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

Refactor macro resolution errors + add derive macro suggestions #39752

Merged
merged 1 commit into from
Feb 17, 2017

Conversation

keeperofdakeys
Copy link
Contributor

@keeperofdakeys keeperofdakeys commented Feb 12, 2017

Move legacy macro resolution error reporting to finalize_current_module_macro_resolutions, and provide suggestions for derive macros.

Fixes #39323

cc #30197

r? @jseyfried

@keeperofdakeys
Copy link
Contributor Author

All tests pass expect a few compile-fail tests. For some reason some macro invocations are no longer giving an error, I suspect this is a bug in my code (eg: src/test/compile-fail/macro-error.rs). Also type errors are also occuring in some tests, which leads to interesting bugs with dummy expansions (eg. src/test/compile-fail/macro-expansion-tests.rs).

@@ -260,21 +255,7 @@ impl<'a> base::Resolver for Resolver<'a> {

fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I'd refactor away this function now that it is a one-liner.

find_best_match_for_name(self.macro_names.iter(), name, None),
MacroInvocKind::Attr |
MacroInvocKind::Derive => {
// FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
Copy link
Contributor

Choose a reason for hiding this comment

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

We could probably mem::replace the builtins -- I think the clone on an error path is fine though.

@@ -474,6 +474,35 @@ impl MacResult for DummyResult {
pub type BuiltinDeriveFn =
for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));

/// Represents different kinds of macro invocations that can be resolved.
#[derive(Clone, Copy)]
pub enum MacroInvocKind {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I'd name this MacroKind to be more general -- for example, it also describes macro definitions. Also, the current name is pretty close to expand::InvocationKind.


impl MacroInvocKind {
/// Returns true if the syntax extension is allowed for this macro invocation.
pub fn allow_ext(&self, _ext: &Rc<SyntaxExtension>) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd instead add a method fn kind(&self) -> MacroKind { ... } to SyntaxExtension.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't think that there was a 1-1 mapping, but I can see that there seems to be.

@@ -11,7 +11,7 @@
// ignore-tidy-linelength

#[derive(Eqr)]
//~^ ERROR cannot find derive macro `Eqr` in this scope
//~^ ERROR cannot find macro `Eqr` in this scope
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure that this is an improvement -- I think we should use "derive macro" (status quo) or "custom derive" here.
cc @nrc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I actually agree with this, and I was meaning to change it back. Should attribute macros show something different to "macro"?

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 attribute macros should say "cannot find attribute macro `...` in this scope".

Copy link
Member

Choose a reason for hiding this comment

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

+1

if suggestion != name {
err.help(&format!("did you mean `{}!`?", suggestion));
if let MacroInvocKind::Bang = kind {
err.help(&format!("did you mean `{}!`?", suggestion));
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: indent

@@ -14,14 +14,14 @@
#![feature(asm)]
#![feature(trace_macros, concat_idents)]

#[derive(Zero)] //~ ERROR
#[derive(Zero)]
struct CantDeriveThis;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd remove this -- confusing to have erroneous code that doesn't emit errors since we abort early.

Copy link
Contributor Author

@keeperofdakeys keeperofdakeys Feb 12, 2017

Choose a reason for hiding this comment

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

I was actually a bit confused about why we don't see a resolve error here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe it's because we abort here due to other errors during expansion, so we never get to finalize_current_module_macro_resolutions.

@@ -15,19 +15,24 @@ struct Self;

struct Bar<'Self>;
//~^ ERROR lifetimes cannot use keyword names
//~^^ ERROR parameter `'Self` is never used
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we move the struct Self; in this test into a sub-module to avoid these extra errors?

@jseyfried
Copy link
Contributor

@keeperofdakeys It looks like all test failures are due

  • aborting before we get a chance to emit the unresolved macro errors that the test expects, or
  • not aborting after emitting unresolved macro errors, leading to type errors later on.

I think the best solution would be to make sure we abort before ast->hir lowering if there were unresolved macro errors, at least until we figure out how to suppress the spurious type errors.

@keeperofdakeys
Copy link
Contributor Author

That sounds good, but I don't know what to change to do that. Where is the code that starts the lowering?

@jseyfried
Copy link
Contributor

I would add a pub flag to Resolver that we set if there is an unresolved invocation and we need to abort before type checking. Then, we could check the flag and abort just after name resolution, see here for an example.

Btw, import resolution happens during expansion today, so this comment is outdated.

@keeperofdakeys
Copy link
Contributor Author

Are attribute macros stored in builtin_macros, or somewhere else? The attribute macro suggestions aren't working.

@jseyfried
Copy link
Contributor

jseyfried commented Feb 12, 2017

@keeperofdakeys
Depends on the attribute macro. Attribute macros from #![plugin(..)] are in builtin_macros, use-imported attribute macros are stored in the field resolutions of the containing module's resolver::ModuleData.

Normally, builtin_macros would also have #[macro_use]-imported macros, but this is forbidden for attribute proc macros (we tell people to use use instead).

@jseyfried
Copy link
Contributor

jseyfried commented Feb 12, 2017

Also, we can import proc macro derives today via use (behind #![feature(proc_macro)]), I believe these aren't included in the suggestions.

I think the best path forward here (in this PR or later) is to check resolve::lookup_typo_candidate first when resolver.use_extern_macros is true (includes #![feature(proc_macro)]). You shouldn't have to change the filter function's signature; you can do Def -(retain Def::Macro)-> DefId -> SyntaxExtension -> MacroKind -(retain expected)-> ().

@bors
Copy link
Contributor

bors commented Feb 13, 2017

☔ The latest upstream changes (presumably #39572) made this pull request unmergeable. Please resolve the merge conflicts.

@keeperofdakeys
Copy link
Contributor Author

That sounds like a good idea, however I'm unsure how to go from a DefId -> SyntaxExtension.

@keeperofdakeys
Copy link
Contributor Author

Mmm, for some reason the lookup_typo_candidate call is causing a panic here.

@keeperofdakeys
Copy link
Contributor Author

Oh I see now, lookup_typo_candidate uses self.ribs, which hasn't got MacroNS initialised. Would this be easy to fix? Or would it be easier to leave suggestions for extern macros for another PR?

@jseyfried
Copy link
Contributor

@keeperofdakeys

DefId -> SyntaxExtension

This should do the trick.

lookup_typo_candidate uses self.ribs, which hasn't got MacroNS initialised. Would this be easy to fix? Or would it be easier to leave suggestions for extern macros for another PR?

Right, I don't think this is too hard to fix -- wherever we add ModuleRibKind to value and type ribs today (should always happen in pairs and always in resolve/lib.rs), we'd also want to add to the macro ribs.

This should actually be a simplification, since we could use e.g. self.per_ns(|this, ns| this.ribs[ns].push(...)); instead of duplicating for ValueNS and TypeNS manually.

@keeperofdakeys keeperofdakeys force-pushed the macro-error branch 2 times, most recently from a8f30a6 to 71679b5 Compare February 15, 2017 14:10
@keeperofdakeys
Copy link
Contributor Author

It seems like it will be a bit of work to support use macro suggestions, so I think it's best if that's dealt with in another PR.

@keeperofdakeys keeperofdakeys changed the title [WIP] Refactor macro resolution errors + add suggestions Refactor macro resolution errors + add suggestions Feb 15, 2017
@keeperofdakeys keeperofdakeys changed the title Refactor macro resolution errors + add suggestions Refactor macro resolution errors + add derive macro suggestions Feb 15, 2017
Copy link
Contributor

@jseyfried jseyfried left a comment

Choose a reason for hiding this comment

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

Nice! r=me modulo comments

// Since import resolution will eventually happen in expansion,
// don't perform `after_expand` until after import resolution.
// Since import resolution happs in expansion, don't perform
// `after_expand` until after import resolution.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would just remove this comment -- since expansion and import resolution are interleaved, there's no way to perform after_expand before import resolution, so we don't need to warn people about this.

Also, we can move after_expand(&krate)? outside of time(time_passes, "name resolution", ...) now, I think it would be best to put it just before expansion debugging diagnostics ("Post-expansion node count", etc.).

@@ -474,6 +474,17 @@ impl MacResult for DummyResult {
pub type BuiltinDeriveFn =
for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));

/// Represents different kinds of macro invocations that can be resolved.
#[derive(Clone, Copy, PartialEq)]
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I'd add Eq just to be idiomatic.

@@ -20,14 +20,18 @@ pub fn main() {
match 15 {
ref Self => (),
//~^ ERROR expected identifier, found keyword `Self`
//~^^ ERROR match bindings cannot shadow unit structs
Copy link
Contributor

Choose a reason for hiding this comment

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

(optional) Could we avoid these extra errors by moving `struct (from earlier in the file) into a sub-module?

#[derive(Default)] //~ ERROR
enum OrDeriveThis {}

fn main() {
doesnt_exist!(); //~ ERROR
doesnt_exist!();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd remove this -- it's only not an error here since we abort early.

@jseyfried
Copy link
Contributor

@bors delegate=keeperofdakeys

@bors
Copy link
Contributor

bors commented Feb 16, 2017

✌️ @keeperofdakeys can now approve this pull request

@keeperofdakeys
Copy link
Contributor Author

@bors r+

@bors
Copy link
Contributor

bors commented Feb 16, 2017

📌 Commit 2d91e7a has been approved by keeperofdakeys

@bors
Copy link
Contributor

bors commented Feb 16, 2017

⌛ Testing commit 2d91e7a with merge 82aed0b...

bors added a commit that referenced this pull request Feb 16, 2017
Refactor macro resolution errors + add derive macro suggestions

Move legacy macro resolution error reporting to `finalize_current_module_macro_resolutions`, and provide suggestions for derive macros.

Fixes #39323

cc #30197

r? @jseyfried
@bors
Copy link
Contributor

bors commented Feb 16, 2017

💔 Test failed - status-appveyor

@alexcrichton
Copy link
Member

alexcrichton commented Feb 16, 2017 via email

@bors
Copy link
Contributor

bors commented Feb 17, 2017

⌛ Testing commit 2d91e7a with merge 16c94cd...

bors added a commit that referenced this pull request Feb 17, 2017
Refactor macro resolution errors + add derive macro suggestions

Move legacy macro resolution error reporting to `finalize_current_module_macro_resolutions`, and provide suggestions for derive macros.

Fixes #39323

cc #30197

r? @jseyfried
@bors
Copy link
Contributor

bors commented Feb 17, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: keeperofdakeys
Pushing 16c94cd to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants