Skip to content

Commit 806b5a8

Browse files
committed
[Macros] Diagnose errors where a macro is used without the '#'.
1 parent 4ed393d commit 806b5a8

File tree

11 files changed

+126
-15
lines changed

11 files changed

+126
-15
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6794,6 +6794,8 @@ ERROR(macro_in_nested,none,
67946794
ERROR(macro_without_context,none,
67956795
"macro %0 must declare its applicable contexts (e.g., '@expression')",
67966796
(DeclName))
6797+
ERROR(macro_expansion_missing_pound,none,
6798+
"expansion of macro %0 requires leading '#'", (DeclName))
67976799

67986800
//------------------------------------------------------------------------------
67996801
// MARK: Move Only Errors

include/swift/Sema/CSFix.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ enum class FixKind : uint8_t {
415415
/// For example `.a(let x), .b(let x)` where `x` gets bound to different
416416
/// types.
417417
RenameConflictingPatternVariables,
418+
419+
/// Macro without leading #.
420+
MacroMissingPound,
418421
};
419422

420423
class ConstraintFix {
@@ -3228,6 +3231,32 @@ class RenameConflictingPatternVariables final
32283231
}
32293232
};
32303233

3234+
class MacroMissingPound final : public ConstraintFix {
3235+
MacroDecl *macro;
3236+
3237+
MacroMissingPound(ConstraintSystem &cs, MacroDecl *macro,
3238+
ConstraintLocator *locator)
3239+
: ConstraintFix(cs, FixKind::MacroMissingPound, locator),
3240+
macro(macro) { }
3241+
3242+
public:
3243+
std::string getName() const override { return "macro missing pound"; }
3244+
3245+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3246+
3247+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3248+
return diagnose(*commonFixes.front().first);
3249+
}
3250+
3251+
static MacroMissingPound *
3252+
create(ConstraintSystem &cs, MacroDecl *macro,
3253+
ConstraintLocator *locator);
3254+
3255+
static bool classof(ConstraintFix *fix) {
3256+
return fix->getKind() == FixKind::MacroMissingPound;
3257+
}
3258+
};
3259+
32313260
} // end namespace constraints
32323261
} // end namespace swift
32333262

include/swift/Sema/ConstraintLocator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ class ConstraintLocator : public llvm::FoldingSetNode {
292292
/// Determine whether this locator is for a result builder body result type.
293293
bool isForResultBuilderBodyResult() const;
294294

295+
/// Determine whether this locator is for a macro expansion.
296+
bool isForMacroExpansion() const;
297+
295298
/// Determine whether this locator points directly to a given expression.
296299
template <typename E> bool directlyAt() const {
297300
if (auto *expr = getAnchor().dyn_cast<Expr *>())

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8496,3 +8496,9 @@ bool ConflictingPatternVariables::diagnoseAsError() {
84968496
}
84978497
return true;
84988498
}
8499+
8500+
bool AddMissingMacroPound::diagnoseAsError() {
8501+
emitDiagnostic(diag::macro_expansion_missing_pound, macro->getName())
8502+
.fixItInsert(getLoc(), "#");
8503+
return true;
8504+
}

lib/Sema/CSDiagnostics.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,6 +2854,29 @@ class ConflictingPatternVariables final : public FailureDiagnostic {
28542854
bool diagnoseAsError() override;
28552855
};
28562856

2857+
/// Diagnose situations where we end up type checking a reference to a macro
2858+
/// that was not indicated as a missing # in the source.:
2859+
///
2860+
/// \code
2861+
/// func print(_ value: Any)
2862+
/// @expression macro print<Value...>(_ value: Value...)
2863+
///
2864+
/// func test(e: E) {
2865+
/// print(a, b, c) // missing # to use the macro
2866+
/// }
2867+
/// \endcode
2868+
class AddMissingMacroPound final : public FailureDiagnostic {
2869+
MacroDecl *macro;
2870+
2871+
public:
2872+
AddMissingMacroPound(const Solution &solution, MacroDecl *macro,
2873+
ConstraintLocator *locator)
2874+
: FailureDiagnostic(solution, locator),
2875+
macro(macro) { }
2876+
2877+
bool diagnoseAsError() override;
2878+
};
2879+
28572880
} // end namespace constraints
28582881
} // end namespace swift
28592882

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,3 +2601,15 @@ RenameConflictingPatternVariables::create(ConstraintSystem &cs, Type expectedTy,
26012601
return new (mem)
26022602
RenameConflictingPatternVariables(cs, expectedTy, conflicts, locator);
26032603
}
2604+
2605+
bool MacroMissingPound::diagnose(const Solution &solution,
2606+
bool asNote) const {
2607+
AddMissingMacroPound failure(solution, macro, getLocator());
2608+
return failure.diagnose(asNote);
2609+
}
2610+
2611+
MacroMissingPound *
2612+
MacroMissingPound::create(ConstraintSystem &cs, MacroDecl *macro,
2613+
ConstraintLocator *locator) {
2614+
return new (cs.getAllocator()) MacroMissingPound(cs, macro, locator);
2615+
}

lib/Sema/CSGen.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,22 +1482,41 @@ namespace {
14821482
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
14831483
ArrayRef<ValueDecl*> decls = expr->getDecls();
14841484
SmallVector<OverloadChoice, 4> choices;
1485-
1486-
for (unsigned i = 0, n = decls.size(); i != n; ++i) {
1487-
// If the result is invalid, skip it.
1488-
// FIXME: Note this as invalid, in case we don't find a solution,
1489-
// so we don't let errors cascade further.
1490-
if (decls[i]->isInvalid())
1491-
continue;
1485+
bool anyMacros = false;
1486+
auto addChoices = [&](bool skipMacros) {
1487+
for (unsigned i = 0, n = decls.size(); i != n; ++i) {
1488+
// If the result is invalid, skip it.
1489+
// FIXME: Note this as invalid, in case we don't find a solution,
1490+
// so we don't let errors cascade further.
1491+
if (decls[i]->isInvalid())
1492+
continue;
14921493

1493-
OverloadChoice choice =
1494-
OverloadChoice(Type(), decls[i], expr->getFunctionRefKind());
1495-
choices.push_back(choice);
1496-
}
1494+
// If the result is a macro, skip it if we're supposed to.
1495+
if (skipMacros && isa<MacroDecl>(decls[i])) {
1496+
anyMacros = true;
1497+
continue;
1498+
}
14971499

1498-
// If there are no valid overloads, give up.
1499-
if (choices.empty())
1500-
return nullptr;
1500+
OverloadChoice choice =
1501+
OverloadChoice(Type(), decls[i], expr->getFunctionRefKind());
1502+
choices.push_back(choice);
1503+
}
1504+
};
1505+
1506+
addChoices(/*skipMacros=*/true);
1507+
1508+
if (choices.empty()) {
1509+
// If there are no valid overloads, but we ignored some macros, add
1510+
// the macros. This improves recovery when the user forgot the leading
1511+
// '#'.
1512+
if (anyMacros) {
1513+
addChoices(/*skipMacros=*/false);
1514+
assert(!choices.empty());
1515+
} else {
1516+
// There are no suitable overloads. Just fail.
1517+
return nullptr;
1518+
}
1519+
}
15011520

15021521
// Record this overload set.
15031522
CS.addOverloadSet(tv, choices, CurDC, locator);

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13809,7 +13809,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1380913809
case FixKind::AllowAutoClosurePointerConversion:
1381013810
case FixKind::IgnoreKeyPathContextualMismatch:
1381113811
case FixKind::NotCompileTimeConst:
13812-
case FixKind::RenameConflictingPatternVariables: {
13812+
case FixKind::RenameConflictingPatternVariables:
13813+
case FixKind::MacroMissingPound: {
1381313814
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1381413815
}
1381513816
case FixKind::IgnoreInvalidASTNode: {

lib/Sema/ConstraintLocator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ bool ConstraintLocator::isForResultBuilderBodyResult() const {
597597
return isFirstElement<LocatorPathElt::ResultBuilderBodyResult>();
598598
}
599599

600+
bool ConstraintLocator::isForMacroExpansion() const {
601+
return directlyAt<MacroExpansionExpr>();
602+
}
603+
600604
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
601605
// Check whether we have a path that terminates at a generic parameter.
602606
return isForGenericParameter() ?

lib/Sema/ConstraintSystem.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3568,6 +3568,14 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
35683568
// e.g. `foo.bar()` or `Foo.bar(&foo)()`, and there is nothing to do.
35693569
}
35703570
}
3571+
3572+
// If we have a macro, it can only be used in an expansion.
3573+
if (auto macro = dyn_cast<MacroDecl>(decl)) {
3574+
if (!locator->isForMacroExpansion()) {
3575+
// Record a fix here
3576+
(void)recordFix(MacroMissingPound::create(*this, macro, locator));
3577+
}
3578+
}
35713579
}
35723580

35733581
// Note that we have resolved this overload.

0 commit comments

Comments
 (0)