Skip to content

Commit c667d2b

Browse files
committed
Use DefaultArgumentExpr for caller-side defaults
This commit changes how we represent caller-side default arguments within the AST. Instead of directly inserting them into the call-site, use a DefaultArgumentExpr to refer to them indirectly. The main goal of this change is to make it such that the expression type-checker no longer cares about the difference between caller-side and callee-side default arguments. In particular, it no longer cares about whether a caller-side default argument is well-formed when type-checking an apply. This is important because any conversions introduced by the default argument shouldn't affect the score of the resulting solution. Instead, caller-side defaults are now lazily type-checked when we want to emit them in SILGen. This is done through introducing a request, and adjusting the logic in SILGen to be more lenient with ErrorExprs. Caller-side defaults in primary files are still also currently checked as a part of the declaration by `checkDefaultArguments`. Resolves SR-11085. Resolves rdar://problem/56144412.
1 parent 4cd873a commit c667d2b

File tree

20 files changed

+310
-111
lines changed

20 files changed

+310
-111
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5263,6 +5263,10 @@ class ParamDecl : public VarDecl {
52635263
/// have a textual representation of their default expression.
52645264
bool hasDefaultExpr() const;
52655265

5266+
/// Whether this parameter has a caller-side default argument expression
5267+
/// such as the magic literal \c #function.
5268+
bool hasCallerSideDefaultExpr() const;
5269+
52665270
/// Retrieve the fully type-checked default argument expression for this
52675271
/// parameter, or \c nullptr if there is no default expression.
52685272
///

include/swift/AST/Expr.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace swift {
4848
class Decl;
4949
class DeclRefExpr;
5050
class OpenedArchetypeType;
51+
class ParamDecl;
5152
class Pattern;
5253
class SubscriptDecl;
5354
class Stmt;
@@ -3864,6 +3865,8 @@ class OpaqueValueExpr : public Expr {
38643865
/// A DefaultArgumentExpr must only appear as a direct child of a
38653866
/// ParenExpr or a TupleExpr that is itself a call argument.
38663867
class DefaultArgumentExpr final : public Expr {
3868+
friend class CallerSideDefaultArgExprRequest;
3869+
38673870
/// The owning declaration.
38683871
ConcreteDeclRef DefaultArgsOwner;
38693872

@@ -3873,11 +3876,17 @@ class DefaultArgumentExpr final : public Expr {
38733876
/// The source location of the argument list.
38743877
SourceLoc Loc;
38753878

3879+
/// Stores either a DeclContext or, upon type-checking, the caller-side
3880+
/// default expression.
3881+
PointerUnion<DeclContext *, Expr *> ContextOrCallerSideExpr;
3882+
38763883
public:
3877-
explicit DefaultArgumentExpr(ConcreteDeclRef defaultArgsOwner, unsigned paramIndex,
3878-
SourceLoc loc, Type Ty)
3884+
explicit DefaultArgumentExpr(ConcreteDeclRef defaultArgsOwner,
3885+
unsigned paramIndex, SourceLoc loc, Type Ty,
3886+
DeclContext *dc)
38793887
: Expr(ExprKind::DefaultArgument, /*Implicit=*/true, Ty),
3880-
DefaultArgsOwner(defaultArgsOwner), ParamIndex(paramIndex), Loc(loc) { }
3888+
DefaultArgsOwner(defaultArgsOwner), ParamIndex(paramIndex), Loc(loc),
3889+
ContextOrCallerSideExpr(dc) { }
38813890

38823891
SourceRange getSourceRange() const {
38833892
return Loc;
@@ -3891,6 +3900,17 @@ class DefaultArgumentExpr final : public Expr {
38913900
return ParamIndex;
38923901
}
38933902

3903+
/// Retrieves the parameter declaration for this default argument.
3904+
const ParamDecl *getParamDecl() const;
3905+
3906+
/// Checks whether this is a caller-side default argument that is emitted
3907+
/// directly at the call site.
3908+
bool isCallerSide() const;
3909+
3910+
/// For a caller-side default argument, retrieves the fully type-checked
3911+
/// expression within the context of the call site.
3912+
Expr *getCallerSideDefaultExpr() const;
3913+
38943914
static bool classof(const Expr *E) {
38953915
return E->getKind() == ExprKind::DefaultArgument;
38963916
}
@@ -5398,6 +5418,9 @@ Expr *packSingleArgument(ASTContext &ctx, SourceLoc lParenLoc,
53985418
});
53995419

54005420
void simple_display(llvm::raw_ostream &out, const ClosureExpr *CE);
5421+
void simple_display(llvm::raw_ostream &out, const DefaultArgumentExpr *expr);
5422+
5423+
SourceLoc extractNearestSourceLoc(const DefaultArgumentExpr *expr);
54015424

54025425
} // end namespace swift
54035426

include/swift/AST/TypeCheckRequests.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace swift {
3333
class AbstractStorageDecl;
3434
class AccessorDecl;
3535
enum class AccessorKind;
36+
class DefaultArgumentExpr;
3637
class GenericParamList;
3738
class PrecedenceGroupDecl;
3839
struct PropertyWrapperBackingPropertyInfo;
@@ -1886,6 +1887,29 @@ class DefaultArgumentExprRequest
18861887
void cacheResult(Expr *expr) const;
18871888
};
18881889

1890+
/// Computes the fully type-checked caller-side default argument within the
1891+
/// context of the call site that it will be inserted into.
1892+
class CallerSideDefaultArgExprRequest
1893+
: public SimpleRequest<CallerSideDefaultArgExprRequest,
1894+
Expr *(DefaultArgumentExpr *),
1895+
CacheKind::SeparatelyCached> {
1896+
public:
1897+
using SimpleRequest::SimpleRequest;
1898+
1899+
private:
1900+
friend SimpleRequest;
1901+
1902+
// Evaluation.
1903+
llvm::Expected<Expr *> evaluate(Evaluator &evaluator,
1904+
DefaultArgumentExpr *defaultExpr) const;
1905+
1906+
public:
1907+
// Separate caching.
1908+
bool isCached() const { return true; }
1909+
Optional<Expr *> getCachedResult() const;
1910+
void cacheResult(Expr *expr) const;
1911+
};
1912+
18891913
// Allow AnyValue to compare two Type values, even though Type doesn't
18901914
// support ==.
18911915
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ SWIFT_REQUEST(TypeChecker, AttachedPropertyWrapperTypeRequest,
2727
SWIFT_REQUEST(TypeChecker, AttachedPropertyWrappersRequest,
2828
llvm::TinyPtrVector<CustomAttr *>(VarDecl *), Cached,
2929
NoLocationInfo)
30+
SWIFT_REQUEST(TypeChecker, CallerSideDefaultArgExprRequest,
31+
Expr *(DefaultArgumentExpr *), SeparatelyCached, NoLocationInfo)
3032
SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest,
3133
AncestryFlags(ClassDecl *), Cached, NoLocationInfo)
3234
SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest,

lib/AST/Decl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6081,6 +6081,25 @@ bool ParamDecl::hasDefaultExpr() const {
60816081
llvm_unreachable("Unhandled case in switch");
60826082
}
60836083

6084+
bool ParamDecl::hasCallerSideDefaultExpr() const {
6085+
switch (getDefaultArgumentKind()) {
6086+
case DefaultArgumentKind::None:
6087+
case DefaultArgumentKind::Inherited:
6088+
case DefaultArgumentKind::StoredProperty:
6089+
case DefaultArgumentKind::Normal:
6090+
return false;
6091+
case DefaultArgumentKind::File:
6092+
case DefaultArgumentKind::Line:
6093+
case DefaultArgumentKind::Column:
6094+
case DefaultArgumentKind::Function:
6095+
case DefaultArgumentKind::DSOHandle:
6096+
case DefaultArgumentKind::NilLiteral:
6097+
case DefaultArgumentKind::EmptyArray:
6098+
case DefaultArgumentKind::EmptyDictionary:
6099+
return true;
6100+
}
6101+
}
6102+
60846103
Expr *ParamDecl::getTypeCheckedDefaultExpr() const {
60856104
// Don't kick off a request if we know there's no default expr. The only
60866105
// exception is for inherited default args which we need to perform a couple

lib/AST/Expr.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/ASTWalker.h"
2626
#include "swift/AST/AvailabilitySpec.h"
2727
#include "swift/AST/PrettyStackTrace.h"
28+
#include "swift/AST/TypeCheckRequests.h"
2829
#include "swift/AST/TypeLoc.h"
2930
#include "llvm/ADT/APFloat.h"
3031
#include "llvm/ADT/PointerUnion.h"
@@ -1382,6 +1383,23 @@ static ValueDecl *getCalledValue(Expr *E) {
13821383
return nullptr;
13831384
}
13841385

1386+
const ParamDecl *DefaultArgumentExpr::getParamDecl() const {
1387+
return getParameterAt(DefaultArgsOwner.getDecl(), ParamIndex);
1388+
}
1389+
1390+
bool DefaultArgumentExpr::isCallerSide() const {
1391+
return getParamDecl()->hasCallerSideDefaultExpr();
1392+
}
1393+
1394+
Expr *DefaultArgumentExpr::getCallerSideDefaultExpr() const {
1395+
assert(isCallerSide());
1396+
auto &ctx = DefaultArgsOwner.getDecl()->getASTContext();
1397+
auto *mutableThis = const_cast<DefaultArgumentExpr *>(this);
1398+
return evaluateOrDefault(ctx.evaluator,
1399+
CallerSideDefaultArgExprRequest{mutableThis},
1400+
new (ctx) ErrorExpr(getSourceRange(), getType()));
1401+
}
1402+
13851403
ValueDecl *ApplyExpr::getCalledValue() const {
13861404
return ::getCalledValue(Fn);
13871405
}
@@ -2209,6 +2227,23 @@ void swift::simple_display(llvm::raw_ostream &out, const ClosureExpr *CE) {
22092227
}
22102228
}
22112229

2230+
void swift::simple_display(llvm::raw_ostream &out,
2231+
const DefaultArgumentExpr *expr) {
2232+
if (!expr) {
2233+
out << "(null)";
2234+
return;
2235+
}
2236+
2237+
out << "default arg for param ";
2238+
out << "#" << expr->getParamIndex() + 1 << " ";
2239+
out << "of ";
2240+
simple_display(out, expr->getDefaultArgsOwner().getDecl());
2241+
}
2242+
2243+
SourceLoc swift::extractNearestSourceLoc(const DefaultArgumentExpr *expr) {
2244+
return expr->getLoc();
2245+
}
2246+
22122247
// See swift/Basic/Statistic.h for declaration: this enables tracing Exprs, is
22132248
// defined here to avoid too much layering violation / circular linkage
22142249
// dependency.

lib/AST/TypeCheckRequests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,3 +1218,23 @@ void DefaultArgumentExprRequest::cacheResult(Expr *expr) const {
12181218
auto *param = std::get<0>(getStorage());
12191219
param->setDefaultExpr(expr, /*isTypeChecked*/ true);
12201220
}
1221+
1222+
//----------------------------------------------------------------------------//
1223+
// CallerSideDefaultArgExprRequest computation.
1224+
//----------------------------------------------------------------------------//
1225+
1226+
Optional<Expr *> CallerSideDefaultArgExprRequest::getCachedResult() const {
1227+
auto *defaultExpr = std::get<0>(getStorage());
1228+
auto storage = defaultExpr->ContextOrCallerSideExpr;
1229+
assert(!storage.isNull());
1230+
1231+
if (auto *expr = storage.dyn_cast<Expr *>())
1232+
return expr;
1233+
1234+
return None;
1235+
}
1236+
1237+
void CallerSideDefaultArgExprRequest::cacheResult(Expr *expr) const {
1238+
auto *defaultExpr = std::get<0>(getStorage());
1239+
defaultExpr->ContextOrCallerSideExpr = expr;
1240+
}

lib/SILGen/ArgumentSource.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,22 @@ class ArgumentSource {
172172
bool isRValue() const & { return StoredKind == Kind::RValue; }
173173
bool isLValue() const & { return StoredKind == Kind::LValue; }
174174

175-
bool isDefaultArg() const {
175+
/// Whether this argument is for a default argument that should be delayed.
176+
/// Note that this will return false for caller-side default arguments which
177+
/// are emitted directly.
178+
bool isDelayedDefaultArg() const {
176179
switch (StoredKind) {
177180
case Kind::Invalid:
178181
llvm_unreachable("argument source is invalid");
179182
case Kind::RValue:
180183
case Kind::LValue:
181184
return false;
182-
case Kind::Expr:
183-
return isa<DefaultArgumentExpr>(asKnownExpr());
185+
case Kind::Expr: {
186+
auto *defaultArg = dyn_cast<DefaultArgumentExpr>(asKnownExpr());
187+
if (!defaultArg)
188+
return false;
189+
return !defaultArg->isCallerSide();
190+
}
184191
}
185192
llvm_unreachable("bad kind");
186193
}

lib/SILGen/SILGenApply.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,9 +2634,9 @@ class ArgEmitter {
26342634

26352635
// origParamType is a parameter type.
26362636
void emitSingleArg(ArgumentSource &&arg, AbstractionPattern origParamType) {
2637-
// If this is default argument, prepare to emit the default argument
2637+
// If this is delayed default argument, prepare to emit the default argument
26382638
// generator later.
2639-
if (arg.isDefaultArg()) {
2639+
if (arg.isDelayedDefaultArg()) {
26402640
auto substParamType = arg.getSubstRValueType();
26412641
auto defArg = std::move(arg).asKnownDefaultArg();
26422642

lib/SILGen/SILGenExpr.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,8 @@ namespace {
499499
RValue visitUnevaluatedInstanceExpr(UnevaluatedInstanceExpr *E,
500500
SGFContext C);
501501
RValue visitTapExpr(TapExpr *E, SGFContext C);
502+
RValue visitDefaultArgumentExpr(DefaultArgumentExpr *E, SGFContext C);
503+
RValue visitErrorExpr(ErrorExpr *E, SGFContext C);
502504
};
503505
} // end anonymous namespace
504506

@@ -5399,6 +5401,25 @@ RValue RValueEmitter::visitTapExpr(TapExpr *E, SGFContext C) {
53995401
return outerScope.popPreservingValue(std::move(result));
54005402
}
54015403

5404+
RValue RValueEmitter::visitDefaultArgumentExpr(DefaultArgumentExpr *E,
5405+
SGFContext C) {
5406+
// We should only be emitting this as an rvalue for caller-side default
5407+
// arguments such as magic literals. Other default arguments get handled
5408+
// specially.
5409+
return SGF.emitRValue(E->getCallerSideDefaultExpr());
5410+
}
5411+
5412+
RValue RValueEmitter::visitErrorExpr(ErrorExpr *E, SGFContext C) {
5413+
// Running into an ErrorExpr here means we've failed to lazily typecheck
5414+
// something. Just emit an undef of the appropriate type and carry on.
5415+
if (SGF.getASTContext().Diags.hadAnyError())
5416+
return SGF.emitUndefRValue(E, E->getType());
5417+
5418+
// Use report_fatal_error to ensure we trap in release builds instead of
5419+
// miscompiling.
5420+
llvm::report_fatal_error("Found an ErrorExpr but didn't emit an error?");
5421+
}
5422+
54025423
RValue SILGenFunction::emitRValue(Expr *E, SGFContext C) {
54035424
assert(!E->getType()->hasLValueType() &&
54045425
"l-values must be emitted with emitLValue");

0 commit comments

Comments
 (0)