Refactor cast representation in AST and SIL, and implement 'is'.

Improve our representations of casts in the AST and SIL so that 'as!' and 'is' (and eventually 'as?') can share almost all of the same type-checking, SILGen, and IRGen code.

In the AST, we now represent 'as!' and 'is' as UnconditionalCheckedCastExpr and IsaExpr, respectively, with the semantic variations of cast (downcast, super-to-archetype, archetype-to-concrete, etc.) discriminated by an enum field. This keeps the user-visible syntactic and type behavior differences of the two forms cleanly separated for AST consumers.

At the SIL level, we transpose the representation so that the different cast semantics get their own instructions and the conditional/unconditional cast behavior is indicated by an enum, making it easy for IRGen to discriminate the different code paths for the different semantics. We also add an 'IsNonnull' instruction to cover the conditional-cast-result-to-boolean conversion common to all the forms of 'is'.

The upshot of all this is that 'x is T' now works for all the new archetype and existential cast forms supported by 'as!'.

Swift SVN r5737
This commit is contained in:
Joe Groff
2013-06-21 05:54:03 +00:00
parent be0f7b4c48
commit f072c48e45
28 changed files with 587 additions and 636 deletions

View File

@@ -964,6 +964,9 @@ ERROR(cannot_construct_type,sema_tcc,none,
ERROR(downcast_to_supertype,sema_tcc,none,
"downcast from %0 to supertype %1 is a coercion; remove the '!'",
(Type, Type))
ERROR(isa_is_always_true,sema_tcc,none,
"'is' test is always true",
(Type, Type))
ERROR(downcast_to_unrelated,sema_tcc,none,
"downcast from %0 to unrelated type %1", (Type, Type))
ERROR(downcast_to_existential,sema_tcc,none,

View File

@@ -2142,23 +2142,30 @@ public:
}
};
/// \brief Represents an explicit cast, 'a as T', 'a as? T', or 'a as! T',
/// where "T" is a type, and "a" is the expression that will be converted to
/// the type.
/// \brief Represents an explicit cast, 'a as T', 'a as? T', 'a as! T', or
/// 'a is T', where "T" is a type, and "a" is the expression that will be
/// converted to the type.
class ExplicitCastExpr : public Expr {
Expr *SubExpr;
SourceLoc AsLoc;
TypeLoc Ty;
TypeLoc CastTy;
protected:
ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeLoc type)
: Expr(kind, type.getType()), SubExpr(sub), AsLoc(AsLoc), Ty(type)
ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeLoc castTy,
Type resultTy)
: Expr(kind), SubExpr(sub), AsLoc(AsLoc), CastTy(castTy)
{}
public:
Expr *getSubExpr() const { return SubExpr; }
TypeLoc &getTypeLoc() { return Ty; }
TypeLoc getTypeLoc() const { return Ty; }
/// Get the type syntactically spelled in the cast. For some forms of checked
/// cast this is different from the result type of the expression.
TypeLoc &getCastTypeLoc() { return CastTy; }
/// Get the type syntactically spelled in the cast. For some forms of checked
/// cast this is different from the result type of the expression.
TypeLoc getCastTypeLoc() const { return CastTy; }
void setSubExpr(Expr *E) { SubExpr = E; }
@@ -2166,8 +2173,8 @@ public:
SourceRange getSourceRange() const {
return SubExpr
? SourceRange{SubExpr->getStartLoc(), Ty.getSourceRange().End}
: SourceRange{AsLoc, Ty.getSourceRange().End};
? SourceRange{SubExpr->getStartLoc(), CastTy.getSourceRange().End}
: SourceRange{AsLoc, CastTy.getSourceRange().End};
}
/// True if the node has been processed by SequenceExpr folding.
@@ -2188,7 +2195,8 @@ public:
class CoerceExpr : public ExplicitCastExpr {
public:
CoerceExpr(Expr *sub, SourceLoc asLoc, TypeLoc type)
: ExplicitCastExpr(ExprKind::Coerce, sub, asLoc, type) { }
: ExplicitCastExpr(ExprKind::Coerce, sub, asLoc, type,
type.getType()) { }
CoerceExpr(SourceLoc asLoc, TypeLoc type)
: CoerceExpr(nullptr, asLoc, type)
@@ -2198,169 +2206,103 @@ public:
return E->getKind() == ExprKind::Coerce;
}
};
/// Discriminates the different kinds of checked cast supported.
enum class CheckedCastKind {
/// The kind has not been determined yet.
Unresolved,
/// The requested conversion is implicit and should be represented as a
/// coercion.
InvalidCoercible,
/// Valid resolved kinds start here.
First_Resolved,
/// A cast from a class to one of its subclasses.
Downcast = First_Resolved,
/// A cast from a class to a type parameter constrained by that class as a
/// base class.
SuperToArchetype,
/// A cast from a type parameter to another type parameter.
ArchetypeToArchetype,
/// A cast from a type parameter to a concrete type.
ArchetypeToConcrete,
/// A cast from an existential type to a type parameter.
ExistentialToArchetype,
/// A cast from an existential type to a concrete type.
ExistentialToConcrete,
};
/// \brief Abstract base class for checked casts 'as!' and 'is'. These represent
/// casts that can dynamically fail.
class CheckedCastExpr : public ExplicitCastExpr {
CheckedCastKind CastKind;
public:
CheckedCastExpr(ExprKind kind,
Expr *sub, SourceLoc asLoc, TypeLoc castTy, Type resultTy)
: ExplicitCastExpr(kind, sub, asLoc, castTy, resultTy),
CastKind(CheckedCastKind::Unresolved)
{}
/// Return the semantic kind of cast performed.
CheckedCastKind getCastKind() const { return CastKind; }
void setCastKind(CheckedCastKind kind) { CastKind = kind; }
/// True if the cast has been type-checked and its kind has been set.
bool isResolved() const {
return CastKind >= CheckedCastKind::First_Resolved;
}
static bool classof(const Expr *E) {
return E->getKind() >= ExprKind::First_CheckedCastExpr
&& E->getKind() <= ExprKind::Last_CheckedCastExpr;
}
};
/// \brief Represents an explicit unchecked downcast, converting from a
/// supertype to its subtype or crashing if the cast is not possible,
/// \brief Represents an explicit unconditional checked cast, which converts
/// from a type to some subtype or aborts if the cast is not possible,
/// spelled 'a as! T'.
///
/// FIXME: At present, only class downcasting is supported.
/// FIXME: All downcasts are currently unchecked, which is horrible.
class UncheckedDowncastExpr : public ExplicitCastExpr {
/// FIXME: All downcasts are currently unconditional, which is horrible.
class UnconditionalCheckedCastExpr : public CheckedCastExpr {
SourceLoc BangLoc;
public:
UncheckedDowncastExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
TypeLoc type)
: ExplicitCastExpr(ExprKind::UncheckedDowncast, sub, asLoc, type),
UnconditionalCheckedCastExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
TypeLoc type)
: CheckedCastExpr(ExprKind::UnconditionalCheckedCast,
sub, asLoc, type, type.getType()),
BangLoc(bangLoc) { }
UncheckedDowncastExpr(SourceLoc asLoc, SourceLoc bangLoc, TypeLoc type)
: UncheckedDowncastExpr(nullptr, asLoc, bangLoc, type)
UnconditionalCheckedCastExpr(SourceLoc asLoc, SourceLoc bangLoc, TypeLoc type)
: UnconditionalCheckedCastExpr(nullptr, asLoc, bangLoc, type)
{}
SourceLoc getBangLoc() const { return BangLoc; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UncheckedDowncast;
return E->getKind() == ExprKind::UnconditionalCheckedCast;
}
};
/// \brief Represents an explicit unchecked downcast, converting from a
/// superclass of an archetype to the archetype iself or crashing if the cast
/// is not possible, spelled 'a as! T' for an archetype type T.
///
/// FIXME: All downcasts are currently unchecked, which is horrible.
class UncheckedSuperToArchetypeExpr : public ExplicitCastExpr {
SourceLoc BangLoc;
public:
UncheckedSuperToArchetypeExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
TypeLoc type)
: ExplicitCastExpr(ExprKind::UncheckedSuperToArchetype, sub, asLoc, type),
BangLoc(bangLoc) { }
SourceLoc getBangLoc() const { return BangLoc; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UncheckedSuperToArchetype;
}
};
/// \brief Represents an explicit unchecked cast from an archetype value to a
/// different archetype, spelled 't as! U' for an archetype value t and
/// archetype type U.
class UncheckedArchetypeToArchetypeExpr : public ExplicitCastExpr {
SourceLoc BangLoc;
public:
UncheckedArchetypeToArchetypeExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
TypeLoc type)
: ExplicitCastExpr(ExprKind::UncheckedArchetypeToArchetype, sub, asLoc, type),
BangLoc(bangLoc) { }
SourceLoc getBangLoc() const { return BangLoc; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UncheckedArchetypeToArchetype;
}
};
/// \brief Represents an explicit unchecked cast from an archetype value to a
/// concrete type, spelled 't as! A' for an archetype value t
/// and concrete type 'A'.
class UncheckedArchetypeToConcreteExpr : public ExplicitCastExpr {
SourceLoc BangLoc;
public:
UncheckedArchetypeToConcreteExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
TypeLoc type)
: ExplicitCastExpr(ExprKind::UncheckedArchetypeToConcrete, sub, asLoc, type),
BangLoc(bangLoc) { }
SourceLoc getBangLoc() const { return BangLoc; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UncheckedArchetypeToConcrete;
}
};
/// \brief Represents an explicit unchecked cast from an existential type value
/// to an archetype, spelled 'p as! T' for a protocol value p
/// and archetype type 'T'.
class UncheckedExistentialToArchetypeExpr : public ExplicitCastExpr {
SourceLoc BangLoc;
public:
UncheckedExistentialToArchetypeExpr(Expr *sub, SourceLoc asLoc,
SourceLoc bangLoc,
TypeLoc type)
: ExplicitCastExpr(ExprKind::UncheckedExistentialToArchetype,
sub, asLoc, type),
BangLoc(bangLoc) { }
SourceLoc getBangLoc() const { return BangLoc; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UncheckedExistentialToArchetype;
}
};
/// \brief Represents an explicit unchecked cast from an existential type value
/// to a concrete type, spelled 'p as! A' for a protocol value p
/// and conforming type 'A'.
class UncheckedExistentialToConcreteExpr : public ExplicitCastExpr {
SourceLoc BangLoc;
public:
UncheckedExistentialToConcreteExpr(Expr *sub, SourceLoc asLoc,
SourceLoc bangLoc,
TypeLoc type)
: ExplicitCastExpr(ExprKind::UncheckedExistentialToConcrete,
sub, asLoc, type),
BangLoc(bangLoc) { }
SourceLoc getBangLoc() const { return BangLoc; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UncheckedExistentialToConcrete;
}
};
/// \brief Represents a runtime type check query, 'a is T', where 'T' is a type
/// and 'a' is a value of a supertype of T. Evaluates to true if 'a' is of the
/// and 'a' is a value of some related type. Evaluates to true if 'a' is of the
/// type and 'a as! T' would succeed, false otherwise.
class IsSubtypeExpr : public Expr {
Expr *SubExpr;
TypeLoc Type;
SourceLoc IsLoc;
///
/// FIXME: We should support type queries with a runtime metatype value too.
class IsaExpr : public CheckedCastExpr {
public:
IsSubtypeExpr(Expr *sub, SourceLoc isLoc, TypeLoc type)
: Expr(ExprKind::IsSubtype), SubExpr(sub), Type(type), IsLoc(isLoc)
IsaExpr(Expr *sub, SourceLoc isLoc, TypeLoc type)
: CheckedCastExpr(ExprKind::Isa,
sub, isLoc, type, Type())
{}
IsSubtypeExpr(SourceLoc isLoc, TypeLoc type)
: IsSubtypeExpr(nullptr, isLoc, type)
IsaExpr(SourceLoc isLoc, TypeLoc type)
: IsaExpr(nullptr, isLoc, type)
{}
Expr *getSubExpr() const { return SubExpr; }
TypeLoc &getTypeLoc() { return Type; }
TypeLoc getTypeLoc() const { return Type; }
void setSubExpr(Expr *E) { SubExpr = E; }
SourceLoc getLoc() const { return IsLoc; }
SourceRange getSourceRange() const {
return SubExpr
? SourceRange{SubExpr->getStartLoc(), Type.getSourceRange().End}
: SourceRange{IsLoc, Type.getSourceRange().End};
}
/// True if the node has been processed by SequenceExpr folding.
bool isFolded() const { return SubExpr; }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::IsSubtype;
return E->getKind() == ExprKind::Isa;
}
};

