Skip to content

[Macros/Parse] Attributes on MacroExpansionDecl #65815

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

Merged
merged 1 commit into from
May 15, 2023

Conversation

rintaro
Copy link
Member

@rintaro rintaro commented May 10, 2023

  • Parse #<identifier> after an attribute list as a MacroExpansionDecl regardless of the position
  • Diagnose whitespaces between # and the macro name
  • Correctly attach attributes to MacroExpansionDecl
  • Fix OrigDeclAttributes to handle modifiers (use getLocation() instead of AtLoc.)

Type checking and macro expansion are TODO

rdar://107386648

@rintaro
Copy link
Member Author

rintaro commented May 10, 2023

swiftlang/swift-syntax#1650
@swift-ci Please smoke test

@rintaro
Copy link
Member Author

rintaro commented May 10, 2023

swiftlang/swift-syntax#1650
@swift-ci Please Test Source Compatibility

// expected-error@+2 2 {{consecutive declarations on a line must be separated by ';}}
// expected-error@+1 2 {{expected a macro identifier}}
// expected-error@+2 {{consecutive declarations on a line must be separated by ';}}
// expected-error@+1 {{expected a macro identifier}}
/ ###line 25 "line-directive.swift"
Copy link
Member Author

Choose a reason for hiding this comment

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

This is improved because previously # not followed by an identifier was true for isStartOfSwiftDecl(). Now it's false so the expression parsing recovery skips the second #.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense, thank you!

@rintaro rintaro force-pushed the macros-attributes-rdar107386648 branch from 9b92a14 to 9017dea Compare May 10, 2023 04:39
@rintaro
Copy link
Member Author

rintaro commented May 10, 2023

swiftlang/swift-syntax#1650
@swift-ci Please smoke test

@@ -1049,8 +1049,10 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) {

auto topLevelItems = macroSourceFile->getTopLevelItems();
for (auto item : topLevelItems) {
if (auto *decl = item.dyn_cast<Decl *>())
if (auto *decl = item.dyn_cast<Decl *>()) {
decl->getAttrs().add(med->getAttrs());
decl->setDeclContext(dc);
Copy link
Member

Choose a reason for hiding this comment

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

This will cause problems when the same attribute is added to multiple places. Per our offline discussion, I think it's best for us to syntactically add the attributes (e.g., by splicing them into the DeclSyntax nodes we get back from the macro) rather than do it semantically. That way, we'll see the attributes in the expansion.

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 scoped down this PR to Parse support only. Removed this bit.

@@ -1549,6 +1551,9 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator,
macroRef.getArgs(), roles);
}

// FIXME: Type checking should reflect the attributes on the expansion.
// e.g. '@available(macOS 999) #Future { newAPIFrom999() }'.
Copy link
Member

Choose a reason for hiding this comment

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

The actual fix for this will be in TypeRefinementContextBuilder.

// expected-error@+2 2 {{consecutive declarations on a line must be separated by ';}}
// expected-error@+1 2 {{expected a macro identifier}}
// expected-error@+2 {{consecutive declarations on a line must be separated by ';}}
// expected-error@+1 {{expected a macro identifier}}
/ ###line 25 "line-directive.swift"
Copy link
Member

Choose a reason for hiding this comment

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

Makes sense, thank you!

@rintaro rintaro force-pushed the macros-attributes-rdar107386648 branch from 9017dea to 74ddec5 Compare May 11, 2023 18:59
* Parse `#<identifier>` attribute list as a `MacroExpansionDecl`
  regardless of the position
* Diagnose whitespaces between `#` and the macro name.
* Correctly attach attributes to `MacroExpansionDecl`
* Fix `OrigDeclAttributes` to handle modifiers (use `getLocation()`
  instead of `AtLoc`.)

Type checking is a TODO

rdar://107386648
@rintaro rintaro force-pushed the macros-attributes-rdar107386648 branch from 74ddec5 to 9fc1521 Compare May 11, 2023 19:04
@rintaro rintaro changed the title [Macros] Attributes on MacroExpansionDecl [Macros/Parse] Attributes on MacroExpansionDecl May 11, 2023
@rintaro
Copy link
Member Author

rintaro commented May 11, 2023

swiftlang/swift-syntax#1650
@swift-ci Please smoke test

@rintaro rintaro marked this pull request as ready for review May 11, 2023 19:08
@rintaro
Copy link
Member Author

rintaro commented May 12, 2023

swiftlang/swift-syntax#1650
@swift-ci Please smoke test

1 similar comment
@rintaro
Copy link
Member Author

rintaro commented May 12, 2023

swiftlang/swift-syntax#1650
@swift-ci Please smoke test

@xedin xedin removed their request for review May 12, 2023 16:23
@@ -4917,7 +4939,8 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) {
// it's an actor declaration, otherwise, it isn't.
do {
consumeToken();
} while (isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false));
} while (isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
/*hadAttrsOrModifiers=*/true));
Copy link
Member

Choose a reason for hiding this comment

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

Can actor be a modifier here?

Copy link
Member Author

Choose a reason for hiding this comment

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

actor is still declared as a (deprecated) modifier, and it's diagnosed as a error in parseDeclModifierList(). The diagnostic message is not great, though.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, OK. Makes sense then. Just wanted to double-check

@@ -4976,7 +5001,8 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) {
// Otherwise, do a recursive parse.
Parser::BacktrackingScope Backtrack(*this);
consumeToken(tok::identifier);
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false);
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
/*hadAttrsOrModifiers=*/true);
Copy link
Member

Choose a reason for hiding this comment

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

What’s the attribute or modifier that has been consumed here?

Copy link
Member Author

Choose a reason for hiding this comment

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

At this point Tok is a contextual keyword, and all decl introducers with contextual keyword (e.g. macro) are handled above. The all remaining cases are simple decl modifiers.

Copy link
Member

Choose a reason for hiding this comment

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

At this point Tok is a contextual keyword

We don’t know that it’s a contextual keyword, right? We just continue pretending that it might be, but really, it could be any identifier, right? Or am I missing something?

Copy link
Member Author

Choose a reason for hiding this comment

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

There's

  // If this can't possibly be a contextual keyword, then this identifier is
  // not interesting.  Bail out.
  if (!Tok.isContextualDeclKeyword())
    return false;

above.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, OK. I just didn’t read far enough back. It’s what you get from large functions that implicitly retain state from other early exits…

Thanks for the explanation. Good with me 👍🏽

Comment on lines +1844 to +1849
if (!isStartOfFreestandingMacroExpansion()) {
consumeToken(tok::pound);
diagnose(Tok.getLoc(),
diag::macro_expansion_expr_expected_macro_identifier);
return makeParserError();
}
Copy link
Member

Choose a reason for hiding this comment

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

Weren’t we diagnosing this before? Out of curiosity: Is there a test case that triggers this?

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.

3 participants