Skip to content

Improve divergence checking for loops #51053

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

Closed
wants to merge 1 commit into from

Conversation

varkor
Copy link
Member

@varkor varkor commented May 25, 2018

This change permits breaks to be considered diverging (i.e. having type !) in diverging blocks, which allows constructions like:

let _: ! = { loop { return; break } }

thus relaxing the overly-restrictive divergence rules.

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 25, 2018
@rust-highfive

This comment has been minimized.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

The code looks good as is, but I am worried it's trying to extend the divergence mechanism beyond its design. Might be still worth fixing, not sure. Kind of a matter of "predictability" I guess — thoughts @rust-lang/lang (and specifically @eddyb and maybe @arielb1)?

(Also, @varkor, please verify my test case — though if that one is wrong, I'm sure there is a similar one that is right.)

// the function is already diverging. In this case, we
// don't need to supply any value (in which case, the
// value will be considered to have type `!`).
if !prev_diverges.always() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I think if we are going to "do this", we might want to consider "doing it right". In particular, the value of the diverges flag on entry to an expression does not indicate if "all prior points in the CFG diverged" but rather if some preceding subexpression within the parent diverged.

This means that while this test works now:

    if false {
        let _: ! = {
            loop { return; break } // ok
        };
}

I expect that this one will fail, right?

    if false {
        let _: ! = {
            loop { 
                return; 
                { break; } // now the break is part of a sub-block...
            }
        };
}

Put another way, I am wary of adding rules that try to use the existing divergence mechanism to figure out if prior code had diverged.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that's correct.

@nikomatsakis
Copy link
Contributor

I know in the past @arielb1 and I had talked about adding a separate divergence mechanism to track whether "prior code has diverged" basically...

This change permits `break`s to be considered diverging (i.e. having type `!`) in diverging blocks, which allows constructions like `let _: ! = { loop { return; break } }`, relaxing the overly-restrictive divergence rules.
@varkor
Copy link
Member Author

varkor commented Jun 2, 2018

Perhaps that would be worthing thinking about in a little more detail, yes.

@varkor varkor force-pushed the better-loop-divergence branch from a4eaa41 to 2039a9b Compare June 2, 2018 00:05
@nikomatsakis
Copy link
Contributor

I don't see a lot of comments either way yet =)

@TimNN TimNN added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 5, 2018
@varkor
Copy link
Member Author

varkor commented Jun 5, 2018

I'll try taking a look at more sophisticated divergence checking soon.

@nikomatsakis
Copy link
Contributor

I think the deeper question is if we want the compiler to be that smart.

@nikomatsakis
Copy link
Contributor

Let me just spell out my concerns:

I know we could implement this, but it means making the type checker that much more clever. The existing check and its implications are pretty subtle! Now we would have to be threading two notions of divergence through typeck, with lots of opportunity to make a small mistake. The result of making a mistake like that would be bugs that may wind up in code that lives in crates.io. Or even if there are no bugs, it's just complexity that we have to support forever.

The counter-argument, I guess, is that we already do some amount of dead-code reasoning, and it's kind of surprising that things like return; break; are dumb. And that's true. On the other hand, we've been around and around on just how much to type-check dead code, and I feel like we've reached a "pretty ok" point right now, so I'm somewhat reluctant to disturb it until the type-checker overall is clearer and nicer.

So I guess I remain sort of vaguely biased against making this work at this time. I'd feel better if the type-checker were refactored into something clean where we could easily specify this extra analysis, versus being the current setup where we'd really have to thread it around by hand.

@varkor
Copy link
Member Author

varkor commented Jun 6, 2018

Okay, I'm happy to close this for now and we can potentially take another look at some later point. It's an edge case anyway.

@varkor varkor closed this Jun 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants