Skip to content

Commit 4e462d0

Browse files
committed
[ASTPrinter] Switch to new ParameterTypeFlags
Switch printing off of using Function's ExtInfo for autoclosure and escaping, and onto the ParameterTypeFlags, which let us do precise and accurate context-sensitive printing of these parameter type attributes. This fixes a huge list of issues where we were printing @escaping for things like optional ObjC completion handlers, among many others. We now correctly print @escaping in more places, and don't print it when it's not correct. Also updates the dumper to be consistent and give a good view of the AST as represented in memory. Tests updated, more involved testing coming soon.
1 parent a2ec0f9 commit 4e462d0

File tree

13 files changed

+1857
-1188
lines changed

13 files changed

+1857
-1188
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ struct PrintOptions {
244244
/// protocol requirements.
245245
bool SkipOverrides = false;
246246

247+
/// Whether to skip parameter type attributes
248+
bool SkipParameterTypeAttributes = false;
249+
247250
/// Whether to print a long attribute like '\@available' on a separate line
248251
/// from the declaration or other attributes.
249252
bool PrintLongAttrsOnSeparateLines = false;

lib/AST/ASTDumper.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,15 @@ namespace {
26212621
return OS;
26222622
}
26232623

2624+
void dumpParameterFlags(ParameterTypeFlags paramFlags) {
2625+
if (paramFlags.isVariadic())
2626+
printFlag("vararg");
2627+
if (paramFlags.isAutoClosure())
2628+
printFlag("autoclosure");
2629+
if (paramFlags.isEscaping())
2630+
printFlag("escaping");
2631+
}
2632+
26242633
public:
26252634
PrintType(raw_ostream &os, unsigned indent) : OS(os), Indent(indent) { }
26262635

@@ -2684,6 +2693,7 @@ namespace {
26842693

26852694
void visitParenType(ParenType *T, StringRef label) {
26862695
printCommon(T, label, "paren_type");
2696+
dumpParameterFlags(T->getParameterFlags());
26872697
printRec(T->getUnderlyingType());
26882698
OS << ")";
26892699
}
@@ -2698,9 +2708,7 @@ namespace {
26982708
PrintWithColorRAII(OS, TypeFieldColor) << "tuple_type_elt";
26992709
if (elt.hasName())
27002710
printField("name", elt.getName().str());
2701-
if (elt.isVararg())
2702-
printFlag("vararg");
2703-
2711+
dumpParameterFlags(elt.getParameterFlags());
27042712
printRec(elt.getType());
27052713
OS << ")";
27062714
}
@@ -2911,10 +2919,7 @@ namespace {
29112919
}
29122920

29132921
printFlag(T->isAutoClosure(), "autoclosure");
2914-
2915-
// Dump out either @noescape or @escaping
2916-
printFlag(!T->isNoEscape(), "@escaping");
2917-
2922+
printFlag(!T->isNoEscape(), "escaping");
29182923
printFlag(T->throws(), "throws");
29192924

29202925
printRec("input", T->getInput());

lib/AST/ASTPrinter.cpp

Lines changed: 100 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,20 @@ void StreamPrinter::printText(StringRef Text) {
992992
OS << Text;
993993
}
994994

995+
/// Whether we will be printing a TypeLoc by using the TypeRepr printer
996+
static bool willUseTypeReprPrinting(TypeLoc tyLoc,
997+
const PrintOptions &options) {
998+
// Special case for when transforming archetypes
999+
if (options.TransformContext && tyLoc.getType() &&
1000+
options.TransformContext->transform(tyLoc.getType()))
1001+
return false;
1002+
1003+
// Otherwise, whether we have a type repr and prefer that
1004+
return ((options.PreferTypeRepr && tyLoc.hasLocation()) ||
1005+
tyLoc.getType().isNull()) &&
1006+
tyLoc.getTypeRepr();
1007+
}
1008+
9951009
namespace {
9961010
/// \brief AST pretty-printer.
9971011
class PrintAST : public ASTVisitor<PrintAST> {
@@ -1187,8 +1201,11 @@ class PrintAST : public ASTVisitor<PrintAST> {
11871201
// is null.
11881202
if ((Options.PreferTypeRepr && TL.hasLocation()) ||
11891203
TL.getType().isNull()) {
1190-
if (auto repr = TL.getTypeRepr())
1204+
if (auto repr = TL.getTypeRepr()) {
1205+
llvm::SaveAndRestore<bool> SPTA(Options.SkipParameterTypeAttributes,
1206+
true);
11911207
repr->print(Printer, Options);
1208+
}
11921209
return;
11931210
}
11941211

@@ -1232,10 +1249,10 @@ class PrintAST : public ASTVisitor<PrintAST> {
12321249
/// \returns true if anything was printed.
12331250
bool printASTNodes(const ArrayRef<ASTNode> &Elements, bool NeedIndent = true);
12341251

1235-
void printOneParameter(const ParamDecl *param, bool Curried,
1236-
bool ArgNameIsAPIByDefault);
1252+
void printOneParameter(const ParamDecl *param, ParameterTypeFlags paramFlags,
1253+
bool Curried, bool ArgNameIsAPIByDefault);
12371254

1238-
void printParameterList(ParameterList *PL, bool isCurried,
1255+
void printParameterList(ParameterList *PL, Type paramListTy, bool isCurried,
12391256
std::function<bool()> isAPINameByDefault);
12401257

12411258
/// \brief Print the function parameters in curried or selector style,
@@ -2500,6 +2517,14 @@ static bool isStructOrClassContext(DeclContext *dc) {
25002517
return false;
25012518
}
25022519

2520+
static void printParameterFlags(ASTPrinter &printer, PrintOptions options,
2521+
ParameterTypeFlags flags) {
2522+
if (!options.excludeAttrKind(TAK_autoclosure) && flags.isAutoClosure())
2523+
printer << "@autoclosure ";
2524+
if (!options.excludeAttrKind(TAK_escaping) && flags.isEscaping())
2525+
printer << "@escaping ";
2526+
}
2527+
25032528
void PrintAST::visitVarDecl(VarDecl *decl) {
25042529
printDocumentationComment(decl);
25052530
// Print @sil_stored when the attribute is not already
@@ -2536,7 +2561,8 @@ void PrintAST::visitParamDecl(ParamDecl *decl) {
25362561
visitVarDecl(decl);
25372562
}
25382563

2539-
void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
2564+
void PrintAST::printOneParameter(const ParamDecl *param,
2565+
ParameterTypeFlags paramFlags, bool Curried,
25402566
bool ArgNameIsAPIByDefault) {
25412567
Printer.callPrintStructurePre(PrintStructureKind::FunctionParameter, param);
25422568
SWIFT_DEFER {
@@ -2590,7 +2616,25 @@ void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
25902616
// Set and restore in-parameter-position printing of types
25912617
{
25922618
llvm::SaveAndRestore<bool> savePrintParam(Options.PrintAsInParamType, true);
2619+
// FIXME: don't do if will be using type repr printing
2620+
printParameterFlags(Printer, Options, paramFlags);
2621+
2622+
// Special case, if we're not going to use the type repr printing, peek
2623+
// through the paren types so that we don't print excessive @escapings
2624+
unsigned numParens = 0;
2625+
if (!willUseTypeReprPrinting(TheTypeLoc, Options)) {
2626+
while (auto parenTy =
2627+
dyn_cast<ParenType>(TheTypeLoc.getType().getPointer())) {
2628+
++numParens;
2629+
TheTypeLoc = TypeLoc::withoutLoc(parenTy->getUnderlyingType());
2630+
}
2631+
}
2632+
2633+
for (unsigned i = 0; i < numParens; ++i)
2634+
Printer << "(";
25932635
printTypeLoc(TheTypeLoc);
2636+
for (unsigned i = 0; i < numParens; ++i)
2637+
Printer << ")";
25942638
}
25952639

25962640
if (param->isVariadic())
@@ -2621,28 +2665,68 @@ void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
26212665
}
26222666
}
26232667

2624-
void PrintAST::printParameterList(ParameterList *PL, bool isCurried,
2625-
std::function<bool()> isAPINameByDefault) {
2668+
void PrintAST::printParameterList(ParameterList *PL, Type paramListTy,
2669+
bool isCurried,
2670+
std::function<bool()> isAPINameByDefault) {
2671+
SmallVector<ParameterTypeFlags, 4> paramFlags;
2672+
if (paramListTy) {
2673+
if (auto parenTy = dyn_cast<ParenType>(paramListTy.getPointer())) {
2674+
paramFlags.push_back(parenTy->getParameterFlags());
2675+
} else if (auto tupleTy = paramListTy->getAs<TupleType>()) {
2676+
for (auto elt : tupleTy->getElements())
2677+
paramFlags.push_back(elt.getParameterFlags());
2678+
} else {
2679+
paramFlags.push_back({});
2680+
}
2681+
} else {
2682+
// Malformed AST, just use default flags
2683+
paramFlags.resize(PL->size());
2684+
}
2685+
26262686
Printer << "(";
26272687
for (unsigned i = 0, e = PL->size(); i != e; ++i) {
26282688
if (i > 0)
26292689
Printer << ", ";
26302690

2631-
printOneParameter(PL->get(i), isCurried, isAPINameByDefault());
2691+
printOneParameter(PL->get(i), paramFlags[i], isCurried,
2692+
isAPINameByDefault());
26322693
}
26332694
Printer << ")";
26342695
}
26352696

26362697
void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) {
26372698
auto BodyParams = AFD->getParameterLists();
2699+
auto curTy = AFD->hasType() ? AFD->getType() : nullptr;
26382700

26392701
// Skip over the implicit 'self'.
2640-
if (AFD->getImplicitSelfDecl())
2702+
if (AFD->getImplicitSelfDecl()) {
26412703
BodyParams = BodyParams.slice(1);
2704+
if (curTy)
2705+
if (auto funTy = curTy->getAs<AnyFunctionType>())
2706+
curTy = funTy->getResult();
2707+
}
2708+
2709+
SmallVector<Type, 4> parameterListTypes;
2710+
for (auto i = 0; i < BodyParams.size(); ++i) {
2711+
if (curTy) {
2712+
if (auto funTy = curTy->getAs<AnyFunctionType>()) {
2713+
parameterListTypes.push_back(funTy->getInput());
2714+
if (i < BodyParams.size() - 1)
2715+
curTy = funTy->getResult();
2716+
} else {
2717+
parameterListTypes.push_back(curTy);
2718+
}
2719+
}
2720+
}
26422721

26432722
for (unsigned CurrPattern = 0, NumPatterns = BodyParams.size();
26442723
CurrPattern != NumPatterns; ++CurrPattern) {
2645-
printParameterList(BodyParams[CurrPattern], /*Curried=*/CurrPattern > 0,
2724+
// Be extra careful in the event of printing mal-formed ASTs
2725+
auto paramListType = parameterListTypes.size() > CurrPattern
2726+
? parameterListTypes[CurrPattern]
2727+
: nullptr;
2728+
printParameterList(BodyParams[CurrPattern], paramListType,
2729+
/*Curried=*/CurrPattern > 0,
26462730
[&]()->bool {
26472731
return CurrPattern > 0 || AFD->argumentNameIsAPIByDefault();
26482732
});
@@ -2889,7 +2973,8 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) {
28892973
recordDeclLoc(decl, [&]{
28902974
Printer << "subscript";
28912975
}, [&] { // Parameters
2892-
printParameterList(decl->getIndices(), /*Curried=*/false,
2976+
printParameterList(decl->getIndices(), decl->getIndicesType(),
2977+
/*Curried=*/false,
28932978
/*isAPINameByDefault*/[]()->bool{return false;});
28942979
});
28952980
Printer << " -> ";
@@ -3609,6 +3694,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
36093694

36103695
void visitParenType(ParenType *T) {
36113696
Printer << "(";
3697+
printParameterFlags(Printer, Options, T->getParameterFlags());
36123698
visit(T->getUnderlyingType());
36133699
Printer << ")";
36143700
}
@@ -3638,8 +3724,10 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
36383724
if (TD.isVararg()) {
36393725
visit(TD.getVarargBaseTy());
36403726
Printer << "...";
3641-
} else
3727+
} else {
3728+
printParameterFlags(Printer, Options, TD.getParameterFlags());
36423729
visit(EltType);
3730+
}
36433731
}
36443732
Printer << ")";
36453733
}
@@ -3765,15 +3853,6 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
37653853
if (Options.SkipAttributes)
37663854
return;
37673855

3768-
if (info.isAutoClosure() && !Options.excludeAttrKind(TAK_autoclosure)) {
3769-
Printer.printSimpleAttr("@autoclosure");
3770-
Printer << " ";
3771-
}
3772-
if (inParameterPrinting && !info.isNoEscape() &&
3773-
!Options.excludeAttrKind(TAK_escaping)) {
3774-
Printer.printSimpleAttr("@escaping");
3775-
Printer << " ";
3776-
}
37773856

37783857
if (Options.PrintFunctionRepresentationAttrs &&
37793858
!Options.excludeAttrKind(TAK_convention)) {

lib/AST/TypeRepr.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,11 @@ void AttributedTypeRepr::printAttrs(ASTPrinter &Printer,
283283
return Attrs.has(K);
284284
};
285285

286-
if (hasAttr(TAK_autoclosure)) {
287-
Printer.printSimpleAttr("@autoclosure");
288-
Printer << " ";
289-
}
290-
if (hasAttr(TAK_escaping)) {
291-
Printer.printSimpleAttr("@escaping");
292-
Printer << " ";
286+
if (!Options.SkipParameterTypeAttributes) {
287+
if (hasAttr(TAK_autoclosure))
288+
Printer.printSimpleAttr("@autoclosure") << " ";
289+
if (hasAttr(TAK_escaping))
290+
Printer.printSimpleAttr("@escaping") << " ";
293291
}
294292

295293
if (hasAttr(TAK_thin)) {

test/Constraints/diagnostics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ f1(
6060
)
6161

6262
f3(
63-
f2 // expected-error {{cannot convert value of type '((@escaping (Int) -> Int)) -> Int' to expected argument type '(@escaping (Int) -> Float) -> Int'}}
63+
f2 // expected-error {{cannot convert value of type '(@escaping ((Int) -> Int)) -> Int' to expected argument type '(@escaping (Int) -> Float) -> Int'}}
6464
)
6565

6666
f4(i, d) // expected-error {{extra argument in call}}
@@ -672,7 +672,7 @@ func overloadSetResultType(_ a : Int, b : Int) -> Int {
672672
// https://twitter.com/_jlfischer/status/712337382175952896
673673
// TODO: <rdar://problem/27391581> QoI: Nonsensical "binary operator '&&' cannot be applied to two 'Bool' operands"
674674
return a == b && 1 == 2 // expected-error {{binary operator '&&' cannot be applied to two 'Bool' operands}}
675-
// expected-note @-1 {{expected an argument list of type '(Bool, @autoclosure () throws -> Bool)'}}
675+
// expected-note @-1 {{expected an argument list of type '(Bool, () throws -> Bool)'}}
676676
}
677677

678678
// <rdar://problem/21523291> compiler error message for mutating immutable field is incorrect
@@ -736,7 +736,7 @@ extension Foo23752537 {
736736
// TODO: <rdar://problem/27391581> QoI: Nonsensical "binary operator '&&' cannot be applied to two 'Bool' operands"
737737
// expected-error @+1 {{binary operator '&&' cannot be applied to two 'Bool' operands}}
738738
return (self.title != other.title && self.message != other.message)
739-
// expected-note @-1 {{expected an argument list of type '(Bool, @autoclosure () throws -> Bool)'}}
739+
// expected-note @-1 {{expected an argument list of type '(Bool, () throws -> Bool)'}}
740740
}
741741
}
742742

0 commit comments

Comments
 (0)