View File

@@ -121,15 +121,12 @@ ABSTRACT_EXPR(ImplicitConversion, Expr)
EXPR_RANGE(ImplicitConversion, Load, BridgeToBlock)
ABSTRACT_EXPR(ExplicitCast, Expr)
EXPR(Coerce, ExplicitCastExpr)
EXPR(UncheckedDowncast, ExplicitCastExpr)
EXPR(UncheckedSuperToArchetype, ExplicitCastExpr)
EXPR(UncheckedArchetypeToConcrete, ExplicitCastExpr)
EXPR(UncheckedArchetypeToArchetype, ExplicitCastExpr)
EXPR(UncheckedExistentialToArchetype, ExplicitCastExpr)
EXPR(UncheckedExistentialToConcrete, ExplicitCastExpr)
EXPR_RANGE(ExplicitCast, Coerce, UncheckedExistentialToConcrete)
ABSTRACT_EXPR(CheckedCast, ExplicitCastExpr)
EXPR(UnconditionalCheckedCast, CheckedCastExpr)
EXPR(Isa, CheckedCastExpr)
EXPR_RANGE(CheckedCast, UnconditionalCheckedCast, Isa)
EXPR_RANGE(ExplicitCast, Coerce, Isa)
EXPR(If, Expr)
EXPR(IsSubtype, Expr)
EXPR(Assign, Expr)
EXPR(ZeroValue, Expr)
EXPR(DefaultValue, Expr)

View File

