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 bad diagnostics for anon params with ref and/or qualified paths #82774

Merged
merged 4 commits into from
Mar 17, 2021

Conversation

JohnTitor
Copy link
Member

@JohnTitor JohnTitor commented Mar 4, 2021

Fixes #82729
It's easier to review with hiding whitespace changes.

@rust-highfive
Copy link
Collaborator

r? @oli-obk

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 4, 2021
format!("{}: &{}TypeName", ident, mutab),
format!("_: &{}{}", mutab, ident),
)
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

@JohnTitor can you also add a test case for a fully qualified path, like in the original report? I get the feeling that the new code will work well only for the case of fn foo(&bar) and not for fn foo(&<Bar as T>::Baz). To handle the later, we might want to add a Parser snapshot here and try to parse a type. If successful, we know we can suggest _: <Ty> and recover the parser state.

Copy link
Member Author

@JohnTitor JohnTitor Mar 5, 2021

Choose a reason for hiding this comment

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

Good point! Yeah, the current parameter_without_type doesn't handle it with/without refs (1082ced). Should we address that case in this PR?

For now, I only added a note about anon params since I'm not sure how we deal with this: To handle the later, we might want to add a Parser snapshot here and try to parse a type. If successful, we know we can suggest _: <Ty> and recover the parser state.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can see an example of what I mean here:

https://github.com/rust-lang/rust/blob/6f43f4c3fbc99c3a6699ed8d44608c8f086b10af/compiler/rustc_parse/src/parser/diagnostics.rs#L749-L761

You have a bounded lookahead to see that you might be in a weird known situation that will for sure emit an error. You clone the parser and try an alternative parse. If it is successful, you emit a targeted error, otherwise you "revert" the parser by overriding the parser state with your snapshot. Doing this you gain a lot of confidence in any suggestions you give because you know that the alternative parse worked.

@oli-obk
Copy link
Contributor

oli-obk commented Mar 5, 2021

r? @estebank

@rust-highfive rust-highfive assigned estebank and unassigned oli-obk Mar 5, 2021
@JohnTitor JohnTitor force-pushed the bad-diag-for-anon-params-with-ref branch from 1082ced to 6f43f4c Compare March 5, 2021 19:48
@JohnTitor JohnTitor changed the title Fix bad diagnostics for anon params with ref Fix bad diagnostics for anon params with ref and/or qualified paths Mar 5, 2021
Comment on lines 1629 to 1661
PatKind::Ref(ref pat, mutab) => {
match pat.clone().into_inner().kind {
PatKind::Ident(_, ident, _) => {
let mutab = mutab.prefix_str();
(
ident,
format!("self: &{}{}", mutab, ident),
format!("{}: &{}TypeName", ident, mutab),
format!("_: &{}{}", mutab, ident),
)
}
PatKind::Path(..) => {
err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
return None;
}
_ => return None,
}
}
// Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to
// `fn foo(HashMap: TypeName<u32>)`.
if self.token != token::Lt {
err.span_suggestion(
pat.span,
"if this is a parameter name, give it a type",
format!("{}: TypeName", ident),
Applicability::HasPlaceholders,
);
// Also catches `fn foo(<Bar as T>::Baz)`
PatKind::Path(..) => {
err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
return None;
}
// Ignore other `PatKind`.
_ => return None,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Using the snapshot strategy this can then be replaced with something like:

                PatKind::Ref(ref pat, mutab) if matches!(pat.clone().into_inner().kind, PatKind::Ident(_, ident, _)) => {
                    match pat.clone().into_inner().kind {
                        PatKind::Ident(_, ident, _) => {
                            let mutab = mutab.prefix_str();
                            (
                                ident,
                                format!("self: &{}{}", mutab, ident),
                                format!("{}: &{}TypeName", ident, mutab),
                                format!("_: &{}{}", mutab, ident),
                            )
                        }
                        _ => unreachable!(),
                    }
                }
                _ => {
                    let snapshot = self.clone();
                    match self.parse_ty_common(
                        AllowPlus::No,
                        AllowCVariadic::No,
                        RecoverQPath::No,
                        RecoverReturnSign::No,
                    ) {
                        Ok(ty) => {
                            err.span_suggestion_verbose(
                                pat.span,
                                "explicitly ignore the parameter name",
                                format!("_: {}", ty),
                                Applicability::MachineApplicable,
                            );
                            err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
                            return None;
                        }
                        Err(mut inner_err) => {
                            inner_err.cancel();
                            *self = snapshot;
                        }
                    }
                    return None,
                }
            };

Copy link
Contributor

Choose a reason for hiding this comment

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

Doing that we can even go further and actually bubble up the ty and continue to the type checking as if the user had written _: , but that is not entirely necessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the pointer! Just copy-pasted your suggestion but the diagnostics don't seem to be changed (a6c75e8). Am I missing something?

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 that parse_ty_common might not be the right thing to call then. Try using parse_ty_for_param (which should be almost the same thing, only Yes passed to all parse_ty_common arguments. Can you change the inner_err.cancel(); to inner_err.emit();? I'm wondering whether it is taking that branch always and why.

Copy link
Member Author

Choose a reason for hiding this comment

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

Suggestions are applied via 01adaef. So looks like the parser looks at ) and cannot find a type.

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've come up with another approach: call to_ty() and emit a suggestion if it successes, implemented via 2d99e68.
@estebank Could you check it?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, that seems to work. Do we have a test for fn foo(<A as B>::X, <C as D>::Y)? I wonder how well this new method works with multiple arguments. Reviewing now, but I think it'll be ready to merge (and you can add a test if you have the time and r=me).

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, added via 55bdf7f. The current rustc emits errors for each arg (https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=1a7575e24dd5fd79ad045613426147c2) and this PR's suggestion is also applied to both.

@JohnTitor JohnTitor force-pushed the bad-diag-for-anon-params-with-ref branch from a6c75e8 to 01adaef Compare March 12, 2021 02:44
@rust-log-analyzer

This comment has been minimized.

@JohnTitor JohnTitor force-pushed the bad-diag-for-anon-params-with-ref branch from 01adaef to 2d99e68 Compare March 17, 2021 00:58
@estebank
Copy link
Contributor

@bors r+

Feel free to update this PR with a multiple arg test if you get to it before bors does its thing.

@bors
Copy link
Contributor

bors commented Mar 17, 2021

📌 Commit 2d99e68 has been approved by estebank

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 17, 2021
@JohnTitor
Copy link
Member Author

@bors r=estebank

@bors
Copy link
Contributor

bors commented Mar 17, 2021

📌 Commit 55bdf7f has been approved by estebank

bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 17, 2021
Rollup of 8 pull requests

Successful merges:

 - rust-lang#82774 (Fix bad diagnostics for anon params with ref and/or qualified paths)
 - rust-lang#82826 ((std::net::parser): Fix capitalization of IP version names)
 - rust-lang#83092 (More precise spans for HIR paths)
 - rust-lang#83124 (Do not insert impl_trait_in_bindings opaque definitions twice.)
 - rust-lang#83202 (Show details in cfg version unstable book)
 - rust-lang#83203 (Don't warn about old rustdoc lint names (temporarily))
 - rust-lang#83206 (Update books)
 - rust-lang#83219 (Update cargo)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit a16db3d into rust-lang:master Mar 17, 2021
@rustbot rustbot added this to the 1.52.0 milestone Mar 17, 2021
@JohnTitor JohnTitor deleted the bad-diag-for-anon-params-with-ref branch March 17, 2021 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Upgrading to 2018 edition with nameless trait arguments gives opaque error message.
7 participants