From b09a22a9a0f2acf59c71189d50f77def2fb5fa3a Mon Sep 17 00:00:00 2001 From: Apollo Zhu Date: Wed, 20 Sep 2023 12:51:09 -0700 Subject: [PATCH] Somewhat working Test shadowed variable of same type Fully type check caller side macro expansion Skip macro default arg caller side expr at decl primary Test macro expand more complex expressions Set synthesized expression as implicit Add test case for with argument, not compiling currently Test with swiftinterface Always use the string representation of the default argument Now works across module boundary Check works for multiple files Make default argument expression work in single file Use expected-error Disallow expression macro as default argument Using as a sub expression in default argument still allowed as expression macros behave the same as built-in magic literals --- include/swift/AST/DefaultArgumentKind.h | 2 + include/swift/AST/Module.h | 1 + include/swift/AST/SourceFile.h | 1 + include/swift/Basic/Features.def | 1 + include/swift/Basic/MacroRoles.def | 3 + include/swift/Basic/SourceManager.h | 3 + include/swift/Sema/ConstraintSystem.h | 4 +- lib/AST/ASTDumper.cpp | 2 + lib/AST/ASTMangler.cpp | 2 + lib/AST/ASTPrinter.cpp | 12 ++ lib/AST/Decl.cpp | 10 +- lib/AST/DiagnosticEngine.cpp | 5 +- lib/AST/Module.cpp | 4 +- lib/Basic/SourceLoc.cpp | 4 +- lib/IDE/CompletionLookup.cpp | 1 + lib/IDE/Utils.cpp | 1 + lib/Parse/ParseDecl.cpp | 2 + lib/Parse/ParseRequests.cpp | 3 +- lib/Parse/Parser.cpp | 1 + lib/Refactoring/Refactoring.cpp | 3 +- lib/SILGen/SILGen.cpp | 1 + lib/SILGen/SILGenFunction.cpp | 1 + lib/Sema/CodeSynthesisDistributedActor.cpp | 1 + lib/Sema/MiscDiagnostics.cpp | 1 + lib/Sema/TypeCheckConcurrency.cpp | 3 + lib/Sema/TypeCheckConstraints.cpp | 11 +- lib/Sema/TypeCheckDeclPrimary.cpp | 17 ++- lib/Sema/TypeCheckEffects.cpp | 12 ++ lib/Sema/TypeCheckExpr.cpp | 84 ++++++++++- lib/Sema/TypeCheckStmt.cpp | 13 +- lib/Sema/TypeChecker.cpp | 2 + lib/Sema/TypeChecker.h | 5 +- lib/Serialization/Deserialization.cpp | 1 + lib/Serialization/ModuleFormat.h | 1 + lib/Serialization/Serialization.cpp | 7 +- .../Inputs/syntax_macro_definitions.swift | 68 +++++++++ .../with_macro_default_arg_interface.swift | 49 +++++++ .../with_macro_default_arg_module.swift | 8 + .../with_macro_default_arg_same_module.swift | 29 ++++ .../macro_default_argument_enabled.swift | 138 ++++++++++++++++++ 40 files changed, 496 insertions(+), 21 deletions(-) create mode 100644 test/Macros/Inputs/with_macro_default_arg_interface.swift create mode 100644 test/Macros/Inputs/with_macro_default_arg_module.swift create mode 100644 test/Macros/Inputs/with_macro_default_arg_same_module.swift create mode 100644 test/Macros/macro_default_argument_enabled.swift diff --git a/include/swift/AST/DefaultArgumentKind.h b/include/swift/AST/DefaultArgumentKind.h index d9b571baf14..ee9781828e9 100644 --- a/include/swift/AST/DefaultArgumentKind.h +++ b/include/swift/AST/DefaultArgumentKind.h @@ -51,6 +51,8 @@ enum class DefaultArgumentKind : uint8_t { // Magic identifier literals expanded at the call site: #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) NAME, #include "swift/AST/MagicIdentifierKinds.def" + /// An expression macro. + ExpressionMacro }; enum { NumDefaultArgumentKindBits = 4 }; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 8b7dccc5807..f5de567aef7 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -106,6 +106,7 @@ enum class SourceFileKind { SIL, ///< Came from a .sil file. Interface, ///< Came from a .swiftinterface file, representing another module. MacroExpansion, ///< Came from a macro expansion. + DefaultArgument, ///< Came from default argument at caller side }; /// Contains information about where a particular path is used in diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index ee4874f5ae5..4d95bf7315f 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -674,6 +674,7 @@ public: case SourceFileKind::Interface: case SourceFileKind::SIL: case SourceFileKind::MacroExpansion: + case SourceFileKind::DefaultArgument: return false; } llvm_unreachable("bad SourceFileKind"); diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index aec28b32d33..ea6ebaac7b5 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -135,6 +135,7 @@ EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false) EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false) EXPERIMENTAL_FEATURE(CodeItemMacros, false) EXPERIMENTAL_FEATURE(BodyMacros, true) +EXPERIMENTAL_FEATURE(ExpressionMacroDefaultArguments, false) EXPERIMENTAL_FEATURE(TupleConformances, false) // Whether to enable @_used and @_section attributes diff --git a/include/swift/Basic/MacroRoles.def b/include/swift/Basic/MacroRoles.def index 372e50f3157..eaee94a6728 100644 --- a/include/swift/Basic/MacroRoles.def +++ b/include/swift/Basic/MacroRoles.def @@ -70,6 +70,9 @@ ATTACHED_MACRO_ROLE(Conformance, "conformance", "c") /// declarations in a code block. EXPERIMENTAL_FREESTANDING_MACRO_ROLE(CodeItem, "codeItem", CodeItemMacros) +/// A freestanding macro that is used as the default argument +EXPERIMENTAL_FREESTANDING_MACRO_ROLE(DefaultArgument, "defaultArgument", ExpressionMacroDefaultArguments) + /// An attached macro that adds extensions to the declaration the /// macro is attached to. ATTACHED_MACRO_ROLE(Extension, "extension", "e") diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index 8b4e7cb7d78..9c906f6cb47 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -43,6 +43,9 @@ public: /// Pretty-printed declarations that have no source location. PrettyPrinted, + + /// The expansion of default argument at caller side + DefaultArgument, } kind; /// The source range in the enclosing buffer where this source was generated. diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 7937a388660..21e1e4b17bf 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -85,7 +85,7 @@ llvm::Optional typeCheckTarget(constraints::SyntacticElementTarget &target, OptionSet options); -Type typeCheckParameterDefault(Expr *&, DeclContext *, Type, bool); +Type typeCheckParameterDefault(Expr *&, DeclContext *, Type, bool, bool); } // end namespace TypeChecker @@ -2970,7 +2970,7 @@ private: friend Type swift::TypeChecker::typeCheckParameterDefault(Expr *&, DeclContext *, Type, - bool); + bool, bool); /// Emit the fixes computed as part of the solution, returning true if we were /// able to emit an error message, or false if none of the fixits worked out. diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 5f235df84c2..262c2da34f1 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -309,6 +309,8 @@ static StringRef getDumpString(DefaultArgumentKind value) { case DefaultArgumentKind::EmptyDictionary: return "[:]"; case DefaultArgumentKind::Normal: return "normal"; case DefaultArgumentKind::StoredProperty: return "stored property"; + case DefaultArgumentKind::ExpressionMacro: + return "expression macro"; } llvm_unreachable("Unhandled DefaultArgumentKind in switch."); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 2983a40a0b2..cc77e924586 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -3877,6 +3877,8 @@ void ASTMangler::appendMacroExpansionContext( case GeneratedSourceInfo::PrettyPrinted: case GeneratedSourceInfo::ReplacedFunctionBody: + // TODO: ApolloZhu check if this correct? + case GeneratedSourceInfo::DefaultArgument: return appendContext(origDC, StringRef()); } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index a9dd76d6363..1995e5bbc9e 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3042,6 +3042,18 @@ static bool usesFeatureFreestandingMacros(Decl *decl) { return macro->getMacroRoles().contains(MacroRole::Declaration); } +static bool usesFeatureExpressionMacroDefaultArguments(Decl *decl) { + if (auto func = dyn_cast(decl)) { + for (auto param : *func->getParameters()) { + if (param->getDefaultArgumentKind() == + DefaultArgumentKind::ExpressionMacro) + return true; + } + } + + return false; +} + static bool usesFeatureCodeItemMacros(Decl *decl) { auto macro = dyn_cast(decl); if (!macro) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2a46e881b5f..d790e494d9a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8290,6 +8290,9 @@ DefaultArgumentKind swift::getDefaultArgKind(Expr *init) { if (isa(init)) return DefaultArgumentKind::NilLiteral; + if (isa(init)) + return DefaultArgumentKind::ExpressionMacro; + auto magic = dyn_cast(init); if (!magic) return DefaultArgumentKind::Normal; @@ -8489,6 +8492,7 @@ bool ParamDecl::hasDefaultExpr() const { #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case DefaultArgumentKind::NAME: #include "swift/AST/MagicIdentifierKinds.def" + case DefaultArgumentKind::ExpressionMacro: case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: @@ -8512,6 +8516,7 @@ bool ParamDecl::hasCallerSideDefaultExpr() const { case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: + case DefaultArgumentKind::ExpressionMacro: return true; } llvm_unreachable("invalid default argument kind"); @@ -8708,6 +8713,7 @@ ParamDecl::getDefaultValueStringRepresentation( switch (getDefaultArgumentKind()) { case DefaultArgumentKind::None: llvm_unreachable("called on a ParamDecl with no default value"); + case DefaultArgumentKind::ExpressionMacro: case DefaultArgumentKind::Normal: { assert(DefaultValueAndFlags.getPointer() && "default value not provided yet"); @@ -8800,7 +8806,8 @@ ParamDecl::getDefaultValueStringRepresentation( void ParamDecl::setDefaultValueStringRepresentation(StringRef stringRepresentation) { assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal || - getDefaultArgumentKind() == DefaultArgumentKind::StoredProperty); + getDefaultArgumentKind() == DefaultArgumentKind::StoredProperty || + getDefaultArgumentKind() == DefaultArgumentKind::ExpressionMacro); assert(!stringRepresentation.empty()); if (!DefaultValueAndFlags.getPointer()) { @@ -12008,6 +12015,7 @@ MacroDiscriminatorContext MacroDiscriminatorContext::getParentOf( #include "swift/Basic/MacroRoles.def" case GeneratedSourceInfo::PrettyPrinted: case GeneratedSourceInfo::ReplacedFunctionBody: + case GeneratedSourceInfo::DefaultArgument: return origDC; } } diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index f48061066e8..d8eab4bce4d 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -1392,6 +1392,7 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) { case GeneratedSourceInfo::Name##MacroExpansion: #include "swift/Basic/MacroRoles.def" case GeneratedSourceInfo::PrettyPrinted: + case GeneratedSourceInfo::DefaultArgument: fixIts = {}; break; case GeneratedSourceInfo::ReplacedFunctionBody: @@ -1465,6 +1466,7 @@ DiagnosticEngine::getGeneratedSourceBufferNotes(SourceLoc loc) { case GeneratedSourceInfo::PrettyPrinted: break; + case GeneratedSourceInfo::DefaultArgument: case GeneratedSourceInfo::ReplacedFunctionBody: return childNotes; } @@ -1648,6 +1650,7 @@ swift::getGeneratedSourceInfoMacroName(const GeneratedSourceInfo &info) { case GeneratedSourceInfo::PrettyPrinted: case GeneratedSourceInfo::ReplacedFunctionBody: - return DeclName(); + case GeneratedSourceInfo::DefaultArgument: + return DeclName(); } } diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index b6db331fedb..bf1b8ae9a18 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -1214,6 +1214,7 @@ llvm::Optional SourceFile::getFulfilledMacroRole() const { case GeneratedSourceInfo::ReplacedFunctionBody: case GeneratedSourceInfo::PrettyPrinted: + case GeneratedSourceInfo::DefaultArgument: return llvm::None; } } @@ -3308,7 +3309,8 @@ SourceFile::SourceFile(ModuleDecl &M, SourceFileKind K, (void)problem; } - if (Kind == SourceFileKind::MacroExpansion) + if (Kind == SourceFileKind::MacroExpansion || + Kind == SourceFileKind::DefaultArgument) M.addAuxiliaryFile(*this); } diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 4cfd9a1f3ac..b89bfbab7fc 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -289,7 +289,8 @@ StringRef SourceManager::getIdentifierForBuffer( if (auto generatedInfo = getGeneratedSourceInfo(bufferID)) { // We only care about macros, so skip everything else. if (generatedInfo->kind == GeneratedSourceInfo::ReplacedFunctionBody || - generatedInfo->kind == GeneratedSourceInfo::PrettyPrinted) + generatedInfo->kind == GeneratedSourceInfo::PrettyPrinted || + generatedInfo->kind == GeneratedSourceInfo::DefaultArgument) return buffer->getBufferIdentifier(); if (generatedInfo->onDiskBufferCopyFileName.empty()) { @@ -382,6 +383,7 @@ void SourceManager::setGeneratedSourceInfo( case GeneratedSourceInfo::Name##MacroExpansion: #include "swift/Basic/MacroRoles.def" case GeneratedSourceInfo::PrettyPrinted: + case GeneratedSourceInfo::DefaultArgument: break; case GeneratedSourceInfo::ReplacedFunctionBody: diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index f3384cb583f..176546a989f 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -1006,6 +1006,7 @@ bool CompletionLookup::hasInterestingDefaultValue(const ParamDecl *param) { #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case DefaultArgumentKind::NAME: #include "swift/AST/MagicIdentifierKinds.def" + case DefaultArgumentKind::ExpressionMacro: return false; } } diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 96bd1489462..e2900c8d7ac 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -658,6 +658,7 @@ adjustMacroExpansionWhitespace(GeneratedSourceInfo::Kind kind, case GeneratedSourceInfo::BodyMacroExpansion: case GeneratedSourceInfo::ReplacedFunctionBody: case GeneratedSourceInfo::PrettyPrinted: + case GeneratedSourceInfo::DefaultArgument: return expandedCode; } } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c3a73000bbc..e564cbf6d94 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -218,6 +218,7 @@ void Parser::parseTopLevelItems(SmallVectorImpl &items) { break; case SourceFileKind::MacroExpansion: + case SourceFileKind::DefaultArgument: braceItemListKind = BraceItemListKind::MacroExpansion; break; } @@ -9932,6 +9933,7 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) { case SourceFileKind::Library: case SourceFileKind::Main: case SourceFileKind::MacroExpansion: + case SourceFileKind::DefaultArgument: if (Tok.is(tok::identifier)) { diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc()); consumeToken(); diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index 00cd09d0c6a..1f6d1cc1d53 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -183,7 +183,8 @@ SourceFileParsingResult ParseSourceFileRequest::evaluate(Evaluator &evaluator, case GeneratedSourceInfo::ExpressionMacroExpansion: case GeneratedSourceInfo::PreambleMacroExpansion: case GeneratedSourceInfo::ReplacedFunctionBody: - case GeneratedSourceInfo::PrettyPrinted: { + case GeneratedSourceInfo::PrettyPrinted: + case GeneratedSourceInfo::DefaultArgument: { parser.parseTopLevelItems(items); break; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 52288e0ea3f..7ff3e23e2c1 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -325,6 +325,7 @@ static LexerMode sourceFileKindToLexerMode(SourceFileKind kind) { case swift::SourceFileKind::Library: case swift::SourceFileKind::Main: case swift::SourceFileKind::MacroExpansion: + case swift::SourceFileKind::DefaultArgument: return LexerMode::Swift; } llvm_unreachable("covered switch"); diff --git a/lib/Refactoring/Refactoring.cpp b/lib/Refactoring/Refactoring.cpp index 58c4650ebfa..afd26e5b797 100644 --- a/lib/Refactoring/Refactoring.cpp +++ b/lib/Refactoring/Refactoring.cpp @@ -155,7 +155,8 @@ swift::ide::collectRefactorings(SourceFile *SF, RangeConfig Range, DiagConsumers); // No refactorings are available within generated buffers - if (SF->Kind == SourceFileKind::MacroExpansion) + if (SF->Kind == SourceFileKind::MacroExpansion || + SF->Kind == SourceFileKind::DefaultArgument) return {}; // Prepare the tool box. diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 5626288ac40..bd80097948e 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1617,6 +1617,7 @@ void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: + case DefaultArgumentKind::ExpressionMacro: break; } } diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 20cda981a86..8efa59d1ba0 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -344,6 +344,7 @@ static MacroInfo getMacroInfo(GeneratedSourceInfo &Info, } case GeneratedSourceInfo::PrettyPrinted: case GeneratedSourceInfo::ReplacedFunctionBody: + case GeneratedSourceInfo::DefaultArgument: break; } return Result; diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index 2fb59c472fd..fa9fe468e37 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -785,6 +785,7 @@ addDistributedActorCodableConformance( case SourceFileKind::Main: case SourceFileKind::MacroExpansion: case SourceFileKind::SIL: + case SourceFileKind::DefaultArgument: break; } } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index bfc5202bbae..8bacaa91c47 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -615,6 +615,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: case DefaultArgumentKind::StoredProperty: + case DefaultArgumentKind::ExpressionMacro: return llvm::None; } diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index d37cd02baa4..c4b82315a6e 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -45,6 +45,7 @@ static bool shouldInferAttributeInContext(const DeclContext *dc) { // Interfaces have explicitly called-out Sendable conformances. return false; + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::MacroExpansion: case SourceFileKind::Main: @@ -868,6 +869,7 @@ static bool shouldDiagnosePreconcurrencyImports(SourceFile &sf) { case SourceFileKind::SIL: return false; + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::Main: case SourceFileKind::MacroExpansion: @@ -5615,6 +5617,7 @@ ProtocolConformance *swift::deriveImplicitSendableConformance( // Interfaces have explicitly called-out Sendable conformances. return nullptr; + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::MacroExpansion: case SourceFileKind::Main: diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index d0b83e14e7e..8a4a22e924e 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -545,7 +545,8 @@ TypeChecker::typeCheckTarget(SyntacticElementTarget &target, Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue, DeclContext *DC, Type paramType, - bool isAutoClosure) { + bool isAutoClosure, + bool atCallerSide) { // During normal type checking we don't type check the parameter default if // the param has an error type. For code completion, we also type check the // parameter default because it might contain the code completion token. @@ -569,10 +570,16 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue, // different contextual type, see below. DiagnosticTransaction diagnostics(ctx.Diags); + TypeCheckExprOptions options; + // Expand macro expansion expression at caller side only + if (!atCallerSide && isa(defaultValue)) { + options |= TypeCheckExprFlags::DisableMacroExpansions; + } + // First, let's try to type-check default expression using // archetypes, which guarantees that it would work for any // substitution of the generic parameter (if they are involved). - if (auto result = typeCheckExpression(defaultExprTarget)) { + if (auto result = typeCheckExpression(defaultExprTarget, options)) { defaultValue = result->getAsExpr(); return defaultValue->getType(); } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 80208bd112e..b4031ab6165 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1132,8 +1132,11 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, auto *initExpr = param->getStructuralDefaultExpr(); assert(initExpr); - // Prohibit default argument that is a non-built-in macro to avoid confusion. - if (isa(initExpr)) { + // Prohibit default argument that is a non-built-in macro to avoid confusion, + // unless the experimental feature flag is set. + auto isMacroExpansionExpr = isa(initExpr); + if (isMacroExpansionExpr && + !ctx.LangOpts.hasFeature(Feature::ExpressionMacroDefaultArguments)) { ctx.Diags.diagnose(initExpr->getLoc(), diag::macro_as_default_argument); return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); } @@ -1148,10 +1151,15 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, assert(dc); if (!TypeChecker::typeCheckParameterDefault(initExpr, dc, paramTy, - param->isAutoClosure())) { + param->isAutoClosure(), + /*atCallerSide=*/false)) { return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); } + // Expression macro default arguments are checked at caller side + if (isMacroExpansionExpr) + return initExpr; + // Walk the checked initializer and contextualize any closures // we saw there. TypeChecker::contextualizeInitializer(dc, initExpr); @@ -1545,6 +1553,7 @@ static void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) { case SourceFileKind::SIL: case SourceFileKind::Interface: return; + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::Main: case SourceFileKind::MacroExpansion: @@ -2608,6 +2617,7 @@ public: case SourceFileKind::Interface: case SourceFileKind::SIL: return; + case SourceFileKind::DefaultArgument: case SourceFileKind::Main: case SourceFileKind::Library: case SourceFileKind::MacroExpansion: @@ -2630,6 +2640,7 @@ public: case SourceFileKind::Interface: case SourceFileKind::SIL: return; + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::MacroExpansion: break; diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 8c3af3bba56..6316acdfc85 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -2196,6 +2196,10 @@ public: return getContextForPatternBinding(binding); } + static Context forDefaultArgument(DeclContext *dc) { + return Context(Kind::DefaultArgument, dc); + } + static Context forEnumElementInitializer(EnumElementDecl *elt) { return Context(Kind::EnumElementInitializer, elt); } @@ -3697,6 +3701,14 @@ void TypeChecker::checkInitializerEffects(Initializer *initCtx, init->walk(LocalFunctionEffectsChecker()); } +void TypeChecker::checkCallerSideDefaultArgumentEffects(DeclContext *initCtx, + Expr *init) { + auto &ctx = initCtx->getASTContext(); + CheckEffectsCoverage checker(ctx, Context::forDefaultArgument(initCtx)); + init->walk(checker); + init->walk(LocalFunctionEffectsChecker()); +} + /// Check the correctness of effects within the given enum /// element's raw value expression. /// diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 64c042f926b..b7faf280126 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -710,8 +710,60 @@ Expr *TypeChecker::foldSequence(SequenceExpr *expr, DeclContext *dc) { return Result; } +static SourceFile *createDefaultArgumentSourceFile(StringRef macroExpression, + SourceLoc insertionPoint, + ASTNode target, + DeclContext *dc) { + ASTContext &ctx = dc->getASTContext(); + SourceManager &sourceMgr = ctx.SourceMgr; + + llvm::SmallString<256> builder; + unsigned line, column; + std::tie(line, column) = + sourceMgr.getPresumedLineAndColumnForLoc(insertionPoint); + auto file = dc->getOutermostParentSourceFile()->getFilename(); + + // find a way to pass the file:line:column to macro expansion + // so that we can share same buffer for the same default argument + builder.append(line - 1, '\n'); + builder.append(column - 1, ' '); + builder.append(macroExpression); + + std::unique_ptr buffer; + buffer = llvm::MemoryBuffer::getMemBufferCopy(builder.str(), file); + + // Dump default argument to standard output, if requested. + if (ctx.LangOpts.DumpMacroExpansions) { + llvm::errs() << buffer->getBufferIdentifier() + << "\n------------------------------\n" + << buffer->getBuffer() + << "\n------------------------------\n"; + } + + // Create a new source buffer with the contents of the default argument + unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(buffer)); + auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID); + GeneratedSourceInfo sourceInfo{GeneratedSourceInfo::DefaultArgument, + {insertionPoint, 0}, + macroBufferRange, + target.getOpaqueValue(), + dc, + nullptr}; + sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo); + + // Create a source file to hold the macro buffer. This is automatically + // registered with the enclosing module. + auto sourceFile = new (ctx) SourceFile( + *dc->getParentModule(), SourceFileKind::DefaultArgument, macroBufferID, + /*parsingOpts=*/{}, /*isPrimary=*/false); + sourceFile->setImports(dc->getParentSourceFile()->getImports()); + return sourceFile; +} + static Expr *synthesizeCallerSideDefault(const ParamDecl *param, - SourceLoc loc) { + DefaultArgumentExpr *defaultExpr, + DeclContext *dc) { + SourceLoc loc = defaultExpr->getLoc(); auto &ctx = param->getASTContext(); switch (param->getDefaultArgumentKind()) { #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ @@ -721,6 +773,26 @@ static Expr *synthesizeCallerSideDefault(const ParamDecl *param, /*implicit=*/true); #include "swift/AST/MagicIdentifierKinds.def" + case DefaultArgumentKind::ExpressionMacro: { + // FIXME: ApolloZhu what is macro has parameters that references + // other things in decl context? + SmallString<128> scratch; + const StringRef text = param->getDefaultValueStringRepresentation(scratch); + SourceFile *defaultArgSourceFile = + createDefaultArgumentSourceFile(text, loc, defaultExpr, dc); + auto topLevelItems = defaultArgSourceFile->getTopLevelItems(); + for (auto item : topLevelItems) { + if (auto *expr = item.dyn_cast()) + if (auto *callerSideMacroExpansionExpr = + dyn_cast(expr)) { + callerSideMacroExpansionExpr->setImplicit(); + return callerSideMacroExpansionExpr; + } + } + llvm_unreachable("default argument source file missing caller side macro " + "expansion expression"); + } + case DefaultArgumentKind::NilLiteral: return new (ctx) NilLiteralExpr(loc, /*Implicit=*/true); break; @@ -750,15 +822,15 @@ Expr *CallerSideDefaultArgExprRequest::evaluate( auto paramTy = defaultExpr->getType(); // Re-create the default argument using the location info of the call site. - auto *initExpr = - synthesizeCallerSideDefault(param, defaultExpr->getLoc()); auto *dc = defaultExpr->ContextOrCallerSideExpr.get(); + auto *initExpr = synthesizeCallerSideDefault(param, defaultExpr, dc); assert(dc && "Expected a DeclContext before type-checking caller-side arg"); auto &ctx = param->getASTContext(); DiagnosticTransaction transaction(ctx.Diags); if (!TypeChecker::typeCheckParameterDefault(initExpr, dc, paramTy, - param->isAutoClosure())) { + param->isAutoClosure(), + /*atCallerSide=*/true)) { if (param->hasDefaultExpr()) { // HACK: If we were unable to type-check the default argument in context, // then retry by type-checking it within the parameter decl, which should @@ -770,6 +842,10 @@ Expr *CallerSideDefaultArgExprRequest::evaluate( } return new (ctx) ErrorExpr(initExpr->getSourceRange(), paramTy); } + if (param->getDefaultArgumentKind() == DefaultArgumentKind::ExpressionMacro) { + TypeChecker::contextualizeCallSideDefaultArgument(dc, initExpr); + TypeChecker::checkCallerSideDefaultArgumentEffects(dc, initExpr); + } return initExpr; } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 96ec5852760..4e8abdebbdf 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -119,7 +119,12 @@ namespace { // Caller-side default arguments need their @autoclosures checked. if (auto *DAE = dyn_cast(E)) - if (DAE->isCallerSide() && DAE->getParamDecl()->isAutoClosure()) + if (DAE->isCallerSide() && + (DAE->getParamDecl()->isAutoClosure() || + (DAE->getParamDecl()->getDefaultArgumentKind() == + DefaultArgumentKind::ExpressionMacro && + ParentDC->getASTContext().LangOpts.hasFeature( + Feature::ExpressionMacroDefaultArguments)))) DAE->getCallerSideDefaultExpr()->walk(*this); // Macro expansion expressions require a DeclContext as well. @@ -206,6 +211,12 @@ void TypeChecker::contextualizeInitializer(Initializer *DC, Expr *E) { E->walk(CC); } +void TypeChecker::contextualizeCallSideDefaultArgument(DeclContext *DC, + Expr *E) { + ContextualizeClosuresAndMacros CC(DC); + E->walk(CC); +} + void TypeChecker::contextualizeTopLevelCode(TopLevelCodeDecl *TLCD) { ContextualizeClosuresAndMacros CC(TLCD); if (auto *body = TLCD->getBody()) diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index b692576b832..7c26d04c6dc 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -372,6 +372,7 @@ void swift::performWholeModuleTypeChecking(SourceFile &SF) { FrontendStatsTracer tracer(Ctx.Stats, "perform-whole-module-type-checking"); switch (SF.Kind) { + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::Main: case SourceFileKind::MacroExpansion: @@ -418,6 +419,7 @@ void swift::loadDerivativeConfigurations(SourceFile &SF) { }; switch (SF.Kind) { + case SourceFileKind::DefaultArgument: case SourceFileKind::Library: case SourceFileKind::MacroExpansion: case SourceFileKind::Main: { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index bd510097241..09534115456 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -467,7 +467,8 @@ bool typeCheckClosureBody(ClosureExpr *closure); bool typeCheckTapBody(TapExpr *expr, DeclContext *DC); Type typeCheckParameterDefault(Expr *&defaultValue, DeclContext *DC, - Type paramType, bool isAutoClosure); + Type paramType, bool isAutoClosure, + bool atCallerSide); void typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD); @@ -760,6 +761,7 @@ void checkPatternBindingCaptures(IterableDeclContext *DC); /// Change the context of closures in the given initializer /// expression to the given context. void contextualizeInitializer(Initializer *DC, Expr *init); +void contextualizeCallSideDefaultArgument(DeclContext *DC, Expr *init); void contextualizeTopLevelCode(TopLevelCodeDecl *TLCD); /// Retrieve the default type for the given protocol. @@ -1135,6 +1137,7 @@ void checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name); void checkTopLevelEffects(TopLevelCodeDecl *D); void checkFunctionEffects(AbstractFunctionDecl *D); void checkInitializerEffects(Initializer *I, Expr *E); +void checkCallerSideDefaultArgumentEffects(DeclContext *I, Expr *E); void checkEnumElementEffects(EnumElementDecl *D, Expr *expr); void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index d1e6dddd058..ef805489871 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -452,6 +452,7 @@ getActualDefaultArgKind(uint8_t raw) { CASE(EmptyArray) CASE(EmptyDictionary) CASE(StoredProperty) + CASE(ExpressionMacro) #undef CASE } return llvm::None; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 4c3a78f91fc..825bda6e2d3 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -537,6 +537,7 @@ enum class DefaultArgumentKind : uint8_t { EmptyArray, EmptyDictionary, StoredProperty, + ExpressionMacro, }; using DefaultArgumentField = BCFixed<4>; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index fe29cfefb8b..25c46f16acc 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1415,6 +1415,7 @@ static uint8_t getRawStableDefaultArgumentKind(swift::DefaultArgumentKind kind) CASE(EmptyArray) CASE(EmptyDictionary) CASE(StoredProperty) + CASE(ExpressionMacro) #undef CASE } @@ -4402,12 +4403,14 @@ public: swift::DefaultArgumentKind argKind = param->getDefaultArgumentKind(); if (argKind == swift::DefaultArgumentKind::Normal || - argKind == swift::DefaultArgumentKind::StoredProperty) { + argKind == swift::DefaultArgumentKind::StoredProperty || + argKind == swift::DefaultArgumentKind::ExpressionMacro) { defaultArgumentText = param->getDefaultValueStringRepresentation(scratch); // Serialize the type of the default expression (if any). - defaultExprType = param->getTypeOfDefaultExpr(); + if (!param->hasCallerSideDefaultExpr()) + defaultExprType = param->getTypeOfDefaultExpr(); } auto isolation = param->getInitializerIsolation(); diff --git a/test/Macros/Inputs/syntax_macro_definitions.swift b/test/Macros/Inputs/syntax_macro_definitions.swift index 8287a943252..f216661ce70 100644 --- a/test/Macros/Inputs/syntax_macro_definitions.swift +++ b/test/Macros/Inputs/syntax_macro_definitions.swift @@ -1986,6 +1986,74 @@ public struct NestedMagicLiteralMacro: ExpressionMacro { } } +public struct NativeFileIDMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + return context.location( + of: node, at: .afterLeadingTrivia, filePathMode: .fileID + )!.file + } +} + +public struct NativeFilePathMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + return context.location( + of: node, at: .afterLeadingTrivia, filePathMode: .filePath + )!.file + } +} + +public struct NativeLineMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + return context.location(of: node)!.line + } +} + +public struct NativeColumnMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + return context.location(of: node)!.column + } +} + +public struct ClosureCallerMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + let location = context.location(of: node)! + return #""" + ClosureCaller({ (value, then) in + #sourceLocation(file: \#(location.file), line: \#(location.line)) + print("\(value)@\(\#(location.file))#\(\#(location.line))") + then() + #sourceLocation() + }) + """# + } +} + +public struct FirstArgumentConcatStringMacro: ExpressionMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + """ + \(node.arguments.first!.expression) + " world" + """ + } +} + public struct InvalidIfExprMacro: MemberMacro { public static func expansion( of node: AttributeSyntax, diff --git a/test/Macros/Inputs/with_macro_default_arg_interface.swift b/test/Macros/Inputs/with_macro_default_arg_interface.swift new file mode 100644 index 00000000000..0997efcb02a --- /dev/null +++ b/test/Macros/Inputs/with_macro_default_arg_interface.swift @@ -0,0 +1,49 @@ +@freestanding(expression) +public macro FileID() -> T = #externalMacro( + module: "MacroDefinition", type: "NativeFileIDMacro" +) + +@freestanding(expression) +public macro HasParam(_ param: String) -> String = #externalMacro( + module: "MacroDefinition", type: "FirstArgumentConcatStringMacro" +) + +@freestanding(expression) +public macro MakeClosureCaller() -> ClosureCaller = #externalMacro( + module: "MacroDefinition", type: "ClosureCallerMacro" +) + +public func printCurrentFileDefinedInAnotherModuleInterface( + file: String = #FileID +) { + print(file) +} + +public struct ClosureCaller { + private let callback: @convention(thin) (Any, () -> Void) -> Void + + public init(_ callback: @convention(thin) (Any, () -> Void) -> Void) { + self.callback = callback + } + + public func callAsFunction(context: Any, then: () -> Void = {}) { + callback(context, then) + } +} + +public let shadowed = "hello" + +public func testParameterUseVariableFromOriginalDeclContext( + param: String = #HasParam(shadowed) +) { + print(param) +} + +@resultBuilder +public enum ClosureCallerBuilder { + public static func buildBlock( + closureCaller: ClosureCaller = #MakeClosureCaller + ) -> ClosureCaller { + closureCaller + } +} diff --git a/test/Macros/Inputs/with_macro_default_arg_module.swift b/test/Macros/Inputs/with_macro_default_arg_module.swift new file mode 100644 index 00000000000..fe2f5cba5c4 --- /dev/null +++ b/test/Macros/Inputs/with_macro_default_arg_module.swift @@ -0,0 +1,8 @@ +@freestanding(expression) +public macro Line() -> T = #externalMacro( + module: "MacroDefinition", type: "NativeLineMacro" +) + +public func printCurrentLineDefinedAtAnotherModule(line: Int = #Line) { + print(line) +} diff --git a/test/Macros/Inputs/with_macro_default_arg_same_module.swift b/test/Macros/Inputs/with_macro_default_arg_same_module.swift new file mode 100644 index 00000000000..4d236f366c6 --- /dev/null +++ b/test/Macros/Inputs/with_macro_default_arg_same_module.swift @@ -0,0 +1,29 @@ +import WithMacroDefaultArg +import WithMacroDefaultArgInterface + +@freestanding(expression) +macro MagicLine() -> Int = #externalMacro( + module: "MacroDefinition", type: "MagicLineMacro" +) + +@freestanding(expression) +macro Column() -> T = #externalMacro( + module: "MacroDefinition", type: "NativeColumnMacro" +) + +@freestanding(expression) +macro FilePath() -> T = #externalMacro( + module: "MacroDefinition", type: "NativeFilePathMacro" +) + +func printAnotherFileName(file: String = (#FileID)) { + print(file) +} + +func printCurrentFileDefinedAtAnotherFile(file: String = #FileID) { + print(file) +} + +func printCurrentLineDefinedAtAnotherFile(line: Int = #Line) { + print(line) +} diff --git a/test/Macros/macro_default_argument_enabled.swift b/test/Macros/macro_default_argument_enabled.swift new file mode 100644 index 00000000000..f2af11af13b --- /dev/null +++ b/test/Macros/macro_default_argument_enabled.swift @@ -0,0 +1,138 @@ +// REQUIRES: swift_swift_parser + +// RUN: %empty-directory(%t) + +// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath + +// RUN: %target-build-swift-dylib(%t/%target-library-name(WithMacroDefaultArg)) %S/Inputs/with_macro_default_arg_module.swift -module-name WithMacroDefaultArg -emit-module -emit-module-path %t/WithMacroDefaultArg.swiftmodule -load-plugin-library %t/%target-library-name(MacroDefinition) -enable-experimental-feature ExpressionMacroDefaultArguments -I %t -swift-version 5 +// RUN: %target-codesign %t/%target-library-name(WithMacroDefaultArg) + +// RUN: %target-build-swift-dylib(%t/%target-library-name(WithMacroDefaultArgInterface)) %S/Inputs/with_macro_default_arg_interface.swift -module-name WithMacroDefaultArgInterface -enable-library-evolution -emit-module-interface-path %t/WithMacroDefaultArgInterface.swiftinterface -load-plugin-library %t/%target-library-name(MacroDefinition) -enable-experimental-feature ExpressionMacroDefaultArguments -I %t -swift-version 5 +// RUN: %target-codesign %t/%target-library-name(WithMacroDefaultArgInterface) + +// RUN: %target-build-swift -enable-experimental-feature ExpressionMacroDefaultArguments -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %S/Inputs/with_macro_default_arg_same_module.swift %s -o %t/main -module-name MacroUser -emit-tbd -emit-tbd-path %t/MacroUser.tbd -I %t -L %t -lWithMacroDefaultArg -lWithMacroDefaultArgInterface +// RUN: %target-codesign %t/main +// RUN: %target-run %t/main | %FileCheck %s + +import WithMacroDefaultArg +import WithMacroDefaultArgInterface + +struct SourceLocation: CustomStringConvertible { + let line: Int + let column: Int + + var description: String { + "\(line):\(column)" + } +} + +func partOfDefaultArgumentOkay( + // CHECK: [[# @LINE + 1]]:59 + location: SourceLocation = .init(line: #Line, column: #Column) +) { + print(location) +} + +// CHECK: [[# @LINE + 1]] +func parenthesizedExpansionAtDeclOkay(line: Int = (#Line)) { + print(line) +} + +func asDefaultArgument(line: Int = #Line) { + print(line) +} + +func asDefaultArgumentExpandingToBuiltInLine(line: Int = #MagicLine) { + print(line) +} + +@resultBuilder +enum SourceLocationBuilder { + static func buildExpression( + _ expression: T, line: Int = #Line, column: Int = #Column + ) -> SourceLocation { + SourceLocation(line: line, column: column) + } + + static func buildBlock(_ location: SourceLocation) -> SourceLocation { + location + } +} + +func build(@SourceLocationBuilder body: () -> SourceLocation) -> SourceLocation { + body() +} + +let result = build { + // CHECK: [[# @LINE + 1]]:5 + 0 +} + +func sameFileID(builtIn: String = #fileID, expressionMacro: String = #FileID) { + print(builtIn == expressionMacro) +} + +func sameFilePath(builtIn: String = #filePath, expressionMacro: String = #FilePath) { + print(builtIn == expressionMacro) +} + +func sameLine(builtIn: Int = #line, expressionMacro: Int = #Line) { + print(builtIn == expressionMacro) +} + +func sameColumn(builtIn: Int = #column, expressionMacro: Int = #Column) { + print(builtIn == expressionMacro) +} + +func buildPrinter( + @ClosureCallerBuilder makeCaller: () -> ClosureCaller +) -> ClosureCaller { + makeCaller() +} + +// CHECK: macro@MacroUser/macro_default_argument_enabled.swift#[[# @LINE + 1]] +let printWithFileLine = buildPrinter { } + +@main struct Main { + static func main() { + partOfDefaultArgumentOkay() + parenthesizedExpansionAtDeclOkay() + print(result) + printWithFileLine(context: "macro") + + do { + let shadowed: Int = 1 + // CHECK: hello world + testParameterUseVariableFromOriginalDeclContext() + } + + do { + let shadowed: String = "not this" + // CHECK: hello world + testParameterUseVariableFromOriginalDeclContext() + } + + // CHECK: [[# @LINE + 1]] + asDefaultArgument() + // CHECK: [[# @LINE + 1]] + asDefaultArgumentExpandingToBuiltInLine() + // CHECK: [[# @LINE + 1]] + printCurrentLineDefinedAtAnotherFile() + // CHECK: [[# @LINE + 1]] + printCurrentLineDefinedAtAnotherModule() + // CHECK: MacroUser/with_macro_default_arg_same_module.swift + printAnotherFileName() + // CHECK: MacroUser/macro_default_argument_enabled.swift + printCurrentFileDefinedAtAnotherFile() + // CHECK: MacroUser/macro_default_argument_enabled.swift + printCurrentFileDefinedInAnotherModuleInterface() + // CHECK: true + sameFileID() + // CHECK: true + sameFilePath() + // CHECK: true + sameLine() + // CHECK: true + sameColumn() + } +}