@@ -241,11 +241,6 @@ public:
UpcastInst(Loc, Op, Ty));
}
DowncastInst *createDowncast(SILLocation Loc, SILValue Op, SILType Ty) {
return insert(new (F.getModule())
DowncastInst(Loc, Op, Ty));
}
AddressToPointerInst *createAddressToPointer(SILLocation Loc, SILValue Op,
SILType Ty) {
return insert(new (F.getModule())
@@ -306,44 +301,55 @@ public:
ArchetypeRefToSuperInst(Loc, Archetype, BaseTy));
}
DowncastInst *createDowncast(SILLocation Loc, SILValue Op, SILType Ty,
CheckedCastMode Mode) {
return insert(new (F.getModule())
DowncastInst(Loc, Op, Ty, Mode));
}
SuperToArchetypeRefInst *createSuperToArchetypeRef(SILLocation Loc,
SILValue Archetype,
SILType BaseTy) {
SILType BaseTy,
CheckedCastMode Mode) {
return insert(new (F.getModule())
SuperToArchetypeRefInst(Loc, Archetype, BaseTy));
SuperToArchetypeRefInst(Loc, Archetype, BaseTy, Mode));
}
DowncastArchetypeAddrInst *createDowncastArchetypeAddr(SILLocation Loc,
SILValue Archetype,
SILType Ty) {
SILType Ty,
CheckedCastMode Mode) {
return insert(new (F.getModule())
DowncastArchetypeAddrInst(Loc, Archetype, Ty));
DowncastArchetypeAddrInst(Loc, Archetype, Ty, Mode));
}
DowncastArchetypeRefInst *createDowncastArchetypeRef(SILLocation Loc,
SILValue Archetype,
SILType Ty) {
SILType Ty,
CheckedCastMode Mode) {
return insert(new (F.getModule())
DowncastArchetypeRefInst(Loc, Archetype, Ty));
DowncastArchetypeRefInst(Loc, Archetype, Ty, Mode));
}
ProjectDowncastExistentialAddrInst *createProjectDowncastExistentialAddr(SILLocation Loc,
ProjectDowncastExistentialAddrInst *createProjectDowncastExistentialAddr(
SILLocation Loc,
SILValue Existential,
SILType Ty) {
SILType Ty,
CheckedCastMode Mode) {
return insert(new (F.getModule())
ProjectDowncastExistentialAddrInst(Loc, Existential, Ty));
ProjectDowncastExistentialAddrInst(Loc, Existential, Ty, Mode));
}
DowncastExistentialRefInst *createDowncastExistentialRef(SILLocation Loc,
SILValue Existential,
SILType Ty) {
SILType Ty,
CheckedCastMode Mode) {
return insert(new (F.getModule())
DowncastExistentialRefInst(Loc, Existential, Ty));
DowncastExistentialRefInst(Loc, Existential, Ty, Mode));
}
IsaInst *createIsa(SILLocation Loc,
SILValue Operand,
SILType TestType,
SILType ResultType) {
IsNonnullInst *createIsNonnull(SILLocation Loc,
SILValue Operand,
SILType ResultType) {
return insert(new (F.getModule())
IsaInst(Loc, Operand, TestType, ResultType));
IsNonnullInst(Loc, Operand, ResultType));
}
StructInst *createStruct(SILLocation Loc, SILType Ty,

View File

@@ -701,20 +701,11 @@ public:
UpcastInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// DowncastInst - Perform an unchecked conversion of a class instance to a
/// subclass type.
class DowncastInst
: public UnaryInstructionBase<ValueKind::DowncastInst, ConversionInst>
{
public:
DowncastInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// AddressToPointerInst - Convert a SIL address to a Builtin.RawPointer value.
class AddressToPointerInst
: public UnaryInstructionBase<ValueKind::AddressToPointerInst, ConversionInst>
: public UnaryInstructionBase<ValueKind::AddressToPointerInst,
ConversionInst>
{
public:
AddressToPointerInst(SILLocation Loc, SILValue Operand, SILType Ty)
@@ -811,29 +802,54 @@ public:
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// Test that an address or reference type is not null.
class IsNonnullInst : public UnaryInstructionBase<ValueKind::IsNonnullInst> {
public:
IsNonnullInst(SILLocation Loc, SILValue Operand, SILType BoolTy)
: UnaryInstructionBase(Loc, Operand, BoolTy) {}
};
/// Discriminates checked cast modes.
enum class CheckedCastMode : unsigned char {
// Abort if the cast fails.
Unconditional,
// Return null if the cast fails.
Conditional,
};
/// CheckedConversionInst - Abstract base class for checked conversions.
class CheckedConversionInst : public ConversionInst {
CheckedCastMode Mode;
public:
CheckedConversionInst(ValueKind Kind, SILLocation Loc, SILType Ty,
CheckedCastMode Mode)
: ConversionInst(Kind, Loc, Ty), Mode(Mode) {}
CheckedCastMode getMode() const { return Mode; }
};
/// DowncastInst - Perform an unchecked conversion of a class instance to a
/// subclass type.
class DowncastInst
: public UnaryInstructionBase<ValueKind::DowncastInst, CheckedConversionInst>
{
public:
DowncastInst(SILLocation Loc, SILValue Operand, SILType Ty,
CheckedCastMode Mode)
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
};
/// SuperToArchetypeRefInst - Given a value of a class type, initializes a
/// class archetype with a base class constraint to contain a reference to
/// the value.
class SuperToArchetypeRefInst
: public UnaryInstructionBase<ValueKind::SuperToArchetypeRefInst,
ConversionInst>
CheckedConversionInst>
{
public:
SuperToArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// IsaInst - Perform a runtime check of a class instance's type.
class IsaInst : public UnaryInstructionBase<ValueKind::IsaInst> {
SILType TestType;
public:
IsaInst(SILLocation Loc,
SILValue Operand,
SILType TestTy,
SILType BoolTy)
: UnaryInstructionBase(Loc, Operand, BoolTy), TestType(TestTy) {}
SILType getTestType() const { return TestType; }
SuperToArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty,
CheckedCastMode Mode)
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
};
/// Given the address of an opaque archetype value, dynamically checks the concrete
@@ -841,11 +857,12 @@ public:
/// successful or crashes if not.
class DowncastArchetypeAddrInst
: public UnaryInstructionBase<ValueKind::DowncastArchetypeAddrInst,
ConversionInst>
CheckedConversionInst>
{
public:
DowncastArchetypeAddrInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
DowncastArchetypeAddrInst(SILLocation Loc, SILValue Operand, SILType Ty,
CheckedCastMode Mode)
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
};
/// Given a value of class archetype type, dynamically checks the concrete
@@ -853,11 +870,12 @@ public:
/// successful or crashes if not.
class DowncastArchetypeRefInst
: public UnaryInstructionBase<ValueKind::DowncastArchetypeRefInst,
ConversionInst>
CheckedConversionInst>
{
public:
DowncastArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
DowncastArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty,
CheckedCastMode Mode)
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
};
/// Given the address of an opaque existential container, dynamically checks the
@@ -865,11 +883,13 @@ public:
/// the contained value if successful or crashes if not.
class ProjectDowncastExistentialAddrInst
: public UnaryInstructionBase<ValueKind::ProjectDowncastExistentialAddrInst,
ConversionInst>
CheckedConversionInst>
{
public:
ProjectDowncastExistentialAddrInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
ProjectDowncastExistentialAddrInst(SILLocation Loc, SILValue Operand,
SILType Ty,
CheckedCastMode Mode)
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
};
/// Given a value of class archetype type, dynamically checks the concrete
@@ -877,11 +897,12 @@ public:
/// successful or crashes if not.
class DowncastExistentialRefInst
: public UnaryInstructionBase<ValueKind::DowncastExistentialRefInst,
ConversionInst>
CheckedConversionInst>
{
public:
DowncastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
DowncastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty,
CheckedCastMode Mode)
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
};
/// StructInst - Represents a constructed tuple.

View File

@@ -115,7 +115,6 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(ConvertFunctionInst, ConversionInst)
INST(CoerceInst, ConversionInst)
INST(UpcastInst, ConversionInst)
INST(DowncastInst, ConversionInst)
INST(AddressToPointerInst, ConversionInst)
INST(PointerToAddressInst, ConversionInst)
INST(RefToObjectPointerInst, ConversionInst)
@@ -126,13 +125,16 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(ConvertCCInst, ConversionInst)
INST(BridgeToBlockInst, ConversionInst)
INST(ArchetypeRefToSuperInst, ConversionInst)
INST(SuperToArchetypeRefInst, ConversionInst)
INST(DowncastArchetypeAddrInst, ConversionInst)
INST(DowncastArchetypeRefInst, ConversionInst)
INST(ProjectDowncastExistentialAddrInst, ConversionInst)
INST(DowncastExistentialRefInst, ConversionInst)
ABSTRACT_VALUE(CheckedConversionInst, ConversionInst)
INST(DowncastInst, CheckedConversionInst)
INST(SuperToArchetypeRefInst, CheckedConversionInst)
INST(DowncastArchetypeAddrInst, CheckedConversionInst)
INST(DowncastArchetypeRefInst, CheckedConversionInst)
INST(ProjectDowncastExistentialAddrInst, CheckedConversionInst)
INST(DowncastExistentialRefInst, CheckedConversionInst)
VALUE_RANGE(CheckedConversionInst, DowncastInst, DowncastExistentialRefInst)
VALUE_RANGE(ConversionInst, ConvertFunctionInst, DowncastExistentialRefInst)
INST(IsaInst, SILInstruction)
INST(IsNonnullInst, SILInstruction)
// Array indexing instructions.
ABSTRACT_VALUE(IndexingInst, SILInstruction)

View File

@@ -363,16 +363,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*> {
return E;
}
Expr *visitIsSubtypeExpr(IsSubtypeExpr *E) {
if (Expr *Sub = E->getSubExpr()) {
Sub = doIt(Sub);
if (!Sub) return nullptr;
E->setSubExpr(Sub);
}
return E;
}
Expr *visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) {
Expr *Sub = doIt(E->getSubExpr());
if (!Sub) return nullptr;

View File

@@ -130,7 +130,7 @@ bool Expr::isImplicit() const {
return true;
}
if (auto downcast = dyn_cast<UncheckedDowncastExpr>(this)) {
if (auto downcast = dyn_cast<ExplicitCastExpr>(this)) {
return downcast->getLoc().isInvalid() &&
downcast->getSubExpr()->isImplicit();
}
@@ -863,7 +863,7 @@ public:
void printExplicitCastExpr(ExplicitCastExpr *E, const char *name) {
printCommon(E, name) << ' ';
E->getTypeLoc().getType()->print(OS);
E->getCastTypeLoc().getType()->print(OS);
OS << '\n';
printRec(E->getSubExpr());
OS << ')';
@@ -872,23 +872,11 @@ public:
void visitCoerceExpr(CoerceExpr *E) {
printExplicitCastExpr(E, "coerce_expr");
}
void visitUncheckedDowncastExpr(UncheckedDowncastExpr *E) {
printExplicitCastExpr(E, "unchecked_downcast_expr");
void visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *E) {
printExplicitCastExpr(E, "unconditional_checked_cast_expr");
}
void visitUncheckedSuperToArchetypeExpr(UncheckedSuperToArchetypeExpr *E) {
printExplicitCastExpr(E, "unchecked_super_to_archetype_expr");
}
void visitUncheckedArchetypeToArchetypeExpr(UncheckedArchetypeToArchetypeExpr *E) {
printExplicitCastExpr(E, "unchecked_archetype_to_archetype_expr");
}
void visitUncheckedArchetypeToConcreteExpr(UncheckedArchetypeToConcreteExpr *E) {
printExplicitCastExpr(E, "unchecked_archetype_to_concrete_expr");
}
void visitUncheckedExistentialToArchetypeExpr(UncheckedExistentialToArchetypeExpr *E) {
printExplicitCastExpr(E, "unchecked_existential_to_archetype_expr");
}
void visitUncheckedExistentialToConcreteExpr(UncheckedExistentialToConcreteExpr *E) {
printExplicitCastExpr(E, "unchecked_existential_to_concrete_expr");
void visitIsaExpr(IsaExpr *E) {
printExplicitCastExpr(E, "is_subtype_expr");
}
void visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) {
printCommon(E, "rebind_this_in_constructor_expr") << '\n';
@@ -904,13 +892,6 @@ public:
printRec(E->getElseExpr());
OS << ')';
}
void visitIsSubtypeExpr(IsSubtypeExpr *E) {
printCommon(E, "is_subtype_expr") << ' ';
E->getTypeLoc().getType()->print(OS);
OS << '\n';
printRec(E->getSubExpr());
OS << ')';
}
void visitDefaultValueExpr(DefaultValueExpr *E) {
printCommon(E, "default_value_expr") << ' ';
printRec(E->getSubExpr());

View File

@@ -508,13 +508,32 @@ namespace {
}
void verifyChecked(CoerceExpr *E) {
Type Ty = E->getTypeLoc().getType();
Type Ty = E->getCastTypeLoc().getType();
if (!Ty->isEqual(E->getType()) ||
!Ty->isEqual(E->getSubExpr()->getType())) {
Out << "CoerceExpr types don't match\n";
abort();
}
}
void verifyChecked(UnconditionalCheckedCastExpr *E) {
Type Ty = E->getCastTypeLoc().getType();
if (!Ty->isEqual(E->getType())) {
Out << "UnconditionalCheckedCast types don't match\n";
abort();
}
if (!E->isResolved()) {
Out << "UnconditionalCheckedCast kind not resolved\n";
abort();
}
}
void verifyChecked(CheckedCastExpr *E) {
if (!E->isResolved()) {
Out << "CheckedCast kind not resolved\n";
abort();
}
}
void verifyChecked(SpecializeExpr *E) {
if (!E->getType()->is<FunctionType>()) {

View File

@@ -1210,11 +1210,13 @@ namespace {
// Cast the result of the alloc call to the (metatype) 'this'.
// FIXME: instancetype should make this unnecessary.
initExpr = new (Impl.SwiftContext) UncheckedDowncastExpr(
auto cast = new (Impl.SwiftContext) UnconditionalCheckedCastExpr(
initExpr,
SourceLoc(),
SourceLoc(),
TypeLoc::withoutLoc(thisTy));
cast->setCastKind(CheckedCastKind::Downcast);
initExpr = cast;
result->setAllocThisExpr(initExpr);
}
@@ -1281,11 +1283,13 @@ namespace {
// Cast the result of the alloc call to the (metatype) 'this'.
// FIXME: instancetype should make this unnecessary.
initExpr = new (Impl.SwiftContext) UncheckedDowncastExpr(
auto cast = new (Impl.SwiftContext) UnconditionalCheckedCastExpr(
initExpr,
SourceLoc(),
SourceLoc(),
TypeLoc::withoutLoc(thisTy));
cast->setCastKind(CheckedCastKind::Downcast);
initExpr = cast;
// Form the assignment statement.
auto refThis
@@ -2581,11 +2585,16 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc,
TypeLoc::withoutLoc(type));
break;
case ConstantConvertKind::Downcast:
expr = new (context) UncheckedDowncastExpr(expr, SourceLoc(), SourceLoc(),
TypeLoc::withoutLoc(type));
case ConstantConvertKind::Downcast: {
auto cast = new (context) UnconditionalCheckedCastExpr(expr,
SourceLoc(),
SourceLoc(),
TypeLoc::withoutLoc(type));
cast->setCastKind(CheckedCastKind::Downcast);
expr = cast;
break;
}
}
// Create the return statement.
auto ret = new (context) ReturnStmt(SourceLoc(), expr);

View File

@@ -20,6 +20,7 @@
#include "swift/AST/Pattern.h"
#include "swift/AST/Types.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/Basic/Optional.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
@@ -39,8 +40,8 @@ using namespace swift;
using namespace irgen;
/// Emit a checked unconditional downcast.
llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from,
SILType toType) {
llvm::Value *IRGenFunction::emitDowncast(llvm::Value *from, SILType toType,
CheckedCastMode mode) {
// Emit the value we're casting from.
if (from->getType() != IGM.Int8PtrTy)
from = Builder.CreateBitCast(from, IGM.Int8PtrTy);
@@ -50,16 +51,30 @@ llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from,
llvm::Value *metadataRef;
llvm::Constant *castFn;
if (isClass) {
// If the dest type is a concrete class, get the class metadata
// If the dest type is a concrete class, get the full class metadata
// and call dynamicCastClass directly.
metadataRef
= IGM.getAddrOfTypeMetadata(toType.getSwiftRValueType(), false, false);
castFn = IGM.getDynamicCastClassUnconditionalFn();
switch (mode) {
case CheckedCastMode::Unconditional:
castFn = IGM.getDynamicCastClassUnconditionalFn();
break;
case CheckedCastMode::Conditional:
castFn = IGM.getDynamicCastClassFn();
break;
}
} else {
// Otherwise, get the type metadata, which may be local, and go through
// the more general dynamicCast entry point.
metadataRef = emitTypeMetadataRef(toType);
castFn = IGM.getDynamicCastUnconditionalFn();
switch (mode) {
case CheckedCastMode::Unconditional:
castFn = IGM.getDynamicCastUnconditionalFn();
break;
case CheckedCastMode::Conditional:
castFn = IGM.getDynamicCastFn();
break;
}
}
if (metadataRef->getType() != IGM.Int8PtrTy)
@@ -76,7 +91,8 @@ llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from,
}
void IRGenFunction::emitFakeExplosion(const TypeInfo &type, Explosion &explosion) {
void IRGenFunction::emitFakeExplosion(const TypeInfo &type,
Explosion &explosion) {
ExplosionSchema schema(explosion.getKind());
type.getSchema(schema);
for (auto &element : schema) {

View File

@@ -17,6 +17,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/Types.h"
#include "swift/AST/Decl.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILType.h"
#include "llvm/IR/DerivedTypes.h"
@@ -684,7 +685,8 @@ void irgen::reemitAsSubstituted(IRGenFunction &IGF,
llvm::Value *
IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super,
SILType destType) {
SILType destType,
CheckedCastMode mode) {
assert(destType.is<ArchetypeType>() && "expected archetype type");
assert(destType.castTo<ArchetypeType>()->requiresClass()
&& "expected class archetype type");
@@ -698,9 +700,18 @@ IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super,
metadataRef = Builder.CreateBitCast(metadataRef, IGM.Int8PtrTy);
// Call the (unconditional) dynamic cast.
llvm::Value *castFn;
switch (mode) {
case CheckedCastMode::Unconditional:
castFn = IGM.getDynamicCastUnconditionalFn();
break;
case CheckedCastMode::Conditional:
castFn = IGM.getDynamicCastFn();
break;
}
auto call
= Builder.CreateCall2(IGM.getDynamicCastUnconditionalFn(),
super, metadataRef);
= Builder.CreateCall2(castFn, super, metadataRef);
// FIXME: Eventually, we may want to throw.
call->setDoesNotThrow();

View File

@@ -3897,10 +3897,11 @@ llvm::Value *irgen::emitClassExistentialProjection(IRGenFunction &IGF,
}
static Address
emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
Address value,
llvm::Value *srcMetadata,
SILType destType) {
emitOpaqueDowncast(IRGenFunction &IGF,
Address value,
llvm::Value *srcMetadata,
SILType destType,
CheckedCastMode mode) {
llvm::Value *addr = IGF.Builder.CreateBitCast(value.getAddress(),
IGF.IGM.OpaquePtrTy);
@@ -3908,9 +3909,17 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
llvm::Value *destMetadata = IGF.emitTypeMetadataRef(destType);
destMetadata = IGF.Builder.CreateBitCast(destMetadata, IGF.IGM.Int8PtrTy);
auto *call
= IGF.Builder.CreateCall3(IGF.IGM.getDynamicCastIndirectUnconditionalFn(),
addr, srcMetadata, destMetadata);
llvm::Value *castFn;
switch (mode) {
case CheckedCastMode::Unconditional:
castFn = IGF.IGM.getDynamicCastIndirectUnconditionalFn();
break;
case CheckedCastMode::Conditional:
castFn = IGF.IGM.getDynamicCastIndirectFn();
break;
}
auto *call = IGF.Builder.CreateCall3(castFn, addr, srcMetadata, destMetadata);
// FIXME: Eventually, we may want to throw.
call->setDoesNotThrow();
@@ -3921,24 +3930,26 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
return destTI.getAddressForPointer(ptr);
}
/// Emit a checked unconditional cast of an opaque archetype.
Address irgen::emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType) {
/// Emit a checked cast of an opaque archetype.
Address irgen::emitOpaqueArchetypeDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType,
CheckedCastMode mode) {
assert(srcType.is<ArchetypeType>());
assert(!srcType.castTo<ArchetypeType>()->requiresClass());
llvm::Value *srcMetadata = IGF.emitTypeMetadataRef(srcType);
return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType);
return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode);
}
/// Emit a checked unconditional cast of an opaque existential container's
/// contained value.
Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
Address container,
SILType srcType,
SILType destType) {
Address irgen::emitOpaqueExistentialDowncast(IRGenFunction &IGF,
Address container,
SILType srcType,
SILType destType,
CheckedCastMode mode) {
assert(srcType.isExistentialType());
assert(!srcType.isClassExistentialType());
@@ -3949,5 +3960,5 @@ Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
std::tie(value, srcMetadata)
= emitOpaqueExistentialProjectionWithMetadata(IGF, container, srcType);
return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType);
return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode);
}

View File

@@ -34,6 +34,7 @@ namespace swift {
class ProtocolConformance;
struct SILConstant;
class SILType;
enum class CheckedCastMode : unsigned char;
namespace irgen {
class AbstractCallee;
@@ -173,18 +174,20 @@ namespace irgen {
Explosion &value,
CanType type);
/// Emit a checked unconditional cast of an opaque archetype.
Address emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType);
/// Emit a checked cast of an opaque archetype.
Address emitOpaqueArchetypeDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType,
CheckedCastMode mode);
/// Emit a checked unconditional cast of an opaque existential container's
/// Emit a checked cast of an opaque existential container's
/// contained value.
Address emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType);
Address emitOpaqueExistentialDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType,
CheckedCastMode mode);
} // end namespace irgen
} // end namespace swift

View File

@@ -51,6 +51,7 @@ namespace swift {
class TranslationUnit;
class ValueDecl;
class VarDecl;
enum class CheckedCastMode : unsigned char;
namespace Mangle {
enum class ExplosionKind : unsigned;
@@ -181,12 +182,14 @@ public:
/// \brief Convert the given explosion to the given destination archetype,
/// using a runtime-checked cast.
llvm::Value *emitSuperToClassArchetypeConversion(llvm::Value *super,
SILType destType);
SILType destType,
CheckedCastMode mode);
/// \brief Convert the given value to the given destination type, using a
/// runtime-checked cast.
llvm::Value *emitUnconditionalDowncast(llvm::Value *from,
SILType toType);
llvm::Value *emitDowncast(llvm::Value *from,
SILType toType,
CheckedCastMode mode);
//--- Declaration emission -----------------------------------------------------

View File

@@ -1291,7 +1291,7 @@ void IRGenSILFunction::visitSuperToArchetypeRefInst(
llvm::Value *in = super.claimNext();
Explosion out(CurExplosionLevel);
llvm::Value *cast
= emitSuperToClassArchetypeConversion(in, i->getType());
= emitSuperToClassArchetypeConversion(in, i->getType(), i->getMode());
out.add(cast);
newLoweredExplosion(SILValue(i, 0), out);
}
@@ -1300,7 +1300,7 @@ void IRGenSILFunction::visitDowncastArchetypeRefInst(
swift::DowncastArchetypeRefInst *i) {
Explosion archetype = getLoweredExplosion(i->getOperand());
llvm::Value *fromValue = archetype.claimNext();
llvm::Value *toValue = emitUnconditionalDowncast(fromValue, i->getType());
llvm::Value *toValue = emitDowncast(fromValue, i->getType(), i->getMode());
Explosion to(archetype.getKind());
to.add(toValue);
newLoweredExplosion(SILValue(i,0), to);
@@ -1313,7 +1313,7 @@ void IRGenSILFunction::visitDowncastExistentialRefInst(
= emitClassExistentialProjection(*this, existential,
i->getOperand().getType());
llvm::Value *toValue = emitUnconditionalDowncast(instance, i->getType());
llvm::Value *toValue = emitDowncast(instance, i->getType(), i->getMode());
Explosion to(existential.getKind());
to.add(toValue);
newLoweredExplosion(SILValue(i,0), to);
@@ -1322,42 +1322,39 @@ void IRGenSILFunction::visitDowncastExistentialRefInst(
void IRGenSILFunction::visitDowncastArchetypeAddrInst(
swift::DowncastArchetypeAddrInst *i) {
Address archetype = getLoweredAddress(i->getOperand());
Address cast = emitUnconditionalOpaqueArchetypeDowncast(*this, archetype,
i->getOperand().getType(),
i->getType());
Address cast = emitOpaqueArchetypeDowncast(*this, archetype,
i->getOperand().getType(),
i->getType(),
i->getMode());
newLoweredAddress(SILValue(i,0), cast);
}
void IRGenSILFunction::visitProjectDowncastExistentialAddrInst(
swift::ProjectDowncastExistentialAddrInst *i) {
Address existential = getLoweredAddress(i->getOperand());
Address cast = emitUnconditionalOpaqueExistentialDowncast(*this, existential,
i->getOperand().getType(),
i->getType());
Address cast = emitOpaqueExistentialDowncast(*this, existential,
i->getOperand().getType(),
i->getType(),
i->getMode());
newLoweredAddress(SILValue(i,0), cast);
}
void IRGenSILFunction::visitIsaInst(swift::IsaInst *i) {
// Emit the value we're testing.
Explosion from = getLoweredExplosion(i->getOperand());
llvm::Value *fromValue = from.claimNext();
fromValue = Builder.CreateBitCast(fromValue, IGM.Int8PtrTy);
// Emit the metadata of the type we're testing against.
CanType toType = i->getTestType().getSwiftRValueType();
Explosion metadata(ExplosionKind::Minimal);
emitMetaTypeRef(*this, toType, metadata);
llvm::Value *metadataValue = metadata.claimNext();
metadataValue = Builder.CreateBitCast(metadataValue, IGM.Int8PtrTy);
// Perform a checked cast.
auto call = Builder.CreateCall2(IGM.getDynamicCastClassFn(),
fromValue, metadataValue);
call->setDoesNotThrow();
void IRGenSILFunction::visitIsNonnullInst(swift::IsNonnullInst *i) {
// Get the value we're testing, which may be an address or an instance
// pointer.
llvm::Value *val;
LoweredValue const &lv = getLoweredValue(i->getOperand());
if (lv.isAddress()) {
val = lv.getAddress().getAddress();
} else {
Explosion values = lv.getExplosion(*this);
val = values.claimNext();
}
// Check that the result isn't null.
auto *valTy = cast<llvm::PointerType>(val->getType());
llvm::Value *result = Builder.CreateICmp(llvm::CmpInst::ICMP_NE,
call, llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
val, llvm::ConstantPointerNull::get(valTy));
Explosion out(CurExplosionLevel);
out.add(result);
@@ -1383,9 +1380,7 @@ void IRGenSILFunction::visitDowncastInst(swift::DowncastInst *i) {
Explosion from = getLoweredExplosion(i->getOperand());
Explosion to(from.getKind());
llvm::Value *fromValue = from.claimNext();
llvm::Value *castValue = emitUnconditionalDowncast(
fromValue,
i->getType());
llvm::Value *castValue = emitDowncast(fromValue, i->getType(), i->getMode());
to.add(castValue);
newLoweredExplosion(SILValue(i, 0), to);
}

View File

@@ -539,7 +539,7 @@ public:
void visitProjectDowncastExistentialAddrInst(
ProjectDowncastExistentialAddrInst *i);
void visitIsaInst(IsaInst *i);
void visitIsNonnullInst(IsNonnullInst *i);
void visitIndexAddrInst(IndexAddrInst *i);
void visitIndexRawPointerInst(IndexRawPointerInst *i);

View File

@@ -92,8 +92,8 @@ static bool isExprPostfix(Expr *expr) {
case ExprKind::PostfixUnary:
case ExprKind::PrefixUnary:
case ExprKind::Sequence:
case ExprKind::IsSubtype:
case ExprKind::UncheckedDowncast:
case ExprKind::Isa:
case ExprKind::UnconditionalCheckedCast:
case ExprKind::Assign:
return false;
@@ -156,11 +156,6 @@ static bool isExprPostfix(Expr *expr) {
case ExprKind::Specialize:
case ExprKind::TupleElement:
case ExprKind::TupleShuffle:
case ExprKind::UncheckedSuperToArchetype:
case ExprKind::UncheckedArchetypeToArchetype:
case ExprKind::UncheckedArchetypeToConcrete:
case ExprKind::UncheckedExistentialToArchetype:
case ExprKind::UncheckedExistentialToConcrete:
case ExprKind::ZeroValue:
llvm_unreachable("Not a parsed expression");
@@ -256,7 +251,7 @@ NullablePtr<Expr> Parser::parseExprIs() {
if (parseType(type, diag::expected_type_after_is))
return nullptr;
return new (Context) IsSubtypeExpr(isLoc, type);
return new (Context) IsaExpr(isLoc, type);
}
/// parseExprAs
@@ -276,7 +271,7 @@ NullablePtr<Expr> Parser::parseExprAs() {
return nullptr;
return bangLoc.isValid()
? (Expr*) new (Context) UncheckedDowncastExpr(asLoc, bangLoc, type)
? (Expr*) new (Context) UnconditionalCheckedCastExpr(asLoc, bangLoc, type)
: (Expr*) new (Context) CoerceExpr(asLoc, type);
}

View File

@@ -531,18 +531,9 @@ public:
SGFContext C);
RValue visitErasureExpr(ErasureExpr *E, SGFContext C);
RValue visitCoerceExpr(CoerceExpr *E, SGFContext C);
RValue visitUncheckedDowncastExpr(UncheckedDowncastExpr *E, SGFContext C);
RValue visitUncheckedSuperToArchetypeExpr(
UncheckedSuperToArchetypeExpr *E, SGFContext C);
RValue visitUncheckedArchetypeToArchetypeExpr(
UncheckedArchetypeToArchetypeExpr *E, SGFContext C);
RValue visitUncheckedArchetypeToConcreteExpr(
UncheckedArchetypeToConcreteExpr *E, SGFContext C);
RValue visitUncheckedExistentialToArchetypeExpr(
UncheckedExistentialToArchetypeExpr *E, SGFContext C);
RValue visitUncheckedExistentialToConcreteExpr(
UncheckedExistentialToConcreteExpr *E, SGFContext C);
RValue visitIsSubtypeExpr(IsSubtypeExpr *E, SGFContext C);
RValue visitUnconditionalCheckedCastExpr(
UnconditionalCheckedCastExpr *E, SGFContext C);
RValue visitIsaExpr(IsaExpr *E, SGFContext C);
RValue visitParenExpr(ParenExpr *E, SGFContext C);
RValue visitTupleExpr(TupleExpr *E, SGFContext C);
RValue visitScalarToTupleExpr(ScalarToTupleExpr *E, SGFContext C);

View File

@@ -486,58 +486,6 @@ RValue SILGenFunction::visitCoerceExpr(CoerceExpr *E, SGFContext C) {
return visit(E->getSubExpr(), C);
}
RValue SILGenFunction::visitUncheckedDowncastExpr(UncheckedDowncastExpr *E,
SGFContext C) {
ManagedValue original = visit(E->getSubExpr()).getAsSingleValue(*this);
SILValue converted = B.createDowncast(E, original.getValue(),
getLoweredLoadableType(E->getType()));
return RValue(*this, ManagedValue(converted, original.getCleanup()));
}
RValue SILGenFunction::visitUncheckedSuperToArchetypeExpr(
UncheckedSuperToArchetypeExpr *E,
SGFContext C) {
ManagedValue base = visit(E->getSubExpr()).getAsSingleValue(*this);
// Initialize it with a SuperToArchetypeInst.
SILValue archetype = B.createSuperToArchetypeRef(E, base.getValue(),
getLoweredLoadableType(E->getType()));
// Keep the base-class-typed cleanup so we use a concrete release.
return RValue(*this, ManagedValue(archetype, base.getCleanup()));
}
static RValue emitArchetypeDowncast(SILGenFunction &gen,
ExplicitCastExpr *E, SGFContext C) {
ManagedValue base = gen.visit(E->getSubExpr()).getAsSingleValue(gen);
// Cast to the concrete type and replace the cleanup with a new one on the
// concrete value, which should be more specific and more efficient than the
// one on the original archetype.
SILValue cast;
if (E->getSubExpr()->getType()->castTo<ArchetypeType>()->requiresClass()) {
cast = gen.B.createDowncastArchetypeRef(E, base.forward(gen),
gen.getLoweredLoadableType(E->getType()));
} else {
SILType castTy = gen.getLoweredType(E->getType());
cast = gen.B.createDowncastArchetypeAddr(E, base.forward(gen),
castTy.getAddressType());
if (castTy.isLoadable(gen.F.getModule()))
cast = gen.B.createLoad(E, cast);
}
return RValue(gen, gen.emitManagedRValueWithCleanup(cast));
}
RValue SILGenFunction::visitUncheckedArchetypeToArchetypeExpr(
UncheckedArchetypeToArchetypeExpr *E,
SGFContext C) {
return emitArchetypeDowncast(*this, E, C);
}
RValue SILGenFunction::visitUncheckedArchetypeToConcreteExpr(
UncheckedArchetypeToConcreteExpr *E,
SGFContext C) {
return emitArchetypeDowncast(*this, E, C);
}
namespace {
class CleanupUsedExistentialContainer : public Cleanup {
SILValue existential;
@@ -551,50 +499,94 @@ namespace {
};
}
static RValue emitExistentialDowncast(SILGenFunction &gen,
ExplicitCastExpr *E, SGFContext C) {
ManagedValue base = gen.visit(E->getSubExpr()).getAsSingleValue(gen);
/// \brief Emit the cast instruction appropriate to the kind of checked cast.
///
/// \param gen The SILGenFunction.
/// \param E The CheckedCastExpr to emit.
/// \param mode Whether to emit an unconditional or conditional cast.
/// \param useCastValue If true, the cleanup on the original value will be
/// disabled, and the callee will be expected to take
/// ownership of the returned value. If false, the original
/// value's cleanup is left intact, and an unowned reference
/// or address is returned.
static SILValue emitCheckedCast(SILGenFunction &gen,
CheckedCastExpr *E,
CheckedCastMode mode,
bool useCastValue) {
ManagedValue originalMV = gen.visit(E->getSubExpr()).getAsSingleValue(gen);
SILValue original = useCastValue
? originalMV.forward(gen)
: originalMV.getValue();
SILValue cast;
if (E->getSubExpr()->getType()->isClassExistentialType()) {
// Cast to the concrete type and replace the cleanup with a new one on the
// archetype, which may be more specific.
cast = gen.B.createDowncastExistentialRef(E, base.forward(gen),
gen.getLoweredLoadableType(E->getType()));
} else {
// Project the concrete value address out of the container.
SILType castTy = gen.getLoweredType(E->getType());
cast = gen.B.createProjectDowncastExistentialAddr(E, base.forward(gen),
castTy.getAddressType());
if (castTy.isLoadable(gen.F.getModule()))
cast = gen.B.createLoad(E, cast);
// We'll pass on ownership of the contained value, but we still need to
// deallocate the existential buffer when we're done.
gen.Cleanups.pushCleanup<CleanupUsedExistentialContainer>(base.getValue());
Type castTy = E->getCastTypeLoc().getType();
switch (E->getCastKind()) {
case CheckedCastKind::Unresolved:
case CheckedCastKind::InvalidCoercible:
llvm_unreachable("invalid checked cast?!");
case CheckedCastKind::Downcast:
return gen.B.createDowncast(E, original,
gen.getLoweredLoadableType(castTy), mode);
case CheckedCastKind::SuperToArchetype:
return gen.B.createSuperToArchetypeRef(E, original,
gen.getLoweredLoadableType(castTy), mode);
case CheckedCastKind::ArchetypeToArchetype:
case CheckedCastKind::ArchetypeToConcrete:
if (E->getSubExpr()->getType()->castTo<ArchetypeType>()->requiresClass()) {
return gen.B.createDowncastArchetypeRef(E, original,
gen.getLoweredLoadableType(castTy), mode);
} else {
SILType loweredTy = gen.getLoweredType(castTy);
SILValue cast = gen.B.createDowncastArchetypeAddr(E, original,
loweredTy.getAddressType(), mode);
if (useCastValue && loweredTy.isLoadable(gen.F.getModule()))
cast = gen.B.createLoad(E, cast);
return cast;
}
case CheckedCastKind::ExistentialToArchetype:
case CheckedCastKind::ExistentialToConcrete:
if (E->getSubExpr()->getType()->isClassExistentialType()) {
return gen.B.createDowncastExistentialRef(E, original,
gen.getLoweredLoadableType(castTy), mode);
} else {
// Project the concrete value address out of the container.
SILType loweredTy = gen.getLoweredType(castTy);
SILValue cast = gen.B.createProjectDowncastExistentialAddr(E, original,
loweredTy.getAddressType(), mode);
if (useCastValue) {
if (loweredTy.isLoadable(gen.F.getModule()))
cast = gen.B.createLoad(E, cast);
// We'll pass on ownership of the contained value, but we still need to
// deallocate the existential buffer when we're done.
gen.Cleanups.pushCleanup<CleanupUsedExistentialContainer>(original);
}
return cast;
}
}
return RValue(gen, gen.emitManagedRValueWithCleanup(cast));
}
RValue SILGenFunction::visitUncheckedExistentialToArchetypeExpr(
UncheckedExistentialToArchetypeExpr *E,
SGFContext C) {
return emitExistentialDowncast(*this, E, C);
RValue SILGenFunction::visitUnconditionalCheckedCastExpr(
UnconditionalCheckedCastExpr *E,
SGFContext C) {
// Disable the original cleanup because the cast-to type is more specific and
// should have a more efficient cleanup.
SILValue cast = emitCheckedCast(*this, E, CheckedCastMode::Unconditional,
/*useCastValue*/ true);
return RValue(*this, emitManagedRValueWithCleanup(cast));
}
RValue SILGenFunction::visitUncheckedExistentialToConcreteExpr(
UncheckedExistentialToConcreteExpr *E,
SGFContext C) {
return emitExistentialDowncast(*this, E, C);
}
RValue SILGenFunction::visitIsSubtypeExpr(IsSubtypeExpr *E, SGFContext C)
{
ManagedValue base = visit(E->getSubExpr()).getAsSingleValue(*this);
SILValue res = B.createIsa(E, base.getValue(),
getLoweredType(E->getTypeLoc().getType()),
getLoweredLoadableType(E->getType()));
return RValue(*this, emitManagedRValueWithCleanup(res));
RValue SILGenFunction::visitIsaExpr(IsaExpr *E, SGFContext C) {
// Cast the value using a conditional cast.
SILValue cast = emitCheckedCast(*this, E, CheckedCastMode::Conditional,
/*useCastValue*/ false);
// Check the result.
SILValue is = B.createIsNonnull(E, cast,
getLoweredLoadableType(E->getType()));
return RValue(*this, emitManagedRValueWithCleanup(is));
}
RValue SILGenFunction::visitParenExpr(ParenExpr *E, SGFContext C) {
@@ -1805,7 +1797,8 @@ RValue SILGenFunction::visitRebindThisInConstructorExpr(
"delegating ctor type mismatch for non-reference type?!");
CleanupsDepth newThisCleanup = newThis.getCleanup();
SILValue newThisValue = B.createDowncast(E, newThis.getValue(),
getLoweredLoadableType(E->getThis()->getType()));
getLoweredLoadableType(E->getThis()->getType()),
CheckedCastMode::Unconditional);
newThis = ManagedValue(newThisValue, newThisCleanup);
}

View File

@@ -370,6 +370,21 @@ public:
llvm::StringRef name) {
OS << name << " " << getID(operand) << ", " << CI->getType();
}
void printConversionInst(CheckedConversionInst *CI,
SILValue operand,
llvm::StringRef name) {
OS << name;
switch (CI->getMode()) {
case CheckedCastMode::Conditional:
OS << " conditional ";
break;
case CheckedCastMode::Unconditional:
OS << " unconditional ";
break;
}
OS << getID(operand) << ", " << CI->getType();
}
void visitConvertFunctionInst(ConvertFunctionInst *CI) {
printConversionInst(CI, CI->getOperand(), "convert_function");
@@ -429,8 +444,8 @@ public:
printConversionInst(CI, CI->getOperand(), "downcast_existential_ref");
}
void visitIsaInst(IsaInst *I) {
OS << "isa " << getID(I->getOperand()) << ", " << I->getTestType();
void visitIsNonnullInst(IsNonnullInst *I) {
OS << "is_nonnull " << getIDAndType(I->getOperand());
}
void visitStructInst(StructInst *SI) {

View File

@@ -894,19 +894,11 @@ public:
"downcast must convert to a class type");
}
void checkIsaInst(IsaInst *II) {
void checkIsNonnullInst(IsNonnullInst *II) {
require(II->getOperand().getType().getSwiftType()
->getClassOrBoundGenericClass(),
"isa operand must be a class type");
CanType testTy = II->getTestType().getSwiftRValueType();
if (auto *archetype = dyn_cast<ArchetypeType>(testTy))
require((bool)archetype->getSuperclass(),
"isa must test against a class type or base-class-constrained "
"archetype");
else
require(testTy->getClassOrBoundGenericClass(),
"isa must test against a class type or base-class-constrained "
"archetype");
->mayHaveSuperclass()
|| II->getOperand().getType().isAddress(),
"isa operand must be a class type or address");
}
void checkAddressToPointerInst(AddressToPointerInst *AI) {

View File

@@ -2891,13 +2891,7 @@ namespace {
// Type check the type parameters in cast expressions.
if (auto cast = dyn_cast<ExplicitCastExpr>(expr)) {
if (TC.validateType(cast->getTypeLoc()))
return nullptr;
return expr;
}
if (auto is = dyn_cast<IsSubtypeExpr>(expr)) {
if (TC.validateType(is->getTypeLoc()))
if (TC.validateType(cast->getCastTypeLoc()))
return nullptr;
return expr;
}

View File

@@ -1457,25 +1457,22 @@ namespace {
expr->setSubExpr(subExpr);
return expr;
}
Expr *visitUncheckedDowncastExpr(UncheckedDowncastExpr *expr) {
/// Type-check a checked cast expression.
CheckedCastKind checkCheckedCastExpr(CheckedCastExpr *expr) {
auto &tc = cs.getTypeChecker();
auto &C = cs.getASTContext();
// Simplify the type we're converting to.
Type toType = simplifyType(expr->getType());
expr->setType(toType);
Type toType = expr->getCastTypeLoc().getType();
// Type-check the subexpression in isolation.
Expr *sub = expr->getSubExpr();
if (tc.typeCheckExpression(sub, cs.DC)) {
// FIXME: Mark as error.
return nullptr;
return CheckedCastKind::Unresolved;
}
sub = tc.coerceToRValue(sub);
if (!sub) {
// FIXME: Mark as error.
return nullptr;
return CheckedCastKind::Unresolved;
}
expr->setSubExpr(sub);
@@ -1488,24 +1485,9 @@ namespace {
// If the from/to types are equivalent or implicitly convertible,
// this should have been a coercion expression (b as A) rather than a
// cast (a as! B). Complain.
// checked cast (a as! B). Complain.
if (fromType->isEqual(toType) || tc.isConvertibleTo(fromType, toType)) {
// Only complain if the cast was explicitly generated.
// FIXME: This leniency is here for the Clang module importer,
// which doesn't necessarily know whether it needs to force the
// cast or not. instancetype should eliminate the need for it.
if (!expr->isImplicit()) {
tc.diagnose(expr->getLoc(), diag::downcast_to_supertype,
origFromType, toType)
.highlight(sub->getSourceRange())
.highlight(expr->getTypeLoc().getSourceRange())
.fixItRemove(SourceRange(expr->getBangLoc()));
}
Expr *coerce = new (C) CoerceExpr(sub, expr->getLoc(),
expr->getTypeLoc());
coerce->setType(expr->getType());
return coerce;
return CheckedCastKind::InvalidCoercible;
}
// We can't downcast to an existential.
@@ -1513,45 +1495,31 @@ namespace {
tc.diagnose(expr->getLoc(), diag::downcast_to_existential,
origFromType, toType)
.highlight(sub->getSourceRange())
.highlight(expr->getTypeLoc().getSourceRange());
return nullptr;
.highlight(expr->getCastTypeLoc().getSourceRange());
return CheckedCastKind::Unresolved;
}
// A downcast can:
// - convert an archetype to a (different) archetype type.
if (fromArchetype && toArchetype) {
auto *atoa = new (C) UncheckedArchetypeToArchetypeExpr(sub,
expr->getLoc(),
expr->getBangLoc(),
expr->getTypeLoc());
atoa->setType(expr->getType());
return atoa;
return CheckedCastKind::ArchetypeToArchetype;
}
// - convert from an existential to an archetype or conforming concrete
// type.
if (fromExistential) {
Expr *etox;
if (toArchetype) {
etox = new (C) UncheckedExistentialToArchetypeExpr(sub,
expr->getLoc(),
expr->getBangLoc(),
expr->getTypeLoc());
return CheckedCastKind::ExistentialToArchetype;
} else if (tc.isConvertibleTo(toType, fromType)) {
etox = new (C) UncheckedExistentialToConcreteExpr(sub,
expr->getLoc(),
expr->getBangLoc(),
expr->getTypeLoc());
return CheckedCastKind::ExistentialToConcrete;
} else {
tc.diagnose(expr->getLoc(),
diag::downcast_from_existential_to_unrelated,
origFromType, toType)
.highlight(sub->getSourceRange())
.highlight(expr->getTypeLoc().getSourceRange());
return nullptr;
.highlight(expr->getCastTypeLoc().getSourceRange());
return CheckedCastKind::Unresolved;
}
etox->setType(expr->getType());
return etox;
}
// - convert an archetype to a concrete type fulfilling its constraints.
@@ -1561,15 +1529,10 @@ namespace {
diag::downcast_from_archetype_to_unrelated,
origFromType, toType)
.highlight(sub->getSourceRange())
.highlight(expr->getTypeLoc().getSourceRange());
return nullptr;
.highlight(expr->getCastTypeLoc().getSourceRange());
return CheckedCastKind::Unresolved;
}
auto *atoc = new (C) UncheckedArchetypeToConcreteExpr(sub,
expr->getLoc(),
expr->getBangLoc(),
expr->getTypeLoc());
atoc->setType(expr->getType());
return atoc;
return CheckedCastKind::ArchetypeToConcrete;
}
// - convert from a superclass to an archetype.
@@ -1578,17 +1541,13 @@ namespace {
// Coerce to the supertype of the archetype.
if (tc.convertToType(sub, toSuperType, cs.DC))
return nullptr;
return CheckedCastKind::Unresolved;
// Construct the supertype-to-archetype cast.
auto *stoa = new (C) UncheckedSuperToArchetypeExpr(sub,
expr->getLoc(),
expr->getBangLoc(),
expr->getTypeLoc());
stoa->setType(expr->getType());
return stoa;
return CheckedCastKind::SuperToArchetype;
}
// The remaining case is a class downcast.
assert(!fromArchetype && "archetypes should have been handled above");
assert(!toArchetype && "archetypes should have been handled above");
assert(!fromExistential && "existentials should have been handled above");
@@ -1599,43 +1558,81 @@ namespace {
tc.diagnose(expr->getLoc(), diag::downcast_to_unrelated,
origFromType, toType)
.highlight(sub->getSourceRange())
.highlight(expr->getTypeLoc().getSourceRange());
return nullptr;
.highlight(expr->getCastTypeLoc().getSourceRange());
return CheckedCastKind::Unresolved;
}
// Okay, we're done.
return CheckedCastKind::Downcast;
}
Expr *visitIsaExpr(IsaExpr *expr) {
CheckedCastKind castKind = checkCheckedCastExpr(expr);
switch (castKind) {
// Invalid type check.
case CheckedCastKind::Unresolved:
return nullptr;
// Check is trivially true.
case CheckedCastKind::InvalidCoercible:
cs.getTypeChecker().diagnose(expr->getLoc(), diag::isa_is_always_true,
expr->getSubExpr()->getType(),
expr->getCastTypeLoc().getType());
break;
// Valid checks.
case CheckedCastKind::Downcast:
case CheckedCastKind::SuperToArchetype:
case CheckedCastKind::ArchetypeToArchetype:
case CheckedCastKind::ArchetypeToConcrete:
case CheckedCastKind::ExistentialToArchetype:
case CheckedCastKind::ExistentialToConcrete:
expr->setCastKind(castKind);
break;
}
return expr;
}
Expr *visitUncheckedSuperToArchetypeExpr(
UncheckedSuperToArchetypeExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitUncheckedArchetypeToArchetypeExpr(
UncheckedArchetypeToArchetypeExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitUncheckedArchetypeToConcreteExpr(
UncheckedArchetypeToConcreteExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitUncheckedExistentialToArchetypeExpr(
UncheckedExistentialToArchetypeExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitUncheckedExistentialToConcreteExpr(
UncheckedExistentialToConcreteExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitIsSubtypeExpr(IsSubtypeExpr *expr) {
expr->setType(simplifyType(expr->getType()));
auto &tc = cs.getTypeChecker();
Expr *sub = tc.coerceToRValue(expr->getSubExpr());
if (!sub) return nullptr;
expr->setSubExpr(sub);
Expr *visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *expr){
Type toType = expr->getCastTypeLoc().getType();
expr->setType(toType);
CheckedCastKind castKind = checkCheckedCastExpr(expr);
switch (castKind) {
/// Invalid cast.
case CheckedCastKind::Unresolved:
return nullptr;
/// Cast trivially succeeds. Emit a fixit and reduce to a coercion.
case CheckedCastKind::InvalidCoercible: {
// Only complain if the cast was explicitly generated.
// FIXME: This leniency is here for the Clang module importer,
// which doesn't necessarily know whether it needs to force the
// cast or not. instancetype should eliminate the need for it.
if (!expr->isImplicit()) {
cs.getTypeChecker().diagnose(expr->getLoc(),
diag::downcast_to_supertype,
expr->getSubExpr()->getType(),
expr->getCastTypeLoc().getType())
.highlight(expr->getSubExpr()->getSourceRange())
.highlight(expr->getCastTypeLoc().getSourceRange())
.fixItRemove(SourceRange(expr->getBangLoc()));
}
Expr *coerce = new (cs.getASTContext()) CoerceExpr(expr->getSubExpr(),
expr->getLoc(),
expr->getCastTypeLoc());
coerce->setType(expr->getType());
return coerce;
}
// Valid casts.
case CheckedCastKind::Downcast:
case CheckedCastKind::SuperToArchetype:
case CheckedCastKind::ArchetypeToArchetype:
case CheckedCastKind::ArchetypeToConcrete:
case CheckedCastKind::ExistentialToArchetype:
case CheckedCastKind::ExistentialToConcrete:
expr->setCastKind(castKind);
break;
}
return expr;
}
@@ -2498,10 +2495,10 @@ Expr *ConstraintSystem::applySolution(const Solution &solution,
return { false, expr };
}
// For unchecked downcast expressions, the subexpression is checked
// For checked cast expressions, the subexpression is checked
// separately.
if (auto unchecked = dyn_cast<UncheckedDowncastExpr>(expr)) {
return { false, Rewriter.visitUncheckedDowncastExpr(unchecked) };
if (auto unchecked = dyn_cast<CheckedCastExpr>(expr)) {
return { false, Rewriter.visit(unchecked) };
}
// For a default-value expression, do nothing.

View File

@@ -856,67 +856,21 @@ namespace {
Type visitCoerceExpr(CoerceExpr *expr) {
// FIXME: Could split the system here.
Type ty = expr->getTypeLoc().getType();
Type ty = expr->getCastTypeLoc().getType();
CS.addConstraint(ConstraintKind::Conversion,
expr->getSubExpr()->getType(), ty,
CS.getConstraintLocator(expr, { }));
return ty;
}
Type visitUncheckedDowncastExpr(UncheckedDowncastExpr *expr) {
Type visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *expr) {
// FIXME: Open this type.
return expr->getTypeLoc().getType();
return expr->getCastTypeLoc().getType();
}
Type visitUncheckedSuperToArchetypeExpr(
UncheckedSuperToArchetypeExpr *expr) {
llvm_unreachable("Already type-checked");
}
Type visitUncheckedArchetypeToArchetypeExpr(
UncheckedArchetypeToArchetypeExpr *expr) {
llvm_unreachable("Already type-checked");
}
Type visitUncheckedArchetypeToConcreteExpr(
UncheckedArchetypeToConcreteExpr *expr) {
llvm_unreachable("Already type-checked");
}
Type visitUncheckedExistentialToArchetypeExpr(
UncheckedExistentialToArchetypeExpr *expr) {
llvm_unreachable("Already type-checked");
}
Type visitUncheckedExistentialToConcreteExpr(
UncheckedExistentialToConcreteExpr *expr) {
llvm_unreachable("Already type-checked");
}
Type visitIsSubtypeExpr(IsSubtypeExpr *expr) {
ASTContext &C = CS.getASTContext();
// The subexpression must be castable to the destination type.
auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }));
CS.addConstraint(ConstraintKind::EqualRvalue, tv,
expr->getSubExpr()->getType(),
CS.getConstraintLocator(expr, ConstraintLocator::RvalueAdjustment));
CS.addConstraint(ConstraintKind::Subtype,
expr->getTypeLoc().getType(), tv);
Type visitIsaExpr(IsaExpr *expr) {
// The result is Bool.
auto &tc = CS.getTypeChecker();
UnqualifiedLookup boolLookup(C.getIdentifier("Bool"),
&tc.TU);
if (!boolLookup.isSuccess()) {
tc.diagnose(expr->getLoc(), diag::bool_type_broken);
return nullptr;
}
TypeDecl *tyDecl = boolLookup.getSingleTypeResult();
if (!tyDecl) {
tc.diagnose(expr->getLoc(), diag::bool_type_broken);
return nullptr;
}
return tyDecl->getDeclaredType();
return CS.getTypeChecker().lookupBoolType();
}
Type visitAssignExpr(AssignExpr *expr) {
@@ -1036,10 +990,10 @@ namespace {
return { false, expr };
}
// For unchecked downcast expressions, we visit the subexpression
// For checked cast expressions, we visit the subexpression
// separately.
if (auto unchecked = dyn_cast<UncheckedDowncastExpr>(expr)) {
auto type = CG.visitUncheckedDowncastExpr(unchecked);
if (auto unchecked = dyn_cast<CheckedCastExpr>(expr)) {
auto type = CG.visit(unchecked);
expr->setType(type);
return { false, expr };
}

View File

@@ -146,12 +146,8 @@ static InfixData getInfixData(TypeChecker &TC, Expr *E) {
// Assignment has fixed precedence.
assert(!assign->isFolded() && "already folded assign expr in sequence?!");
return InfixData(90, Associativity::Right);
} else if (auto *is = dyn_cast<IsSubtypeExpr>(E)) {
// 'is' has fixed precedence.
assert(!is->isFolded() && "already folded 'is' expr in sequence?!");
return InfixData(95, Associativity::None);
} else if (auto *as = dyn_cast<ExplicitCastExpr>(E)) {
// 'as' casts have fixed precedence.
// 'as' and 'is' casts have fixed precedence.
assert(!as->isFolded() && "already folded 'as' expr in sequence?!");
return InfixData(95, Associativity::None);
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
@@ -198,16 +194,8 @@ static Expr *makeBinOp(TypeChecker &TC, Expr *Op, Expr *LHS, Expr *RHS) {
return assign;
}
if (auto *is = dyn_cast<IsSubtypeExpr>(Op)) {
// Resolve the 'is' expression.
assert(!is->isFolded() && "already folded 'is' expr in sequence?!");
assert(RHS == is && "'is' with non-type RHS?!");
is->setSubExpr(LHS);
return is;
}
if (auto *as = dyn_cast<ExplicitCastExpr>(Op)) {
// Resolve the 'as' expression.
// Resolve the 'as' or 'is' expression.
assert(!as->isFolded() && "already folded 'as' expr in sequence?!");
assert(RHS == as && "'as' with non-type RHS?!");
as->setSubExpr(LHS);

View File

@@ -187,6 +187,24 @@ ProtocolDecl *TypeChecker::getLiteralProtocol(Expr *expr) {
llvm_unreachable("Unhandled literal kind");
}
Type TypeChecker::lookupBoolType() {
return boolType.cache([&]{
UnqualifiedLookup boolLookup(Context.getIdentifier("Bool"), &TU);
if (!boolLookup.isSuccess()) {
diagnose(SourceLoc(), diag::bool_type_broken);
return Type();
}
TypeDecl *tyDecl = boolLookup.getSingleTypeResult();
if (!tyDecl) {
diagnose(SourceLoc(), diag::bool_type_broken);
return Type();
}
return tyDecl->getDeclaredType();
});
}
/// \brief Check for circular inheritance of protocols.
///
/// \param Path The circular path through the protocol inheritance hierarchy,

View File

@@ -267,6 +267,8 @@ private:
/// implicitly defined.
llvm::DenseSet<StructDecl *> structsNeedingImplicitDefaultConstructor;
Optional<Type> boolType;
public:
/// \brief Determine whether the given type can be default-initialized.
///
@@ -449,6 +451,9 @@ public:
/// \returns true if any members were found, false otherwise.
bool lookupConstructors(Type type,SmallVectorImpl<ValueDecl *> &constructors);
/// \brief Look up the Bool type in the standard library.
Type lookupBoolType();
/// @}
/// \name Overload resolution