Skip to content

Commit 1bbaaed

Browse files
committed
Merge pull request #2942 from jckarter/optional-codegen-improvements
Optional codegen improvements
2 parents 41177fa + c9ba2bf commit 1bbaaed

27 files changed

+189
-314
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -454,15 +454,6 @@ class ASTContext {
454454
FuncDecl *get##Name(LazyResolver *resolver) const;
455455
#include "swift/AST/KnownDecls.def"
456456

457-
/// Swift._stdlib_{,ImplicitlyUnwrapped}Optional_isSome.
458-
FuncDecl *getOptionalIsSomeDecl(LazyResolver *resolver,
459-
OptionalTypeKind kind) const;
460-
461-
/// Retrieve the declaration of
462-
/// Swift._stdlib_{,ImplicitlyUnwrapped}Optional_unwrapped.
463-
FuncDecl *getOptionalUnwrappedDecl(LazyResolver *resolver,
464-
OptionalTypeKind kind) const;
465-
466457
/// Check whether the standard library provides all the correct
467458
/// intrinsic support for Optional<T>.
468459
///

include/swift/AST/Expr.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ namespace swift {
5151
class TypeDecl;
5252
class PatternBindingDecl;
5353
class ParameterList;
54+
class EnumElementDecl;
5455

5556
enum class ExprKind : uint8_t {
5657
#define EXPR(Id, Parent) Id,
@@ -3655,6 +3656,33 @@ class IfExpr : public Expr {
36553656
}
36563657
};
36573658

3659+
/// EnumIsCaseExpr - A boolean expression that is true if an enum value is of
3660+
/// a particular case.
3661+
class EnumIsCaseExpr : public Expr {
3662+
Expr *SubExpr;
3663+
EnumElementDecl *Element;
3664+
3665+
public:
3666+
EnumIsCaseExpr(Expr *SubExpr, EnumElementDecl *Element)
3667+
: Expr(ExprKind::EnumIsCase, /*implicit*/ true),
3668+
SubExpr(SubExpr), Element(Element)
3669+
{}
3670+
3671+
Expr *getSubExpr() const { return SubExpr; }
3672+
void setSubExpr(Expr *e) { SubExpr = e; }
3673+
3674+
EnumElementDecl *getEnumElement() const { return Element; }
3675+
void setEnumElement(EnumElementDecl *elt) { Element = elt; }
3676+
3677+
SourceLoc getLoc() const { return SubExpr->getLoc(); }
3678+
SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); }
3679+
SourceLoc getEndLoc() const { return SubExpr->getEndLoc(); }
3680+
3681+
static bool classof(const Expr *E) {
3682+
return E->getKind() == ExprKind::EnumIsCase;
3683+
}
3684+
};
3685+
36583686
/// AssignExpr - A value assignment, like "x = y".
36593687
class AssignExpr : public Expr {
36603688
Expr *Dest;

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ ABSTRACT_EXPR(ExplicitCast, Expr)
152152
EXPR_RANGE(ExplicitCast, ForcedCheckedCast, Coerce)
153153
UNCHECKED_EXPR(Arrow, Expr)
154154
EXPR(If, Expr)
155+
EXPR(EnumIsCase, Expr)
155156
EXPR(Assign, Expr)
156157
EXPR(DefaultValue, Expr)
157158
EXPR(CodeCompletion, Expr)

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,6 @@ struct ASTContext::Implementation {
168168
#define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr;
169169
#include "swift/AST/KnownDecls.def"
170170

171-
/// func _stdlib_Optional_isSome<T>(v: Optional<T>) -> Bool
172-
FuncDecl *OptionalIsSomeSomeDecls[NumOptionalTypeKinds] = {};
173-
174-
/// func _stdlib_Optional_unwrapped<T>(v: Optional<T>) -> T
175-
FuncDecl *OptionalUnwrappedDecls[NumOptionalTypeKinds] = {};
176-
177171
/// The declaration of Swift.ImplicitlyUnwrappedOptional<T>.
178172
EnumDecl *ImplicitlyUnwrappedOptionalDecl = nullptr;
179173

@@ -1058,29 +1052,6 @@ FuncDecl *ASTContext::getIsOSVersionAtLeastDecl(LazyResolver *resolver) const {
10581052
return decl;
10591053
}
10601054

1061-
/// Check whether the given function is generic over a single,
1062-
/// unconstrained archetype.
1063-
static bool isGenericIntrinsic(FuncDecl *fn, CanType &input, CanType &output,
1064-
CanType &param) {
1065-
auto fnType =
1066-
dyn_cast<GenericFunctionType>(fn->getInterfaceType()->getCanonicalType());
1067-
if (!fnType || fnType->getGenericParams().size() != 1)
1068-
return false;
1069-
1070-
bool hasRequirements = std::any_of(fnType->getRequirements().begin(),
1071-
fnType->getRequirements().end(),
1072-
[](const Requirement &req) -> bool {
1073-
return req.getKind() != RequirementKind::WitnessMarker;
1074-
});
1075-
if (hasRequirements)
1076-
return false;
1077-
1078-
param = CanGenericTypeParamType(fnType->getGenericParams().front());
1079-
input = stripImmediateLabels(fnType.getInput());
1080-
output = stripImmediateLabels(fnType.getResult());
1081-
return true;
1082-
}
1083-
10841055
// Find library intrinsic function.
10851056
static FuncDecl *findLibraryFunction(const ASTContext &ctx, FuncDecl *&cache,
10861057
StringRef name, LazyResolver *resolver) {
@@ -1097,97 +1068,11 @@ FuncDecl *ASTContext::get##Name(LazyResolver *resolver) const { \
10971068
}
10981069
#include "swift/AST/KnownDecls.def"
10991070

1100-
/// Check whether the given type is Optional applied to the given
1101-
/// type argument.
1102-
static bool isOptionalType(const ASTContext &ctx,
1103-
OptionalTypeKind optionalKind,
1104-
CanType type, CanType arg) {
1105-
if (auto boundType = dyn_cast<BoundGenericType>(type)) {
1106-
return (boundType->getDecl()->classifyAsOptionalType() == optionalKind &&
1107-
boundType.getGenericArgs().size() == 1 &&
1108-
boundType.getGenericArgs()[0] == arg);
1109-
}
1110-
return false;
1111-
}
1112-
1113-
/// Turn an OptionalTypeKind into an index into one of the caches.
1114-
static unsigned asIndex(OptionalTypeKind optionalKind) {
1115-
assert(optionalKind && "passed a non-optional type kind?");
1116-
return unsigned(optionalKind) - 1;
1117-
}
1118-
1119-
#define getOptionalIntrinsicName(PREFIX, KIND, SUFFIX) \
1120-
((KIND) == OTK_Optional \
1121-
? (PREFIX "Optional" SUFFIX) \
1122-
: (PREFIX "ImplicitlyUnwrappedOptional" SUFFIX))
1123-
1124-
FuncDecl *ASTContext::getOptionalIsSomeDecl(
1125-
LazyResolver *resolver, OptionalTypeKind optionalKind) const {
1126-
auto &cache = Impl.OptionalIsSomeSomeDecls[asIndex(optionalKind)];
1127-
if (cache)
1128-
return cache;
1129-
1130-
auto name =
1131-
getOptionalIntrinsicName("_stdlib_", optionalKind, "_isSome");
1132-
1133-
// Look for a generic function.
1134-
CanType input, output, param;
1135-
auto decl = findLibraryIntrinsic(*this, name, resolver);
1136-
if (!decl || !isGenericIntrinsic(decl, input, output, param))
1137-
return nullptr;
1138-
1139-
// Input must be Optional<T>.
1140-
if (!isOptionalType(*this, optionalKind, input, param))
1141-
return nullptr;
1142-
1143-
// Output must be a global type named Bool.
1144-
auto nominalType = dyn_cast<NominalType>(output);
1145-
if (!nominalType || nominalType.getParent() ||
1146-
nominalType->getDecl()->getName().str() != "Bool")
1147-
return nullptr;
1148-
1149-
cache = decl;
1150-
return decl;
1151-
}
1152-
1153-
FuncDecl *ASTContext::getOptionalUnwrappedDecl(LazyResolver *resolver,
1154-
OptionalTypeKind optionalKind) const {
1155-
auto &cache = Impl.OptionalUnwrappedDecls[asIndex(optionalKind)];
1156-
if (cache) return cache;
1157-
1158-
auto name = getOptionalIntrinsicName(
1159-
"_stdlib_", optionalKind, "_unwrapped");
1160-
1161-
// Look for the function.
1162-
CanType input, output, param;
1163-
auto decl = findLibraryIntrinsic(*this, name, resolver);
1164-
if (!decl || !isGenericIntrinsic(decl, input, output, param))
1165-
return nullptr;
1166-
1167-
// Input must be Optional<T>.
1168-
if (!isOptionalType(*this, optionalKind, input, param))
1169-
return nullptr;
1170-
1171-
// Output must be T.
1172-
if (output != param)
1173-
return nullptr;
1174-
1175-
cache = decl;
1176-
return decl;
1177-
}
1178-
1179-
static bool hasOptionalIntrinsics(const ASTContext &ctx, LazyResolver *resolver,
1180-
OptionalTypeKind optionalKind) {
1181-
return ctx.getOptionalIsSomeDecl(resolver, optionalKind) &&
1182-
ctx.getOptionalUnwrappedDecl(resolver, optionalKind);
1183-
}
1184-
11851071
bool ASTContext::hasOptionalIntrinsics(LazyResolver *resolver) const {
11861072
return getOptionalDecl() &&
11871073
getOptionalSomeDecl() &&
11881074
getOptionalNoneDecl() &&
1189-
::hasOptionalIntrinsics(*this, resolver, OTK_Optional) &&
1190-
::hasOptionalIntrinsics(*this, resolver, OTK_ImplicitlyUnwrappedOptional);
1075+
getDiagnoseUnexpectedNilOptional(resolver);
11911076
}
11921077

11931078
bool ASTContext::hasPointerArgumentIntrinsics(LazyResolver *resolver) const {

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,6 +2160,12 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
21602160
printRec(E->getSrc());
21612161
OS << ')';
21622162
}
2163+
void visitEnumIsCaseExpr(EnumIsCaseExpr *E) {
2164+
printCommon(E, "enum_is_case_expr") << ' ' <<
2165+
E->getEnumElement()->getName() << "\n";
2166+
printRec(E->getSubExpr());
2167+
2168+
}
21632169
void visitUnresolvedPatternExpr(UnresolvedPatternExpr *E) {
21642170
printCommon(E, "unresolved_pattern_expr") << '\n';
21652171
printRec(E->getSubPattern());

lib/AST/ASTVerifier.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,26 @@ struct ASTNodeBase {};
835835
checkSameType(lhsTy, S->getSrc()->getType(), "assignment operands");
836836
verifyCheckedBase(S);
837837
}
838+
839+
void verifyChecked(EnumIsCaseExpr *E) {
840+
auto nom = E->getSubExpr()->getType()->getAnyNominal();
841+
if (!nom || !isa<EnumDecl>(nom)) {
842+
Out << "enum_is_decl operand is not an enum: ";
843+
E->getSubExpr()->getType().print(Out);
844+
Out << '\n';
845+
abort();
846+
}
847+
848+
if (nom != E->getEnumElement()->getParentEnum()) {
849+
Out << "enum_is_decl case is not member of enum:\n";
850+
Out << " case: ";
851+
E->getEnumElement()->print(Out);
852+
Out << "\n type: ";
853+
E->getSubExpr()->getType().print(Out);
854+
Out << '\n';
855+
abort();
856+
}
857+
}
838858

839859
void verifyChecked(TupleExpr *E) {
840860
const TupleType *exprTy = E->getType()->castTo<TupleType>();

lib/AST/ASTWalker.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,16 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
747747
return AE;
748748
}
749749

750+
Expr *visitEnumIsCaseExpr(EnumIsCaseExpr *E) {
751+
if (Expr *Sub = E->getSubExpr()) {
752+
if (!(Sub = doIt(Sub)))
753+
return nullptr;
754+
E->setSubExpr(Sub);
755+
}
756+
757+
return E;
758+
}
759+
750760

751761
Expr *visitIfExpr(IfExpr *E) {
752762
if (Expr *Cond = E->getCondExpr()) {

lib/AST/Expr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind,
316316
NON_LVALUE_EXPR(CodeCompletion)
317317
NON_LVALUE_EXPR(ObjCSelector)
318318
NON_LVALUE_EXPR(ObjCKeyPath)
319+
NON_LVALUE_EXPR(EnumIsCase)
319320

320321
#define UNCHECKED_EXPR(KIND, BASE) \
321322
NON_LVALUE_EXPR(KIND)
@@ -600,6 +601,7 @@ bool Expr::canAppendCallParentheses() const {
600601
case ExprKind::LValueToPointer:
601602
case ExprKind::ForeignObjectConversion:
602603
case ExprKind::UnevaluatedInstance:
604+
case ExprKind::EnumIsCase:
603605
// Implicit conversion nodes have no syntax of their own; defer to the
604606
// subexpression.
605607
return cast<ImplicitConversionExpr>(this)->getSubExpr()

lib/SILGen/SILGenConvert.cpp

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,6 @@ getOptionalSomeValue(SILLocation loc, ManagedValue value,
149149
return emitManagedRValueWithCleanup(result, optTL);
150150
}
151151

152-
static Substitution getSimpleSubstitution(GenericSignature *genericSig,
153-
CanType typeArg) {
154-
assert(genericSig->getGenericParams().size() == 1);
155-
return Substitution{typeArg, {}};
156-
}
157-
158-
/// Create the correct substitution for calling the given function at
159-
/// the given type.
160-
static Substitution getSimpleSubstitution(FuncDecl *fn, CanType typeArg) {
161-
auto genericFnType =
162-
cast<GenericFunctionType>(fn->getInterfaceType()->getCanonicalType());
163-
return getSimpleSubstitution(genericFnType->getGenericSignature(), typeArg);
164-
}
165-
166152
static CanType getOptionalValueType(SILType optType,
167153
OptionalTypeKind &optionalKind) {
168154
auto generic = cast<BoundGenericType>(optType.getSwiftRValueType());
@@ -172,19 +158,24 @@ static CanType getOptionalValueType(SILType optType,
172158
}
173159

174160
void SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
175-
SILValue addr) {
161+
SILValue optional) {
176162
OptionalTypeKind OTK;
177-
getOptionalValueType(addr->getType().getObjectType(), OTK);
163+
getOptionalValueType(optional->getType().getObjectType(), OTK);
178164

179-
// Generate code to the optional is present, and if not abort with a message
165+
// Generate code to the optional is present, and if not, abort with a message
180166
// (provided by the stdlib).
181167
SILBasicBlock *contBB = createBasicBlock();
182168
SILBasicBlock *failBB = createBasicBlock();
183169

184170
auto NoneEnumElementDecl = getASTContext().getOptionalNoneDecl(OTK);
185-
B.createSwitchEnumAddr(loc, addr, /*defaultDest*/contBB,
186-
{ { NoneEnumElementDecl, failBB }});
187-
171+
if (optional->getType().isAddress()) {
172+
B.createSwitchEnumAddr(loc, optional, /*defaultDest*/contBB,
173+
{ { NoneEnumElementDecl, failBB }});
174+
} else {
175+
B.createSwitchEnum(loc, optional, /*defaultDest*/contBB,
176+
{ { NoneEnumElementDecl, failBB }});
177+
178+
}
188179
B.emitBlock(failBB);
189180

190181
// Call the standard library implementation of _diagnoseUnexpectedNilOptional.
@@ -221,27 +212,8 @@ ManagedValue SILGenFunction::emitCheckedGetOptionalValueFrom(SILLocation loc,
221212
ManagedValue src,
222213
const TypeLowering &optTL,
223214
SGFContext C) {
224-
SILType optType = src.getType().getObjectType();
225-
OptionalTypeKind optionalKind;
226-
CanType valueType = getOptionalValueType(optType, optionalKind);
227-
228-
FuncDecl *fn = getASTContext().getOptionalUnwrappedDecl(
229-
nullptr, optionalKind);
230-
Substitution sub = getSimpleSubstitution(fn, valueType);
231-
232-
// The intrinsic takes its parameter indirectly.
233-
if (src.getType().isObject()) {
234-
auto buf = emitTemporaryAllocation(loc, src.getType());
235-
B.createStore(loc, src.forward(*this), buf);
236-
src = emitManagedBufferWithCleanup(buf);
237-
}
238-
239-
RValue result = emitApplyOfLibraryIntrinsic(loc, fn, sub, src, C);
240-
if (result) {
241-
return std::move(result).getAsSingleValue(*this, loc);
242-
} else {
243-
return ManagedValue::forInContext();
244-
}
215+
emitPreconditionOptionalHasValue(loc, src.getValue());
216+
return emitUncheckedGetOptionalValueFrom(loc, src, optTL, C);
245217
}
246218

247219
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc,

0 commit comments

Comments
 (0)