Skip to content

Conversation

@WalterBright
Copy link
Member

I.e. when two or more parameters are mutually dependent on each other for scope inference, this detects more cases.

@dlang-bot
Copy link
Contributor

dlang-bot commented Jun 27, 2018

Thanks for your pull request, @WalterBright!

Bugzilla references

Auto-close Bugzilla Severity Description
19035 normal Escape in scope inference, improve scope inference

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#8408"

@WalterBright WalterBright force-pushed the maybescope branch 3 times, most recently from 8472010 to a8d9fec Compare June 27, 2018 01:39
@WalterBright
Copy link
Member Author

don't pull needs work

@jacob-carlborg
Copy link
Contributor

don't pull needs work

Give us a ping when it's ready for review.

@WalterBright
Copy link
Member Author

I'm surprised this slipped through all the tests! I guess it is good to go. Ping @jacob-carlborg

fail_compilation/retscope6.d(7035): Error: reference to local variable `i` assigned to non-scope parameter `_param_0` calling retscope6.S.emplace2!(int*).emplace2
fail_compilation/retscope6.d(7024): Error: scope variable `_param_2` assigned to `s` with longer lifetime
fail_compilation/retscope6.d(7025): Error: scope variable `_param_2` assigned to `t` with longer lifetime
fail_compilation/retscope6.d(7037): Error: template instance `retscope6.S.emplace4!(int*)` error instantiating
Copy link
Contributor

Choose a reason for hiding this comment

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

I recommend a single section of test output, it will be much easier if the error messages need to be updated. It caused me quite some pain in another PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

I do multiple blocks with a #line precisely because they are easier to update. Adding a line doesn't require updating every message line.

Copy link
Contributor

Choose a reason for hiding this comment

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

./run.d fail_compilation AUTO_UPDATE=1 for the win...

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this only works with a single output section.

Expression edtor; // if !=null, does the destruction of the variable
IntRange* range; // if !=null, the variable is known to be within the range

VarDeclarations* maybes; // STC.maybescope variables that are assigned to this STC.maybescope variable
Copy link
Contributor

Choose a reason for hiding this comment

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

  • Can this be a D array?
  • The comment should be a Ddoc comment
  • Can we call this maybeScopes, possibleScopeVariables or some variations of those?

Copy link
Member Author

Choose a reason for hiding this comment

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

  1. No, as it's variable sized, and we generally avoid D arrays in the front end for that reason.
  2. As the rest or not, such a change should await that
  3. I'm not a big fan of long names

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a big fan of long names

I'm not a fan of names that are not understandable. maybes, "maybe" what?

Copy link
Contributor

@jacob-carlborg jacob-carlborg Jun 28, 2018

Choose a reason for hiding this comment

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

No, as it's variable sized, and we generally avoid D arrays in the front end for that reason.

There are several cases where D arrays are used [1] [2] and you're usually arguing for D string instead of C strings, which are D arrays. Also, using a D array would make addMaybe not necessary because D arrays don't need to be newed.

[1] https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d#L56
[2] https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d#L189

src/dmd/escape.d Outdated
* complete, we can finalize this by turning off
* maybescope for array elements that cannot be scope.
*
* va v => va v
Copy link
Contributor

Choose a reason for hiding this comment

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

Are va and v referring to the foreach variables in the source below? If that’s the case please quote them with backticks to make that more clear.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok

src/dmd/escape.d Outdated
//printf("inferScope = %d, %d\n", inferScope, (va.storage_class & STCmaybescope) != 0);

// Determine if va is a parameter that is an indirect reference
bool vaIsRef = va && va.storage_class & STC.parameter &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Can be made const.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok

@WalterBright WalterBright added the Review:Vision Vision Plan https://wiki.dlang.org/Vision/2018H1 label Jun 27, 2018
@WalterBright WalterBright dismissed jacob-carlborg’s stale review June 27, 2018 23:58

Addressed all points

@JinShil
Copy link
Contributor

JinShil commented Jun 28, 2018

Am I the only one drowning in DIP1000 sea? Can we please document all of this first, and then move to implementation? Or at the very least, provide some formal documentation with these PRs?

This PR could also use an elaborate problem statement. There's no bugzilla issue, so I don't understand what the problem is that this solves. How are we supposed to be able to predict the behavior of the compiler with all this inference magic? We'll be debugging our understanding of the language before we ever get to debugging our code. (cue Scott Meyers "The last thing D needs")

@WalterBright
Copy link
Member Author

I thought the test case was pretty clear. Errors that are spurious, and errors that should be diagnosed.

@JinShil
Copy link
Contributor

JinShil commented Jun 28, 2018

I thought the test case was pretty clear.

Sorry, but it's not for me. Perhaps you could augment it with some helpful comments.

