Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4704,7 +4704,7 @@ class ForcedCheckedCastExpr final : public CheckedCastExpr {

/// Represents an explicit conditional checked cast, which converts
/// from a type to some subtype and produces an Optional value, which will be
/// .Some(x) if the cast succeeds, or .None if the cast fails.
/// .some(x) if the cast succeeds, or .none if the cast fails.
/// Spelled 'a as? T' and produces a value of type 'T?'.
class ConditionalCheckedCastExpr final : public CheckedCastExpr {
SourceLoc QuestionLoc;
Expand All @@ -4722,9 +4722,6 @@ class ConditionalCheckedCastExpr final : public CheckedCastExpr {
static ConditionalCheckedCastExpr *createImplicit(ASTContext &ctx, Expr *sub,
Type castTy);

static ConditionalCheckedCastExpr *
createImplicit(ASTContext &ctx, Expr *sub, TypeRepr *tyRepr, Type castTy);

/// Retrieve the location of the '?' that follows 'as'.
SourceLoc getQuestionLoc() const { return QuestionLoc; }

Expand Down Expand Up @@ -4911,20 +4908,21 @@ class IfExpr : public Expr {
/// a particular case.
class EnumIsCaseExpr : public Expr {
Expr *SubExpr;
TypeRepr *CaseRepr;
EnumElementDecl *Element;

public:
EnumIsCaseExpr(Expr *SubExpr, EnumElementDecl *Element)
: Expr(ExprKind::EnumIsCase, /*implicit*/ true),
SubExpr(SubExpr), Element(Element)
{}

EnumIsCaseExpr(Expr *SubExpr, TypeRepr *CaseRepr, EnumElementDecl *Element)
: Expr(ExprKind::EnumIsCase, /*implicit*/ true), SubExpr(SubExpr),
CaseRepr(CaseRepr), Element(Element) {}

Expr *getSubExpr() const { return SubExpr; }
void setSubExpr(Expr *e) { SubExpr = e; }


TypeRepr *getCaseTypeRepr() const { return CaseRepr; }

EnumElementDecl *getEnumElement() const { return Element; }
void setEnumElement(EnumElementDecl *elt) { Element = elt; }


SourceLoc getLoc() const { return SubExpr->getLoc(); }
SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); }
SourceLoc getEndLoc() const { return SubExpr->getEndLoc(); }
Expand Down
6 changes: 5 additions & 1 deletion lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,11 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
return nullptr;
E->setSubExpr(Sub);
}


if (auto *typerepr = E->getCaseTypeRepr())
if (doIt(typerepr))
return nullptr;

return E;
}

Expand Down
11 changes: 0 additions & 11 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1808,17 +1808,6 @@ ConditionalCheckedCastExpr::createImplicit(ASTContext &ctx, Expr *sub,
return expr;
}

ConditionalCheckedCastExpr *
ConditionalCheckedCastExpr::createImplicit(ASTContext &ctx, Expr *sub,
TypeRepr *tyRepr, Type castTy) {
auto *const expr = new (ctx) ConditionalCheckedCastExpr(
sub, SourceLoc(), SourceLoc(), new (ctx) TypeExpr(tyRepr));
expr->setType(OptionalType::get(castTy));
expr->setImplicit();
expr->setCastType(castTy);
return expr;
}

IsExpr *IsExpr::create(ASTContext &ctx, SourceLoc isLoc, TypeRepr *tyRepr) {
return new (ctx) IsExpr(nullptr, isLoc, new (ctx) TypeExpr(tyRepr));
}
Expand Down
38 changes: 23 additions & 15 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3574,12 +3574,14 @@ namespace {
castKind == CheckedCastKind::ArrayDowncast ||
castKind == CheckedCastKind::DictionaryDowncast ||
castKind == CheckedCastKind::SetDowncast) {
auto *const cast = ConditionalCheckedCastExpr::createImplicit(
ctx, sub, castTypeRepr, toType);
auto *const cast =
ConditionalCheckedCastExpr::createImplicit(ctx, sub, toType);
cast->setType(OptionalType::get(toType));
cast->setCastType(toType);
cs.setType(cast, cast->getType());

// Type-check this conditional case.
Expr *result = handleConditionalCheckedCastExpr(cast, true);
Expr *result = handleConditionalCheckedCastExpr(cast, castTypeRepr);
if (!result)
return nullptr;

Expand All @@ -3588,7 +3590,8 @@ namespace {

// Match the optional value against its `Some` case.
auto *someDecl = ctx.getOptionalSomeDecl();
auto isSomeExpr = new (ctx) EnumIsCaseExpr(result, someDecl);
auto isSomeExpr =
new (ctx) EnumIsCaseExpr(result, castTypeRepr, someDecl);
auto boolDecl = ctx.getBoolDecl();

if (!boolDecl) {
Expand Down Expand Up @@ -4010,40 +4013,45 @@ namespace {
}

Expr *visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) {
// Simplify and update the type we're casting to.
auto *const castTypeRepr = expr->getCastTypeRepr();
const auto toType = simplifyType(cs.getType(castTypeRepr));
expr->setCastType(toType);
cs.setType(castTypeRepr, toType);

// If we need to insert a force-unwrap for coercions of the form
// 'as! T!', do so now.
if (hasForcedOptionalResult(expr)) {
auto *coerced = handleConditionalCheckedCastExpr(expr);
auto *coerced = handleConditionalCheckedCastExpr(expr, castTypeRepr);
if (!coerced)
return nullptr;

return coerceImplicitlyUnwrappedOptionalToValue(
coerced, cs.getType(coerced)->getOptionalObjectType());
}

return handleConditionalCheckedCastExpr(expr);
return handleConditionalCheckedCastExpr(expr, castTypeRepr);
}

Expr *handleConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr,
bool isInsideIsExpr = false) {
TypeRepr *castTypeRepr) {
assert(castTypeRepr &&
"cast requires TypeRepr; implicit casts are superfluous");

// The subexpression is always an rvalue.
auto &ctx = cs.getASTContext();
auto sub = cs.coerceToRValue(expr->getSubExpr());
expr->setSubExpr(sub);

// Simplify and update the type we're casting to.
auto *const castTypeRepr = expr->getCastTypeRepr();

const auto fromType = cs.getType(sub);
const auto toType = simplifyType(cs.getType(castTypeRepr));
expr->setCastType(toType);
cs.setType(castTypeRepr, toType);
const auto toType = expr->getCastType();

bool isSubExprLiteral = isa<LiteralExpr>(sub);
auto castContextKind =
(SuppressDiagnostics || isInsideIsExpr || isSubExprLiteral)
? CheckedCastContextKind::None
: CheckedCastContextKind::ConditionalCast;
(SuppressDiagnostics || expr->isImplicit() || isSubExprLiteral)
? CheckedCastContextKind::None
: CheckedCastContextKind::ConditionalCast;

auto castKind = TypeChecker::typeCheckCheckedCast(
fromType, toType, castContextKind, cs.DC, expr->getLoc(), sub,
Expand Down