Skip to content

Commit 1d9cdbb

Browse files
committed
PlaygroundTransform now forwards print() arguments to $builtin_print() exactly.
We put the argument to be printed (so not the stream or the appendNewline:) into a temporary variable to avoid type-checking nastiness. I also made the test case considerably more comprehensive. <rdar://problem/21905513> [Swift submission] playgrounds need to handle print with weird arguments Swift SVN r30457
1 parent d356a2f commit 1d9cdbb

File tree

5 files changed

+222
-117
lines changed

5 files changed

+222
-117
lines changed

lib/Sema/PlaygroundTransform.cpp

+153-78
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ template <class E> class Added {
4545
E Contents;
4646
public:
4747
Added() { }
48-
Added(E &&NewContents) { Contents = NewContents; }
48+
Added(E NewContents) { Contents = NewContents; }
4949
const Added<E> &operator=(const Added<E> &rhs) {
5050
Contents = rhs.Contents;
5151
return *this;
@@ -472,13 +472,17 @@ class Instrumenter {
472472
}
473473
};
474474

475-
bool doTypeCheck(ASTContext &Ctx, DeclContext *DC,
476-
Added<Expr *> &parsedExpr) {
475+
template <class T> bool doTypeCheck(ASTContext &Ctx,
476+
DeclContext *DC,
477+
Added<T*> &parsedExpr) {
477478
DiagnosticEngine diags(Ctx.SourceMgr);
478479
ErrorGatherer errorGatherer(diags);
479480

480481
TypeChecker TC(Ctx, diags);
481-
TC.typeCheckExpression(*parsedExpr, DC);
482+
483+
Expr *E = *parsedExpr;
484+
TC.typeCheckExpression(E, DC);
485+
parsedExpr = Added<T*>(dyn_cast<T>(E));
482486

483487
if (*parsedExpr) {
484488
ErrorFinder errorFinder;
@@ -515,7 +519,7 @@ class Instrumenter {
515519
std::tie(Base_RE, BaseVD) = digForVariable(MRE->getBase());
516520

517521
if (*Base_RE) {
518-
Added <Expr *> Log = logDeclOrMemberRef(Base_RE);
522+
Added<Stmt *> Log = logDeclOrMemberRef(Base_RE);
519523
if (*Log) {
520524
Elements.insert(Elements.begin() + (EI + 1), *Log);
521525
++EI;
@@ -538,7 +542,7 @@ class Instrumenter {
538542
AE->setImplicit(true);
539543
std::string Name = digForName(AE->getDest());
540544

541-
Added<Expr *> Log(buildLoggerCall(
545+
Added<Stmt *> Log(buildLoggerCall(
542546
new (Context) DeclRefExpr(ConcreteDeclRef(PV.second),
543547
SourceLoc(),
544548
true, // implicit
@@ -563,41 +567,19 @@ class Instrumenter {
563567
StringRef FnName = FnD->getNameStr();
564568
if (FnName.equals("print") || FnName.equals("debugPrint")) {
565569
const bool isDebugPrint = FnName.equals("debugPrint");
566-
Expr *object = nullptr;
567-
Expr *appendNewline = nullptr;
568-
if (ParenExpr *PE = dyn_cast<ParenExpr>(AE->getArg())) {
569-
object = PE->getSubExpr();
570-
Added<Expr *> appendNewlineAdded(
571-
new (Context) BooleanLiteralExpr(true, SourceLoc(), true));
572-
doTypeCheck(Context, TypeCheckDC, appendNewlineAdded);
573-
appendNewline = *appendNewlineAdded;
574-
} else if (TupleExpr *TE = dyn_cast<TupleExpr>(AE->getArg())) {
575-
if (TE->getNumElements() == 2) {
576-
object = TE->getElement(0);
577-
appendNewline = TE->getElement(1);
578-
}
579-
}
580-
if (object && !object->getType()->is<InOutType>() &&
581-
appendNewline && !appendNewline->getType()->is<InOutType>()) {
582-
std::pair<PatternBindingDecl *, VarDecl *> objectPV =
583-
buildPatternAndVariable(object);
584-
std::pair<PatternBindingDecl *, VarDecl *> appendNewlinePV =
585-
buildPatternAndVariable(appendNewline);
586-
Added<Expr *> Log = logPrint(isDebugPrint,
587-
objectPV.second,
588-
appendNewlinePV.second,
589-
AE->getSourceRange());
590-
if (*Log) {
591-
Elements[EI] = objectPV.first;
592-
Elements.insert(Elements.begin() + (EI + 1),
593-
objectPV.second);
594-
Elements.insert(Elements.begin() + (EI + 2),
595-
appendNewlinePV.first);
596-
Elements.insert(Elements.begin() + (EI + 3),
597-
appendNewlinePV.second);
598-
Elements.insert(Elements.begin() + (EI + 4),
599-
*Log);
600-
EI += 4;
570+
PatternBindingDecl *ArgPattern = nullptr;
571+
VarDecl *ArgVariable = nullptr;
572+
Added<Stmt *> Log = logPrint(isDebugPrint, AE,
573+
ArgPattern, ArgVariable);
574+
if (*Log) {
575+
if (ArgPattern) {
576+
assert(ArgVariable);
577+
Elements[EI] = ArgPattern;
578+
Elements.insert(Elements.begin() + (EI + 1), ArgVariable);
579+
Elements.insert(Elements.begin() + (EI + 2), *Log);
580+
EI += 2;
581+
} else {
582+
Elements[EI] = *Log;
601583
}
602584
}
603585
Handled = true;
@@ -615,14 +597,14 @@ class Instrumenter {
615597
std::tie(Target_RE, TargetVD) = digForVariable(TargetExpr);
616598

617599
if (TargetVD) {
618-
Added<Expr *> Log = logDeclOrMemberRef(Target_RE);
600+
Added<Stmt *> Log = logDeclOrMemberRef(Target_RE);
619601
if (*Log) {
620602
Elements.insert(Elements.begin() + (EI + 1), *Log);
621603
++EI;
622604
}
623605
}
624606
} else if (DeclRefExpr *DRE = digForInoutDeclRef(AE->getArg())) {
625-
Added<Expr *> Log = logDeclOrMemberRef(DRE);
607+
Added<Stmt *> Log = logDeclOrMemberRef(DRE);
626608
if (*Log) {
627609
Elements.insert(Elements.begin() + (EI + 1), *Log);
628610
++EI;
@@ -634,7 +616,7 @@ class Instrumenter {
634616
// do the same as for all other expressions
635617
std::pair<PatternBindingDecl *, VarDecl *> PV =
636618
buildPatternAndVariable(E);
637-
Added<Expr *> Log = buildLoggerCall(
619+
Added<Stmt *> Log = buildLoggerCall(
638620
new (Context) DeclRefExpr(ConcreteDeclRef(PV.second),
639621
SourceLoc(),
640622
true, // implicit
@@ -654,7 +636,7 @@ class Instrumenter {
654636
Context.TheEmptyTupleType) {
655637
std::pair<PatternBindingDecl *, VarDecl *> PV =
656638
buildPatternAndVariable(E);
657-
Added <Expr *> Log = buildLoggerCall(
639+
Added<Stmt *> Log = buildLoggerCall(
658640
new (Context) DeclRefExpr(ConcreteDeclRef(PV.second),
659641
SourceLoc(),
660642
true, // implicit
@@ -684,7 +666,7 @@ class Instrumenter {
684666
ReturnStmt *NRS = new (Context) ReturnStmt(SourceLoc(),
685667
DRE,
686668
true); // implicit
687-
Added <Expr *> Log = buildLoggerCall(
669+
Added<Stmt *> Log = buildLoggerCall(
688670
new (Context) DeclRefExpr(ConcreteDeclRef(PV.second),
689671
SourceLoc(),
690672
true, // implicit
@@ -717,7 +699,7 @@ class Instrumenter {
717699
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
718700
if (VarDecl *VD = PBD->getSingleVar()) {
719701
if (VD->getParentInitializer()) {
720-
Added<Expr *> Log = logVarDecl(VD);
702+
Added<Stmt *> Log = logVarDecl(VD);
721703
if (*Log) {
722704
Elements.insert(Elements.begin() + (EI + 1), *Log);
723705
++EI;
@@ -753,7 +735,7 @@ class Instrumenter {
753735
// log*() functions return a newly-created log expression to be inserted
754736
// after or instead of the expression they're looking at. Only call this
755737
// if the variable has an initializer.
756-
Added<Expr *> logVarDecl(VarDecl *VD) {
738+
Added<Stmt *> logVarDecl(VarDecl *VD) {
757739
if (isa<ConstructorDecl>(TypeCheckDC) && VD->getNameStr().equals("self")) {
758740
// Don't log "self" in a constructor
759741
return nullptr;
@@ -768,7 +750,7 @@ class Instrumenter {
768750
VD->getSourceRange(), VD->getName().str().str().c_str());
769751
}
770752

771-
Added <Expr *> logDeclOrMemberRef(Added<Expr *> RE) {
753+
Added<Stmt *> logDeclOrMemberRef(Added<Expr *> RE) {
772754
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*RE)) {
773755
VarDecl *VD = cast<VarDecl>(DRE->getDecl());
774756

@@ -807,24 +789,87 @@ class Instrumenter {
807789
}
808790
}
809791

810-
Added<Expr *> logPrint(bool isDebugPrint, VarDecl *object,
811-
VarDecl *appendNewline, SourceRange SR) {
792+
std::pair<PatternBindingDecl*, VarDecl*>
793+
maybeFixupPrintArgument(ApplyExpr *Print) {
794+
Expr *ArgTuple = Print->getArg();
795+
if (ParenExpr *PE = dyn_cast<ParenExpr>(ArgTuple)) {
796+
std::pair<PatternBindingDecl*, VarDecl*> PV =
797+
buildPatternAndVariable(PE->getSubExpr());
798+
PE->setSubExpr(new (Context) DeclRefExpr(ConcreteDeclRef(PV.second),
799+
SourceLoc(),
800+
true, // implicit
801+
AccessSemantics::Ordinary,
802+
PE->getSubExpr()->getType()));
803+
return PV;
804+
} else if (TupleExpr *TE = dyn_cast<TupleExpr>(ArgTuple)) {
805+
if (TE->getNumElements() == 0) {
806+
return std::make_pair(nullptr, nullptr);
807+
} else {
808+
// Are we using print() specialized to handle a single argument,
809+
// or is actually only the first argument of interest and the rest are
810+
// extra information for print()?
811+
bool useJustFirst = false;
812+
if (TE->hasElementNames()) {
813+
useJustFirst = true;
814+
} else {
815+
for (Expr *Arg : TE->getElements()) {
816+
if (Arg->getType()->getAs<InOutType>()) {
817+
useJustFirst = true;
818+
break;
819+
}
820+
}
821+
}
822+
if (useJustFirst) {
823+
std::pair<PatternBindingDecl*, VarDecl*> PV =
824+
buildPatternAndVariable(TE->getElement(0));
825+
TE->setElement(0,
826+
new (Context) DeclRefExpr(
827+
ConcreteDeclRef(PV.second),
828+
SourceLoc(),
829+
true, // implicit
830+
AccessSemantics::Ordinary,
831+
TE->getElement(0)->getType()));
832+
return PV;
833+
} else {
834+
std::pair<PatternBindingDecl*, VarDecl*> PV =
835+
buildPatternAndVariable(TE);
836+
Print->setArg(new (Context) DeclRefExpr(
837+
ConcreteDeclRef(PV.second),
838+
SourceLoc(),
839+
true, // implicit
840+
AccessSemantics::Ordinary,
841+
TE->getType()));
842+
return PV;
843+
}
844+
}
845+
} else {
846+
return std::make_pair(nullptr, nullptr);
847+
}
848+
}
849+
850+
Added<Stmt *> logPrint(bool isDebugPrint, ApplyExpr *AE,
851+
PatternBindingDecl *&ArgPattern,
852+
VarDecl *&ArgVariable) {
812853
const char *LoggerName = isDebugPrint ? "$builtin_debugPrint" :
813854
"$builtin_print";
814-
DeclRefExpr *object_DRE =
815-
new (Context) DeclRefExpr(ConcreteDeclRef(object),
816-
SourceLoc(),
817-
true, // implicit
818-
AccessSemantics::Ordinary,
819-
Type());
820-
DeclRefExpr *appendNewline_DRE =
821-
new (Context) DeclRefExpr(ConcreteDeclRef(appendNewline),
822-
SourceLoc(),
823-
true, // implicit
824-
AccessSemantics::Ordinary,
825-
Type());
826-
Expr *Args[] = { object_DRE, appendNewline_DRE };
827-
return buildLoggerCallWithArgs(LoggerName, Args, SR);
855+
856+
UnresolvedDeclRefExpr *LoggerRef =
857+
new (Context) UnresolvedDeclRefExpr(
858+
Context.getIdentifier(LoggerName),
859+
DeclRefKind::Ordinary,
860+
AE->getSourceRange().End);
861+
862+
std::tie(ArgPattern, ArgVariable) =
863+
maybeFixupPrintArgument(AE);
864+
865+
AE->setFn(LoggerRef);
866+
Added<ApplyExpr*> AddedApply(AE); // safe because we've fixed up the args
867+
868+
if (!doTypeCheck(Context, TypeCheckDC, AddedApply)) {
869+
return nullptr;
870+
}
871+
872+
return buildLoggerCallWithApply(AddedApply, AE->getSourceRange());
828873
}
829874

830875
std::pair<PatternBindingDecl*, VarDecl*>
@@ -863,7 +908,7 @@ class Instrumenter {
863908
return std::make_pair(PBD, VD);
864909
}
865910

866-
Added<Expr *> buildLoggerCall(Added<Expr *> E, SourceRange SR,
911+
Added<Stmt *> buildLoggerCall(Added<Expr *> E, SourceRange SR,
867912
const char *Name) {
868913
assert(Name);
869914
std::string *NameInContext = Context.AllocateObjectCopy(std::string(Name));
@@ -891,15 +936,15 @@ class Instrumenter {
891936
SR);
892937
}
893938

894-
Added <Expr *> buildScopeEntry(SourceRange SR) {
939+
Added<Stmt *> buildScopeEntry(SourceRange SR) {
895940
return buildScopeCall(SR, false);
896941
}
897942

898-
Added <Expr *> buildScopeExit(SourceRange SR) {
943+
Added<Stmt *> buildScopeExit(SourceRange SR) {
899944
return buildScopeCall(SR, true);
900945
}
901946

902-
Added<Expr *> buildScopeCall(SourceRange SR, bool IsExit) {
947+
Added<Stmt *> buildScopeCall(SourceRange SR, bool IsExit) {
903948
const char *LoggerName = IsExit ? "$builtin_log_scope_exit"
904949
: "$builtin_log_scope_entry";
905950

@@ -908,7 +953,7 @@ class Instrumenter {
908953
SR);
909954
}
910955

911-
Added<Expr *> buildLoggerCallWithArgs(const char *LoggerName,
956+
Added<Stmt *> buildLoggerCallWithArgs(const char *LoggerName,
912957
MutableArrayRef<Expr *> Args,
913958
SourceRange SR) {
914959
Expr *LoggerArgs = nullptr;
@@ -930,9 +975,20 @@ class Instrumenter {
930975

931976
LoggerRef->setImplicit(true);
932977

933-
Expr *LoggerCall = new (Context) CallExpr(LoggerRef, LoggerArgs, true,
934-
Type());
978+
ApplyExpr *LoggerCall = new (Context) CallExpr(LoggerRef, LoggerArgs, true,
979+
Type());
980+
Added<ApplyExpr*> AddedLogger(LoggerCall);
981+
982+
if (!doTypeCheck(Context, TypeCheckDC, AddedLogger)) {
983+
return nullptr;
984+
}
985+
986+
return buildLoggerCallWithApply(AddedLogger, SR);
987+
}
935988

989+
// Assumes Apply has already been type-checked.
990+
Added<Stmt *> buildLoggerCallWithApply(Added<ApplyExpr*> Apply,
991+
SourceRange SR) {
936992
std::pair<unsigned, unsigned> StartLC =
937993
Context.SourceMgr.getLineAndColumn(SR.Start);
938994

@@ -961,8 +1017,17 @@ class Instrumenter {
9611017
Expr *EndColumn = new (Context) IntegerLiteralExpr(end_column_buf,
9621018
SR.End, true);
9631019

1020+
std::pair<PatternBindingDecl *, VarDecl *> PV =
1021+
buildPatternAndVariable(*Apply);
1022+
1023+
DeclRefExpr *DRE = new (Context) DeclRefExpr(ConcreteDeclRef(PV.second),
1024+
SourceLoc(),
1025+
true, // implicit
1026+
AccessSemantics::Ordinary,
1027+
Apply->getType());
1028+
9641029
Expr *SendDataArgExprs[] = {
965-
LoggerCall,
1030+
DRE,
9661031
StartLine,
9671032
EndLine,
9681033
StartColumn,
@@ -979,15 +1044,25 @@ class Instrumenter {
9791044

9801045
SendDataRef->setImplicit(true);
9811046

982-
Added<Expr *> SendDataCall = new (Context) CallExpr(SendDataRef,
983-
SendDataArgs, true,
984-
Type());
1047+
Expr * SendDataCall = new (Context) CallExpr(SendDataRef,
1048+
SendDataArgs, true,
1049+
Type());
1050+
Added<Expr *> AddedSendData(SendDataCall);
9851051

986-
if (!doTypeCheck(Context, TypeCheckDC, SendDataCall)) {
1052+
if (!doTypeCheck(Context, TypeCheckDC, AddedSendData)) {
9871053
return nullptr;
9881054
}
9891055

990-
return SendDataCall;
1056+
ASTNode Elements[] = {
1057+
PV.first,
1058+
PV.second,
1059+
SendDataCall
1060+
};
1061+
1062+
BraceStmt *BS = BraceStmt::create(Context, SourceLoc(), Elements,
1063+
SourceLoc(), true);
1064+
1065+
return BS;
9911066
}
9921067
};
9931068

0 commit comments

Comments
 (0)