static void emplace4(Args...)(scope ref S s, scope out S t, scope Args args) @safe
{
s.payload = args[0];
t.payload = args[0];
Copy link
Contributor

@JinShil JinShil Jun 28, 2018

Choose a reason for hiding this comment

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

Due to the lack of documentation surrounding the semantics of scope I'm assuming that in this context, scope means that args[0]'s lifetime must not exceed the lifetime of this emplace4's scope. However, since we are assigning to a ref and out we are escaping out of emplace4's scope. Is this correct?

When I analyze the implementation of foo, however, there's no escape because everything is local to foo. Perhaps this could use a more compelling test that would actually result in a leak or memory corruption without this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll add some more documentation.

Copy link
Contributor

@JinShil JinShil Jun 28, 2018

Choose a reason for hiding this comment

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

@WalterBright Is it really too much to ask to have you open a dlang.org PR to document the semantics of scope and return function parameters with illustrative examples so we can refer to it when we review these PRs? Or are you still trying to figure all this out, and this is your way of working through it?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's documented in DIP25 and DIP1000. I'd start with a gentler introduction, http://dconf.org/2017/talks/bright.html

@WalterBright WalterBright changed the title improve inference of 'scope' parameters fix Issue 19035 - Escape in scope inference, improve scope inference Jun 28, 2018

/**********************/

void betty()(int* p, int* q)
Copy link
Contributor

Choose a reason for hiding this comment

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

It's interesting that you chose to use a template here? Why is that? Is it to ensure the body of the function is needed in order to do the inference. For example, I noticed that Example 1 does not compile, but Example 2 does.

Example 1

@safe:
void betty(int* p, int* q)  // Notice this is not a template
{
     p = q;
}

void testbetty()
{
    int i;
    int j;
    betty(&i, &j); // Error: reference to local variable i assigned to non-scope parameter p calling betty
                   // Error: reference to local variable j assigned to non-scope parameter q calling betty
}

Example 2

@safe:
void betty()(int* p, int* q)  // Notice this is a template
{
     p = q;
}

void testbetty()
{
    int i;
    int j;
    betty(&i, &j);
}

There's a lot you're not saying here, and I think you're taking a lot for granted expecting us to review the semantics of this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Templates have the scope-ness of their parameters (and other attributes) inferred. Regular functions do not. Yes, I did take such knowledge for granted. Now you know!

s.payload = args[0];
}

static void emplace4(Args...)(scope ref S s, scope out S t, scope Args args) @safe
Copy link
Contributor

Choose a reason for hiding this comment

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

https://dlang.org/spec/attribute.html#scope

scope cannot be applied to globals, statics, data members, ref or out parameters.

This is violating the spec. The spec needs an update.

Copy link
Contributor

Choose a reason for hiding this comment

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

https://dlang.org/spec/attribute.html#scope

Assignment to a scope, other than initialization, is not allowed.

Also not accurate.

Copy link
Member Author

Choose a reason for hiding this comment

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

As I've mentioned before, dip1000 has not been folded into the spec.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, and that's part of the problem. Why hasn't it been done? And shouldn't it be done either prior to PRs like this or together with PRs like this?

Copy link
Member Author

@WalterBright WalterBright Jun 29, 2018

Choose a reason for hiding this comment

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

Why hasn't it been done?

One large reason is because I can't get my spec fixes pulled.

Aside from that, DIP1000 despite being years old has little use, so I don't know how well it works. I can't get people to use DIP1000 features because phobos doesn't compile with dip1000. So I try to get phobos to compile with dip1000. I run into problems. I make corrections (like this PR). And I get blocked.

End result, no progress anywhere.

There is another issue. I used to work at Boeing in design. The designs ended up as drawings, using pen and ink on special plastic paper. Unsurprisingly, revising these drawings (including redrawing them) is quite expensive. But the designs changed constantly (bug fixes, improvements, changing requirements, the same issues that affect software). What was done was issuing DCN (Drawing Change Notices), which contained the fixes to the drawing. The official "drawing" was the original drawing plus a stack of DCNs, applied in chronological order (much like git, git is hardly a new concept). Eventually, the drawing may get redone with all the DCNs folded in.

The analogy for us is the spec, plus approved DIPs, plus Bugzilla Enhancement Requests and bug fixes. It's not ideal, but it's pragmatic. Halting all progress because it all hasn't been folded into the spec yet is not pragmatic, especially when my PRs to update the spec just sit there.

Copy link
Contributor

Choose a reason for hiding this comment

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

One large reason is because I can't get my spec fixes pulled.

I suggest putting a time limit on those PRs that haven't received feedback. We already have a `72h no objection -> merge" label in the DMD repository, and I don't see why that can't be applied to your dlang.org PRs. Noone has a right to complain if they chose not to participate.

There is another issue. I used to work at Boeing in design...

I understand that, but I'm not going to be your rubber stamp. I need to understand what these PRs are doing and why.

Others on this team are well within their charter to move this PR forward if they understand it and have confidence in the direction you're heading, but I'm not on board yet and have concerns. I've already sent you an e-mail or two about the way scope is being inferred, and I don't like what I'm seeing in the implementation so far. I think we need a way to set storage classes meta-programmatically, rather than reaching for inference.

@WalterBright
Copy link
Member Author

I need to understand what these PRs are doing and why.

I won't argue that it is simple. But what do you suggest we do with a 2 person rule when nobody else understands the compiler?

@jacob-carlborg
Copy link
Contributor

I won't argue that it is simple. But what do you suggest we do with a 2 person rule when nobody else understands the compiler?

We need to incrementally try to get more people to understand the compiler.

@JinShil
Copy link
Contributor

JinShil commented Jun 29, 2018

But what do you suggest we do with a 2 person rule when nobody else understands the compiler?

IMO, if you are determined, highly confident in your solution, and you don't receive any feedback or don't receive feedback that you consider significant to change your position, then after a reasonable amount of time, you're in a unique position to just merge away.

But, I'd prefer that you did more to bring others along with you. With the lack of documentation about these inference rules (formal or informal) I don't think you're doing enough to justify this PR to the team. Though it could just be me.

This is an important feature, and I don't recommend anyone hold up this PR based on my objections alone. I won't protest if my objections are overruled, and may even merge this myself if I can be convinced that it's the right solution.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

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

I'm going to merge this now on the understanding that DIP1000 is still under work/ in flux and it needs to move forward (and this is indeed a nice improvement).
However, I agree with @JinShil that if we want -dip1000 to be a success there needs to be a better plan and roadmap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review:Vision Vision Plan https://wiki.dlang.org/Vision/2018H1 Severity:Bug Fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants