mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -964,6 +964,9 @@ ERROR(cannot_construct_type,sema_tcc,none,
|
|||||||
ERROR(downcast_to_supertype,sema_tcc,none,
|
ERROR(downcast_to_supertype,sema_tcc,none,
|
||||||
"downcast from %0 to supertype %1 is a coercion; remove the '!'",
|
"downcast from %0 to supertype %1 is a coercion; remove the '!'",
|
||||||
(Type, Type))
|
(Type, Type))
|
||||||
|
ERROR(isa_is_always_true,sema_tcc,none,
|
||||||
|
"'is' test is always true",
|
||||||
|
(Type, Type))
|
||||||
ERROR(downcast_to_unrelated,sema_tcc,none,
|
ERROR(downcast_to_unrelated,sema_tcc,none,
|
||||||
"downcast from %0 to unrelated type %1", (Type, Type))
|
"downcast from %0 to unrelated type %1", (Type, Type))
|
||||||
ERROR(downcast_to_existential,sema_tcc,none,
|
ERROR(downcast_to_existential,sema_tcc,none,
|
||||||
|
|||||||
@@ -2142,23 +2142,30 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Represents an explicit cast, 'a as T', 'a as? T', or 'a as! T',
|
/// \brief Represents an explicit cast, 'a as T', 'a as? T', 'a as! T', or
|
||||||
/// where "T" is a type, and "a" is the expression that will be converted to
|
/// 'a is T', where "T" is a type, and "a" is the expression that will be
|
||||||
/// the type.
|
/// converted to the type.
|
||||||
class ExplicitCastExpr : public Expr {
|
class ExplicitCastExpr : public Expr {
|
||||||
Expr *SubExpr;
|
Expr *SubExpr;
|
||||||
SourceLoc AsLoc;
|
SourceLoc AsLoc;
|
||||||
TypeLoc Ty;
|
TypeLoc CastTy;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeLoc type)
|
ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeLoc castTy,
|
||||||
: Expr(kind, type.getType()), SubExpr(sub), AsLoc(AsLoc), Ty(type)
|
Type resultTy)
|
||||||
|
: Expr(kind), SubExpr(sub), AsLoc(AsLoc), CastTy(castTy)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Expr *getSubExpr() const { return SubExpr; }
|
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; }
|
void setSubExpr(Expr *E) { SubExpr = E; }
|
||||||
|
|
||||||
@@ -2166,8 +2173,8 @@ public:
|
|||||||
|
|
||||||
SourceRange getSourceRange() const {
|
SourceRange getSourceRange() const {
|
||||||
return SubExpr
|
return SubExpr
|
||||||
? SourceRange{SubExpr->getStartLoc(), Ty.getSourceRange().End}
|
? SourceRange{SubExpr->getStartLoc(), CastTy.getSourceRange().End}
|
||||||
: SourceRange{AsLoc, Ty.getSourceRange().End};
|
: SourceRange{AsLoc, CastTy.getSourceRange().End};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if the node has been processed by SequenceExpr folding.
|
/// True if the node has been processed by SequenceExpr folding.
|
||||||
@@ -2188,7 +2195,8 @@ public:
|
|||||||
class CoerceExpr : public ExplicitCastExpr {
|
class CoerceExpr : public ExplicitCastExpr {
|
||||||
public:
|
public:
|
||||||
CoerceExpr(Expr *sub, SourceLoc asLoc, TypeLoc type)
|
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(SourceLoc asLoc, TypeLoc type)
|
||||||
: CoerceExpr(nullptr, asLoc, type)
|
: CoerceExpr(nullptr, asLoc, type)
|
||||||
@@ -2199,168 +2207,102 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Represents an explicit unchecked downcast, converting from a
|
/// Discriminates the different kinds of checked cast supported.
|
||||||
/// supertype to its subtype or crashing if the cast is not possible,
|
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 unconditional checked cast, which converts
|
||||||
|
/// from a type to some subtype or aborts if the cast is not possible,
|
||||||
/// spelled 'a as! T'.
|
/// spelled 'a as! T'.
|
||||||
///
|
///
|
||||||
/// FIXME: At present, only class downcasting is supported.
|
/// FIXME: All downcasts are currently unconditional, which is horrible.
|
||||||
/// FIXME: All downcasts are currently unchecked, which is horrible.
|
class UnconditionalCheckedCastExpr : public CheckedCastExpr {
|
||||||
class UncheckedDowncastExpr : public ExplicitCastExpr {
|
|
||||||
SourceLoc BangLoc;
|
SourceLoc BangLoc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UncheckedDowncastExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
|
UnconditionalCheckedCastExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc,
|
||||||
TypeLoc type)
|
TypeLoc type)
|
||||||
: ExplicitCastExpr(ExprKind::UncheckedDowncast, sub, asLoc, type),
|
: CheckedCastExpr(ExprKind::UnconditionalCheckedCast,
|
||||||
|
sub, asLoc, type, type.getType()),
|
||||||
BangLoc(bangLoc) { }
|
BangLoc(bangLoc) { }
|
||||||
|
|
||||||
UncheckedDowncastExpr(SourceLoc asLoc, SourceLoc bangLoc, TypeLoc type)
|
UnconditionalCheckedCastExpr(SourceLoc asLoc, SourceLoc bangLoc, TypeLoc type)
|
||||||
: UncheckedDowncastExpr(nullptr, asLoc, bangLoc, type)
|
: UnconditionalCheckedCastExpr(nullptr, asLoc, bangLoc, type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SourceLoc getBangLoc() const { return BangLoc; }
|
SourceLoc getBangLoc() const { return BangLoc; }
|
||||||
|
|
||||||
static bool classof(const Expr *E) {
|
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
|
/// \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.
|
/// type and 'a as! T' would succeed, false otherwise.
|
||||||
class IsSubtypeExpr : public Expr {
|
///
|
||||||
Expr *SubExpr;
|
/// FIXME: We should support type queries with a runtime metatype value too.
|
||||||
TypeLoc Type;
|
class IsaExpr : public CheckedCastExpr {
|
||||||
SourceLoc IsLoc;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IsSubtypeExpr(Expr *sub, SourceLoc isLoc, TypeLoc type)
|
IsaExpr(Expr *sub, SourceLoc isLoc, TypeLoc type)
|
||||||
: Expr(ExprKind::IsSubtype), SubExpr(sub), Type(type), IsLoc(isLoc)
|
: CheckedCastExpr(ExprKind::Isa,
|
||||||
|
sub, isLoc, type, Type())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
IsSubtypeExpr(SourceLoc isLoc, TypeLoc type)
|
IsaExpr(SourceLoc isLoc, TypeLoc type)
|
||||||
: IsSubtypeExpr(nullptr, isLoc, 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) {
|
static bool classof(const Expr *E) {
|
||||||
return E->getKind() == ExprKind::IsSubtype;
|
return E->getKind() == ExprKind::Isa;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -121,15 +121,12 @@ ABSTRACT_EXPR(ImplicitConversion, Expr)
|
|||||||
EXPR_RANGE(ImplicitConversion, Load, BridgeToBlock)
|
EXPR_RANGE(ImplicitConversion, Load, BridgeToBlock)
|
||||||
ABSTRACT_EXPR(ExplicitCast, Expr)
|
ABSTRACT_EXPR(ExplicitCast, Expr)
|
||||||
EXPR(Coerce, ExplicitCastExpr)
|
EXPR(Coerce, ExplicitCastExpr)
|
||||||
EXPR(UncheckedDowncast, ExplicitCastExpr)
|
ABSTRACT_EXPR(CheckedCast, ExplicitCastExpr)
|
||||||
EXPR(UncheckedSuperToArchetype, ExplicitCastExpr)
|
EXPR(UnconditionalCheckedCast, CheckedCastExpr)
|
||||||
EXPR(UncheckedArchetypeToConcrete, ExplicitCastExpr)
|
EXPR(Isa, CheckedCastExpr)
|
||||||
EXPR(UncheckedArchetypeToArchetype, ExplicitCastExpr)
|
EXPR_RANGE(CheckedCast, UnconditionalCheckedCast, Isa)
|
||||||
EXPR(UncheckedExistentialToArchetype, ExplicitCastExpr)
|
EXPR_RANGE(ExplicitCast, Coerce, Isa)
|
||||||
EXPR(UncheckedExistentialToConcrete, ExplicitCastExpr)
|
|
||||||
EXPR_RANGE(ExplicitCast, Coerce, UncheckedExistentialToConcrete)
|
|
||||||
EXPR(If, Expr)
|
EXPR(If, Expr)
|
||||||
EXPR(IsSubtype, Expr)
|
|
||||||
EXPR(Assign, Expr)
|
EXPR(Assign, Expr)
|
||||||
EXPR(ZeroValue, Expr)
|
EXPR(ZeroValue, Expr)
|
||||||
EXPR(DefaultValue, Expr)
|
EXPR(DefaultValue, Expr)
|
||||||
|
|||||||
@@ -241,11 +241,6 @@ public:
|
|||||||
UpcastInst(Loc, Op, Ty));
|
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,
|
AddressToPointerInst *createAddressToPointer(SILLocation Loc, SILValue Op,
|
||||||
SILType Ty) {
|
SILType Ty) {
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
@@ -306,44 +301,55 @@ public:
|
|||||||
ArchetypeRefToSuperInst(Loc, Archetype, BaseTy));
|
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,
|
SuperToArchetypeRefInst *createSuperToArchetypeRef(SILLocation Loc,
|
||||||
SILValue Archetype,
|
SILValue Archetype,
|
||||||
SILType BaseTy) {
|
SILType BaseTy,
|
||||||
|
CheckedCastMode Mode) {
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
SuperToArchetypeRefInst(Loc, Archetype, BaseTy));
|
SuperToArchetypeRefInst(Loc, Archetype, BaseTy, Mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
DowncastArchetypeAddrInst *createDowncastArchetypeAddr(SILLocation Loc,
|
DowncastArchetypeAddrInst *createDowncastArchetypeAddr(SILLocation Loc,
|
||||||
SILValue Archetype,
|
SILValue Archetype,
|
||||||
SILType Ty) {
|
SILType Ty,
|
||||||
|
CheckedCastMode Mode) {
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
DowncastArchetypeAddrInst(Loc, Archetype, Ty));
|
DowncastArchetypeAddrInst(Loc, Archetype, Ty, Mode));
|
||||||
}
|
}
|
||||||
DowncastArchetypeRefInst *createDowncastArchetypeRef(SILLocation Loc,
|
DowncastArchetypeRefInst *createDowncastArchetypeRef(SILLocation Loc,
|
||||||
SILValue Archetype,
|
SILValue Archetype,
|
||||||
SILType Ty) {
|
SILType Ty,
|
||||||
|
CheckedCastMode Mode) {
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
DowncastArchetypeRefInst(Loc, Archetype, Ty));
|
DowncastArchetypeRefInst(Loc, Archetype, Ty, Mode));
|
||||||
}
|
}
|
||||||
ProjectDowncastExistentialAddrInst *createProjectDowncastExistentialAddr(SILLocation Loc,
|
ProjectDowncastExistentialAddrInst *createProjectDowncastExistentialAddr(
|
||||||
|
SILLocation Loc,
|
||||||
SILValue Existential,
|
SILValue Existential,
|
||||||
SILType Ty) {
|
SILType Ty,
|
||||||
|
CheckedCastMode Mode) {
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
ProjectDowncastExistentialAddrInst(Loc, Existential, Ty));
|
ProjectDowncastExistentialAddrInst(Loc, Existential, Ty, Mode));
|
||||||
}
|
}
|
||||||
DowncastExistentialRefInst *createDowncastExistentialRef(SILLocation Loc,
|
DowncastExistentialRefInst *createDowncastExistentialRef(SILLocation Loc,
|
||||||
SILValue Existential,
|
SILValue Existential,
|
||||||
SILType Ty) {
|
SILType Ty,
|
||||||
|
CheckedCastMode Mode) {
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
DowncastExistentialRefInst(Loc, Existential, Ty));
|
DowncastExistentialRefInst(Loc, Existential, Ty, Mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
IsaInst *createIsa(SILLocation Loc,
|
IsNonnullInst *createIsNonnull(SILLocation Loc,
|
||||||
SILValue Operand,
|
SILValue Operand,
|
||||||
SILType TestType,
|
SILType ResultType) {
|
||||||
SILType ResultType) {
|
|
||||||
return insert(new (F.getModule())
|
return insert(new (F.getModule())
|
||||||
IsaInst(Loc, Operand, TestType, ResultType));
|
IsNonnullInst(Loc, Operand, ResultType));
|
||||||
}
|
}
|
||||||
|
|
||||||
StructInst *createStruct(SILLocation Loc, SILType Ty,
|
StructInst *createStruct(SILLocation Loc, SILType Ty,
|
||||||
|
|||||||
@@ -702,19 +702,10 @@ public:
|
|||||||
: UnaryInstructionBase(Loc, Operand, 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.
|
/// AddressToPointerInst - Convert a SIL address to a Builtin.RawPointer value.
|
||||||
class AddressToPointerInst
|
class AddressToPointerInst
|
||||||
: public UnaryInstructionBase<ValueKind::AddressToPointerInst, ConversionInst>
|
: public UnaryInstructionBase<ValueKind::AddressToPointerInst,
|
||||||
|
ConversionInst>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AddressToPointerInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
AddressToPointerInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
||||||
@@ -811,29 +802,54 @@ public:
|
|||||||
: UnaryInstructionBase(Loc, Operand, Ty) {}
|
: 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
|
/// SuperToArchetypeRefInst - Given a value of a class type, initializes a
|
||||||
/// class archetype with a base class constraint to contain a reference to
|
/// class archetype with a base class constraint to contain a reference to
|
||||||
/// the value.
|
/// the value.
|
||||||
class SuperToArchetypeRefInst
|
class SuperToArchetypeRefInst
|
||||||
: public UnaryInstructionBase<ValueKind::SuperToArchetypeRefInst,
|
: public UnaryInstructionBase<ValueKind::SuperToArchetypeRefInst,
|
||||||
ConversionInst>
|
CheckedConversionInst>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SuperToArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
SuperToArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty,
|
||||||
: UnaryInstructionBase(Loc, Operand, Ty) {}
|
CheckedCastMode Mode)
|
||||||
};
|
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
|
||||||
|
|
||||||
/// 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; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Given the address of an opaque archetype value, dynamically checks the concrete
|
/// Given the address of an opaque archetype value, dynamically checks the concrete
|
||||||
@@ -841,11 +857,12 @@ public:
|
|||||||
/// successful or crashes if not.
|
/// successful or crashes if not.
|
||||||
class DowncastArchetypeAddrInst
|
class DowncastArchetypeAddrInst
|
||||||
: public UnaryInstructionBase<ValueKind::DowncastArchetypeAddrInst,
|
: public UnaryInstructionBase<ValueKind::DowncastArchetypeAddrInst,
|
||||||
ConversionInst>
|
CheckedConversionInst>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DowncastArchetypeAddrInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
DowncastArchetypeAddrInst(SILLocation Loc, SILValue Operand, SILType Ty,
|
||||||
: UnaryInstructionBase(Loc, Operand, Ty) {}
|
CheckedCastMode Mode)
|
||||||
|
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Given a value of class archetype type, dynamically checks the concrete
|
/// Given a value of class archetype type, dynamically checks the concrete
|
||||||
@@ -853,11 +870,12 @@ public:
|
|||||||
/// successful or crashes if not.
|
/// successful or crashes if not.
|
||||||
class DowncastArchetypeRefInst
|
class DowncastArchetypeRefInst
|
||||||
: public UnaryInstructionBase<ValueKind::DowncastArchetypeRefInst,
|
: public UnaryInstructionBase<ValueKind::DowncastArchetypeRefInst,
|
||||||
ConversionInst>
|
CheckedConversionInst>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DowncastArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
DowncastArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty,
|
||||||
: UnaryInstructionBase(Loc, Operand, Ty) {}
|
CheckedCastMode Mode)
|
||||||
|
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Given the address of an opaque existential container, dynamically checks the
|
/// 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.
|
/// the contained value if successful or crashes if not.
|
||||||
class ProjectDowncastExistentialAddrInst
|
class ProjectDowncastExistentialAddrInst
|
||||||
: public UnaryInstructionBase<ValueKind::ProjectDowncastExistentialAddrInst,
|
: public UnaryInstructionBase<ValueKind::ProjectDowncastExistentialAddrInst,
|
||||||
ConversionInst>
|
CheckedConversionInst>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ProjectDowncastExistentialAddrInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
ProjectDowncastExistentialAddrInst(SILLocation Loc, SILValue Operand,
|
||||||
: UnaryInstructionBase(Loc, Operand, Ty) {}
|
SILType Ty,
|
||||||
|
CheckedCastMode Mode)
|
||||||
|
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Given a value of class archetype type, dynamically checks the concrete
|
/// Given a value of class archetype type, dynamically checks the concrete
|
||||||
@@ -877,11 +897,12 @@ public:
|
|||||||
/// successful or crashes if not.
|
/// successful or crashes if not.
|
||||||
class DowncastExistentialRefInst
|
class DowncastExistentialRefInst
|
||||||
: public UnaryInstructionBase<ValueKind::DowncastExistentialRefInst,
|
: public UnaryInstructionBase<ValueKind::DowncastExistentialRefInst,
|
||||||
ConversionInst>
|
CheckedConversionInst>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DowncastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
|
DowncastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty,
|
||||||
: UnaryInstructionBase(Loc, Operand, Ty) {}
|
CheckedCastMode Mode)
|
||||||
|
: UnaryInstructionBase(Loc, Operand, Ty, Mode) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// StructInst - Represents a constructed tuple.
|
/// StructInst - Represents a constructed tuple.
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
|
|||||||
INST(ConvertFunctionInst, ConversionInst)
|
INST(ConvertFunctionInst, ConversionInst)
|
||||||
INST(CoerceInst, ConversionInst)
|
INST(CoerceInst, ConversionInst)
|
||||||
INST(UpcastInst, ConversionInst)
|
INST(UpcastInst, ConversionInst)
|
||||||
INST(DowncastInst, ConversionInst)
|
|
||||||
INST(AddressToPointerInst, ConversionInst)
|
INST(AddressToPointerInst, ConversionInst)
|
||||||
INST(PointerToAddressInst, ConversionInst)
|
INST(PointerToAddressInst, ConversionInst)
|
||||||
INST(RefToObjectPointerInst, ConversionInst)
|
INST(RefToObjectPointerInst, ConversionInst)
|
||||||
@@ -126,13 +125,16 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
|
|||||||
INST(ConvertCCInst, ConversionInst)
|
INST(ConvertCCInst, ConversionInst)
|
||||||
INST(BridgeToBlockInst, ConversionInst)
|
INST(BridgeToBlockInst, ConversionInst)
|
||||||
INST(ArchetypeRefToSuperInst, ConversionInst)
|
INST(ArchetypeRefToSuperInst, ConversionInst)
|
||||||
INST(SuperToArchetypeRefInst, ConversionInst)
|
ABSTRACT_VALUE(CheckedConversionInst, ConversionInst)
|
||||||
INST(DowncastArchetypeAddrInst, ConversionInst)
|
INST(DowncastInst, CheckedConversionInst)
|
||||||
INST(DowncastArchetypeRefInst, ConversionInst)
|
INST(SuperToArchetypeRefInst, CheckedConversionInst)
|
||||||
INST(ProjectDowncastExistentialAddrInst, ConversionInst)
|
INST(DowncastArchetypeAddrInst, CheckedConversionInst)
|
||||||
INST(DowncastExistentialRefInst, ConversionInst)
|
INST(DowncastArchetypeRefInst, CheckedConversionInst)
|
||||||
|
INST(ProjectDowncastExistentialAddrInst, CheckedConversionInst)
|
||||||
|
INST(DowncastExistentialRefInst, CheckedConversionInst)
|
||||||
|
VALUE_RANGE(CheckedConversionInst, DowncastInst, DowncastExistentialRefInst)
|
||||||
VALUE_RANGE(ConversionInst, ConvertFunctionInst, DowncastExistentialRefInst)
|
VALUE_RANGE(ConversionInst, ConvertFunctionInst, DowncastExistentialRefInst)
|
||||||
INST(IsaInst, SILInstruction)
|
INST(IsNonnullInst, SILInstruction)
|
||||||
|
|
||||||
// Array indexing instructions.
|
// Array indexing instructions.
|
||||||
ABSTRACT_VALUE(IndexingInst, SILInstruction)
|
ABSTRACT_VALUE(IndexingInst, SILInstruction)
|
||||||
|
|||||||
@@ -363,16 +363,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*> {
|
|||||||
return E;
|
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 *visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) {
|
||||||
Expr *Sub = doIt(E->getSubExpr());
|
Expr *Sub = doIt(E->getSubExpr());
|
||||||
if (!Sub) return nullptr;
|
if (!Sub) return nullptr;
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ bool Expr::isImplicit() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto downcast = dyn_cast<UncheckedDowncastExpr>(this)) {
|
if (auto downcast = dyn_cast<ExplicitCastExpr>(this)) {
|
||||||
return downcast->getLoc().isInvalid() &&
|
return downcast->getLoc().isInvalid() &&
|
||||||
downcast->getSubExpr()->isImplicit();
|
downcast->getSubExpr()->isImplicit();
|
||||||
}
|
}
|
||||||
@@ -863,7 +863,7 @@ public:
|
|||||||
|
|
||||||
void printExplicitCastExpr(ExplicitCastExpr *E, const char *name) {
|
void printExplicitCastExpr(ExplicitCastExpr *E, const char *name) {
|
||||||
printCommon(E, name) << ' ';
|
printCommon(E, name) << ' ';
|
||||||
E->getTypeLoc().getType()->print(OS);
|
E->getCastTypeLoc().getType()->print(OS);
|
||||||
OS << '\n';
|
OS << '\n';
|
||||||
printRec(E->getSubExpr());
|
printRec(E->getSubExpr());
|
||||||
OS << ')';
|
OS << ')';
|
||||||
@@ -872,23 +872,11 @@ public:
|
|||||||
void visitCoerceExpr(CoerceExpr *E) {
|
void visitCoerceExpr(CoerceExpr *E) {
|
||||||
printExplicitCastExpr(E, "coerce_expr");
|
printExplicitCastExpr(E, "coerce_expr");
|
||||||
}
|
}
|
||||||
void visitUncheckedDowncastExpr(UncheckedDowncastExpr *E) {
|
void visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *E) {
|
||||||
printExplicitCastExpr(E, "unchecked_downcast_expr");
|
printExplicitCastExpr(E, "unconditional_checked_cast_expr");
|
||||||
}
|
}
|
||||||
void visitUncheckedSuperToArchetypeExpr(UncheckedSuperToArchetypeExpr *E) {
|
void visitIsaExpr(IsaExpr *E) {
|
||||||
printExplicitCastExpr(E, "unchecked_super_to_archetype_expr");
|
printExplicitCastExpr(E, "is_subtype_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 visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) {
|
void visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) {
|
||||||
printCommon(E, "rebind_this_in_constructor_expr") << '\n';
|
printCommon(E, "rebind_this_in_constructor_expr") << '\n';
|
||||||
@@ -904,13 +892,6 @@ public:
|
|||||||
printRec(E->getElseExpr());
|
printRec(E->getElseExpr());
|
||||||
OS << ')';
|
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) {
|
void visitDefaultValueExpr(DefaultValueExpr *E) {
|
||||||
printCommon(E, "default_value_expr") << ' ';
|
printCommon(E, "default_value_expr") << ' ';
|
||||||
printRec(E->getSubExpr());
|
printRec(E->getSubExpr());
|
||||||
|
|||||||
@@ -508,7 +508,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void verifyChecked(CoerceExpr *E) {
|
void verifyChecked(CoerceExpr *E) {
|
||||||
Type Ty = E->getTypeLoc().getType();
|
Type Ty = E->getCastTypeLoc().getType();
|
||||||
if (!Ty->isEqual(E->getType()) ||
|
if (!Ty->isEqual(E->getType()) ||
|
||||||
!Ty->isEqual(E->getSubExpr()->getType())) {
|
!Ty->isEqual(E->getSubExpr()->getType())) {
|
||||||
Out << "CoerceExpr types don't match\n";
|
Out << "CoerceExpr types don't match\n";
|
||||||
@@ -516,6 +516,25 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void verifyChecked(SpecializeExpr *E) {
|
||||||
if (!E->getType()->is<FunctionType>()) {
|
if (!E->getType()->is<FunctionType>()) {
|
||||||
Out << "SpecializeExpr must have FunctionType result\n";
|
Out << "SpecializeExpr must have FunctionType result\n";
|
||||||
|
|||||||
@@ -1210,11 +1210,13 @@ namespace {
|
|||||||
|
|
||||||
// Cast the result of the alloc call to the (metatype) 'this'.
|
// Cast the result of the alloc call to the (metatype) 'this'.
|
||||||
// FIXME: instancetype should make this unnecessary.
|
// FIXME: instancetype should make this unnecessary.
|
||||||
initExpr = new (Impl.SwiftContext) UncheckedDowncastExpr(
|
auto cast = new (Impl.SwiftContext) UnconditionalCheckedCastExpr(
|
||||||
initExpr,
|
initExpr,
|
||||||
SourceLoc(),
|
SourceLoc(),
|
||||||
SourceLoc(),
|
SourceLoc(),
|
||||||
TypeLoc::withoutLoc(thisTy));
|
TypeLoc::withoutLoc(thisTy));
|
||||||
|
cast->setCastKind(CheckedCastKind::Downcast);
|
||||||
|
initExpr = cast;
|
||||||
|
|
||||||
result->setAllocThisExpr(initExpr);
|
result->setAllocThisExpr(initExpr);
|
||||||
}
|
}
|
||||||
@@ -1281,11 +1283,13 @@ namespace {
|
|||||||
|
|
||||||
// Cast the result of the alloc call to the (metatype) 'this'.
|
// Cast the result of the alloc call to the (metatype) 'this'.
|
||||||
// FIXME: instancetype should make this unnecessary.
|
// FIXME: instancetype should make this unnecessary.
|
||||||
initExpr = new (Impl.SwiftContext) UncheckedDowncastExpr(
|
auto cast = new (Impl.SwiftContext) UnconditionalCheckedCastExpr(
|
||||||
initExpr,
|
initExpr,
|
||||||
SourceLoc(),
|
SourceLoc(),
|
||||||
SourceLoc(),
|
SourceLoc(),
|
||||||
TypeLoc::withoutLoc(thisTy));
|
TypeLoc::withoutLoc(thisTy));
|
||||||
|
cast->setCastKind(CheckedCastKind::Downcast);
|
||||||
|
initExpr = cast;
|
||||||
|
|
||||||
// Form the assignment statement.
|
// Form the assignment statement.
|
||||||
auto refThis
|
auto refThis
|
||||||
@@ -2581,11 +2585,16 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc,
|
|||||||
TypeLoc::withoutLoc(type));
|
TypeLoc::withoutLoc(type));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConstantConvertKind::Downcast:
|
case ConstantConvertKind::Downcast: {
|
||||||
expr = new (context) UncheckedDowncastExpr(expr, SourceLoc(), SourceLoc(),
|
auto cast = new (context) UnconditionalCheckedCastExpr(expr,
|
||||||
TypeLoc::withoutLoc(type));
|
SourceLoc(),
|
||||||
|
SourceLoc(),
|
||||||
|
TypeLoc::withoutLoc(type));
|
||||||
|
cast->setCastKind(CheckedCastKind::Downcast);
|
||||||
|
expr = cast;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the return statement.
|
// Create the return statement.
|
||||||
auto ret = new (context) ReturnStmt(SourceLoc(), expr);
|
auto ret = new (context) ReturnStmt(SourceLoc(), expr);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "swift/AST/Pattern.h"
|
#include "swift/AST/Pattern.h"
|
||||||
#include "swift/AST/Types.h"
|
#include "swift/AST/Types.h"
|
||||||
#include "swift/SIL/SILType.h"
|
#include "swift/SIL/SILType.h"
|
||||||
|
#include "swift/SIL/SILInstruction.h"
|
||||||
#include "swift/Basic/Optional.h"
|
#include "swift/Basic/Optional.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
#include "llvm/IR/Function.h"
|
#include "llvm/IR/Function.h"
|
||||||
@@ -39,8 +40,8 @@ using namespace swift;
|
|||||||
using namespace irgen;
|
using namespace irgen;
|
||||||
|
|
||||||
/// Emit a checked unconditional downcast.
|
/// Emit a checked unconditional downcast.
|
||||||
llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from,
|
llvm::Value *IRGenFunction::emitDowncast(llvm::Value *from, SILType toType,
|
||||||
SILType toType) {
|
CheckedCastMode mode) {
|
||||||
// Emit the value we're casting from.
|
// Emit the value we're casting from.
|
||||||
if (from->getType() != IGM.Int8PtrTy)
|
if (from->getType() != IGM.Int8PtrTy)
|
||||||
from = Builder.CreateBitCast(from, IGM.Int8PtrTy);
|
from = Builder.CreateBitCast(from, IGM.Int8PtrTy);
|
||||||
@@ -50,16 +51,30 @@ llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from,
|
|||||||
llvm::Value *metadataRef;
|
llvm::Value *metadataRef;
|
||||||
llvm::Constant *castFn;
|
llvm::Constant *castFn;
|
||||||
if (isClass) {
|
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.
|
// and call dynamicCastClass directly.
|
||||||
metadataRef
|
metadataRef
|
||||||
= IGM.getAddrOfTypeMetadata(toType.getSwiftRValueType(), false, false);
|
= 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 {
|
} else {
|
||||||
// Otherwise, get the type metadata, which may be local, and go through
|
// Otherwise, get the type metadata, which may be local, and go through
|
||||||
// the more general dynamicCast entry point.
|
// the more general dynamicCast entry point.
|
||||||
metadataRef = emitTypeMetadataRef(toType);
|
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)
|
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());
|
ExplosionSchema schema(explosion.getKind());
|
||||||
type.getSchema(schema);
|
type.getSchema(schema);
|
||||||
for (auto &element : schema) {
|
for (auto &element : schema) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "swift/AST/ASTContext.h"
|
#include "swift/AST/ASTContext.h"
|
||||||
#include "swift/AST/Types.h"
|
#include "swift/AST/Types.h"
|
||||||
#include "swift/AST/Decl.h"
|
#include "swift/AST/Decl.h"
|
||||||
|
#include "swift/SIL/SILInstruction.h"
|
||||||
#include "swift/SIL/SILType.h"
|
#include "swift/SIL/SILType.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
|
|
||||||
@@ -684,7 +685,8 @@ void irgen::reemitAsSubstituted(IRGenFunction &IGF,
|
|||||||
|
|
||||||
llvm::Value *
|
llvm::Value *
|
||||||
IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super,
|
IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super,
|
||||||
SILType destType) {
|
SILType destType,
|
||||||
|
CheckedCastMode mode) {
|
||||||
assert(destType.is<ArchetypeType>() && "expected archetype type");
|
assert(destType.is<ArchetypeType>() && "expected archetype type");
|
||||||
assert(destType.castTo<ArchetypeType>()->requiresClass()
|
assert(destType.castTo<ArchetypeType>()->requiresClass()
|
||||||
&& "expected class archetype type");
|
&& "expected class archetype type");
|
||||||
@@ -698,9 +700,18 @@ IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super,
|
|||||||
metadataRef = Builder.CreateBitCast(metadataRef, IGM.Int8PtrTy);
|
metadataRef = Builder.CreateBitCast(metadataRef, IGM.Int8PtrTy);
|
||||||
|
|
||||||
// Call the (unconditional) dynamic cast.
|
// 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
|
auto call
|
||||||
= Builder.CreateCall2(IGM.getDynamicCastUnconditionalFn(),
|
= Builder.CreateCall2(castFn, super, metadataRef);
|
||||||
super, metadataRef);
|
|
||||||
|
|
||||||
// FIXME: Eventually, we may want to throw.
|
// FIXME: Eventually, we may want to throw.
|
||||||
call->setDoesNotThrow();
|
call->setDoesNotThrow();
|
||||||
|
|||||||
@@ -3897,10 +3897,11 @@ llvm::Value *irgen::emitClassExistentialProjection(IRGenFunction &IGF,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Address
|
static Address
|
||||||
emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
|
emitOpaqueDowncast(IRGenFunction &IGF,
|
||||||
Address value,
|
Address value,
|
||||||
llvm::Value *srcMetadata,
|
llvm::Value *srcMetadata,
|
||||||
SILType destType) {
|
SILType destType,
|
||||||
|
CheckedCastMode mode) {
|
||||||
llvm::Value *addr = IGF.Builder.CreateBitCast(value.getAddress(),
|
llvm::Value *addr = IGF.Builder.CreateBitCast(value.getAddress(),
|
||||||
IGF.IGM.OpaquePtrTy);
|
IGF.IGM.OpaquePtrTy);
|
||||||
|
|
||||||
@@ -3908,9 +3909,17 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
|
|||||||
llvm::Value *destMetadata = IGF.emitTypeMetadataRef(destType);
|
llvm::Value *destMetadata = IGF.emitTypeMetadataRef(destType);
|
||||||
destMetadata = IGF.Builder.CreateBitCast(destMetadata, IGF.IGM.Int8PtrTy);
|
destMetadata = IGF.Builder.CreateBitCast(destMetadata, IGF.IGM.Int8PtrTy);
|
||||||
|
|
||||||
auto *call
|
llvm::Value *castFn;
|
||||||
= IGF.Builder.CreateCall3(IGF.IGM.getDynamicCastIndirectUnconditionalFn(),
|
switch (mode) {
|
||||||
addr, srcMetadata, destMetadata);
|
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.
|
// FIXME: Eventually, we may want to throw.
|
||||||
call->setDoesNotThrow();
|
call->setDoesNotThrow();
|
||||||
|
|
||||||
@@ -3921,24 +3930,26 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
|
|||||||
return destTI.getAddressForPointer(ptr);
|
return destTI.getAddressForPointer(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a checked unconditional cast of an opaque archetype.
|
/// Emit a checked cast of an opaque archetype.
|
||||||
Address irgen::emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF,
|
Address irgen::emitOpaqueArchetypeDowncast(IRGenFunction &IGF,
|
||||||
Address value,
|
Address value,
|
||||||
SILType srcType,
|
SILType srcType,
|
||||||
SILType destType) {
|
SILType destType,
|
||||||
|
CheckedCastMode mode) {
|
||||||
assert(srcType.is<ArchetypeType>());
|
assert(srcType.is<ArchetypeType>());
|
||||||
assert(!srcType.castTo<ArchetypeType>()->requiresClass());
|
assert(!srcType.castTo<ArchetypeType>()->requiresClass());
|
||||||
|
|
||||||
llvm::Value *srcMetadata = IGF.emitTypeMetadataRef(srcType);
|
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
|
/// Emit a checked unconditional cast of an opaque existential container's
|
||||||
/// contained value.
|
/// contained value.
|
||||||
Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
|
Address irgen::emitOpaqueExistentialDowncast(IRGenFunction &IGF,
|
||||||
Address container,
|
Address container,
|
||||||
SILType srcType,
|
SILType srcType,
|
||||||
SILType destType) {
|
SILType destType,
|
||||||
|
CheckedCastMode mode) {
|
||||||
assert(srcType.isExistentialType());
|
assert(srcType.isExistentialType());
|
||||||
assert(!srcType.isClassExistentialType());
|
assert(!srcType.isClassExistentialType());
|
||||||
|
|
||||||
@@ -3949,5 +3960,5 @@ Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
|
|||||||
std::tie(value, srcMetadata)
|
std::tie(value, srcMetadata)
|
||||||
= emitOpaqueExistentialProjectionWithMetadata(IGF, container, srcType);
|
= emitOpaqueExistentialProjectionWithMetadata(IGF, container, srcType);
|
||||||
|
|
||||||
return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType);
|
return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode);
|
||||||
}
|
}
|
||||||
@@ -34,6 +34,7 @@ namespace swift {
|
|||||||
class ProtocolConformance;
|
class ProtocolConformance;
|
||||||
struct SILConstant;
|
struct SILConstant;
|
||||||
class SILType;
|
class SILType;
|
||||||
|
enum class CheckedCastMode : unsigned char;
|
||||||
|
|
||||||
namespace irgen {
|
namespace irgen {
|
||||||
class AbstractCallee;
|
class AbstractCallee;
|
||||||
@@ -173,18 +174,20 @@ namespace irgen {
|
|||||||
Explosion &value,
|
Explosion &value,
|
||||||
CanType type);
|
CanType type);
|
||||||
|
|
||||||
/// Emit a checked unconditional cast of an opaque archetype.
|
/// Emit a checked cast of an opaque archetype.
|
||||||
Address emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF,
|
Address emitOpaqueArchetypeDowncast(IRGenFunction &IGF,
|
||||||
Address value,
|
Address value,
|
||||||
SILType srcType,
|
SILType srcType,
|
||||||
SILType destType);
|
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.
|
/// contained value.
|
||||||
Address emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
|
Address emitOpaqueExistentialDowncast(IRGenFunction &IGF,
|
||||||
Address value,
|
Address value,
|
||||||
SILType srcType,
|
SILType srcType,
|
||||||
SILType destType);
|
SILType destType,
|
||||||
|
CheckedCastMode mode);
|
||||||
} // end namespace irgen
|
} // end namespace irgen
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ namespace swift {
|
|||||||
class TranslationUnit;
|
class TranslationUnit;
|
||||||
class ValueDecl;
|
class ValueDecl;
|
||||||
class VarDecl;
|
class VarDecl;
|
||||||
|
enum class CheckedCastMode : unsigned char;
|
||||||
|
|
||||||
namespace Mangle {
|
namespace Mangle {
|
||||||
enum class ExplosionKind : unsigned;
|
enum class ExplosionKind : unsigned;
|
||||||
@@ -181,12 +182,14 @@ public:
|
|||||||
/// \brief Convert the given explosion to the given destination archetype,
|
/// \brief Convert the given explosion to the given destination archetype,
|
||||||
/// using a runtime-checked cast.
|
/// using a runtime-checked cast.
|
||||||
llvm::Value *emitSuperToClassArchetypeConversion(llvm::Value *super,
|
llvm::Value *emitSuperToClassArchetypeConversion(llvm::Value *super,
|
||||||
SILType destType);
|
SILType destType,
|
||||||
|
CheckedCastMode mode);
|
||||||
|
|
||||||
/// \brief Convert the given value to the given destination type, using a
|
/// \brief Convert the given value to the given destination type, using a
|
||||||
/// runtime-checked cast.
|
/// runtime-checked cast.
|
||||||
llvm::Value *emitUnconditionalDowncast(llvm::Value *from,
|
llvm::Value *emitDowncast(llvm::Value *from,
|
||||||
SILType toType);
|
SILType toType,
|
||||||
|
CheckedCastMode mode);
|
||||||
|
|
||||||
|
|
||||||
//--- Declaration emission -----------------------------------------------------
|
//--- Declaration emission -----------------------------------------------------
|
||||||
|
|||||||
@@ -1291,7 +1291,7 @@ void IRGenSILFunction::visitSuperToArchetypeRefInst(
|
|||||||
llvm::Value *in = super.claimNext();
|
llvm::Value *in = super.claimNext();
|
||||||
Explosion out(CurExplosionLevel);
|
Explosion out(CurExplosionLevel);
|
||||||
llvm::Value *cast
|
llvm::Value *cast
|
||||||
= emitSuperToClassArchetypeConversion(in, i->getType());
|
= emitSuperToClassArchetypeConversion(in, i->getType(), i->getMode());
|
||||||
out.add(cast);
|
out.add(cast);
|
||||||
newLoweredExplosion(SILValue(i, 0), out);
|
newLoweredExplosion(SILValue(i, 0), out);
|
||||||
}
|
}
|
||||||
@@ -1300,7 +1300,7 @@ void IRGenSILFunction::visitDowncastArchetypeRefInst(
|
|||||||
swift::DowncastArchetypeRefInst *i) {
|
swift::DowncastArchetypeRefInst *i) {
|
||||||
Explosion archetype = getLoweredExplosion(i->getOperand());
|
Explosion archetype = getLoweredExplosion(i->getOperand());
|
||||||
llvm::Value *fromValue = archetype.claimNext();
|
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());
|
Explosion to(archetype.getKind());
|
||||||
to.add(toValue);
|
to.add(toValue);
|
||||||
newLoweredExplosion(SILValue(i,0), to);
|
newLoweredExplosion(SILValue(i,0), to);
|
||||||
@@ -1313,7 +1313,7 @@ void IRGenSILFunction::visitDowncastExistentialRefInst(
|
|||||||
= emitClassExistentialProjection(*this, existential,
|
= emitClassExistentialProjection(*this, existential,
|
||||||
i->getOperand().getType());
|
i->getOperand().getType());
|
||||||
|
|
||||||
llvm::Value *toValue = emitUnconditionalDowncast(instance, i->getType());
|
llvm::Value *toValue = emitDowncast(instance, i->getType(), i->getMode());
|
||||||
Explosion to(existential.getKind());
|
Explosion to(existential.getKind());
|
||||||
to.add(toValue);
|
to.add(toValue);
|
||||||
newLoweredExplosion(SILValue(i,0), to);
|
newLoweredExplosion(SILValue(i,0), to);
|
||||||
@@ -1322,42 +1322,39 @@ void IRGenSILFunction::visitDowncastExistentialRefInst(
|
|||||||
void IRGenSILFunction::visitDowncastArchetypeAddrInst(
|
void IRGenSILFunction::visitDowncastArchetypeAddrInst(
|
||||||
swift::DowncastArchetypeAddrInst *i) {
|
swift::DowncastArchetypeAddrInst *i) {
|
||||||
Address archetype = getLoweredAddress(i->getOperand());
|
Address archetype = getLoweredAddress(i->getOperand());
|
||||||
Address cast = emitUnconditionalOpaqueArchetypeDowncast(*this, archetype,
|
Address cast = emitOpaqueArchetypeDowncast(*this, archetype,
|
||||||
i->getOperand().getType(),
|
i->getOperand().getType(),
|
||||||
i->getType());
|
i->getType(),
|
||||||
|
i->getMode());
|
||||||
newLoweredAddress(SILValue(i,0), cast);
|
newLoweredAddress(SILValue(i,0), cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenSILFunction::visitProjectDowncastExistentialAddrInst(
|
void IRGenSILFunction::visitProjectDowncastExistentialAddrInst(
|
||||||
swift::ProjectDowncastExistentialAddrInst *i) {
|
swift::ProjectDowncastExistentialAddrInst *i) {
|
||||||
Address existential = getLoweredAddress(i->getOperand());
|
Address existential = getLoweredAddress(i->getOperand());
|
||||||
Address cast = emitUnconditionalOpaqueExistentialDowncast(*this, existential,
|
Address cast = emitOpaqueExistentialDowncast(*this, existential,
|
||||||
i->getOperand().getType(),
|
i->getOperand().getType(),
|
||||||
i->getType());
|
i->getType(),
|
||||||
|
i->getMode());
|
||||||
newLoweredAddress(SILValue(i,0), cast);
|
newLoweredAddress(SILValue(i,0), cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGenSILFunction::visitIsaInst(swift::IsaInst *i) {
|
void IRGenSILFunction::visitIsNonnullInst(swift::IsNonnullInst *i) {
|
||||||
// Emit the value we're testing.
|
// Get the value we're testing, which may be an address or an instance
|
||||||
Explosion from = getLoweredExplosion(i->getOperand());
|
// pointer.
|
||||||
llvm::Value *fromValue = from.claimNext();
|
llvm::Value *val;
|
||||||
fromValue = Builder.CreateBitCast(fromValue, IGM.Int8PtrTy);
|
LoweredValue const &lv = getLoweredValue(i->getOperand());
|
||||||
|
if (lv.isAddress()) {
|
||||||
// Emit the metadata of the type we're testing against.
|
val = lv.getAddress().getAddress();
|
||||||
CanType toType = i->getTestType().getSwiftRValueType();
|
} else {
|
||||||
Explosion metadata(ExplosionKind::Minimal);
|
Explosion values = lv.getExplosion(*this);
|
||||||
emitMetaTypeRef(*this, toType, metadata);
|
val = values.claimNext();
|
||||||
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();
|
|
||||||
|
|
||||||
// Check that the result isn't null.
|
// Check that the result isn't null.
|
||||||
|
auto *valTy = cast<llvm::PointerType>(val->getType());
|
||||||
llvm::Value *result = Builder.CreateICmp(llvm::CmpInst::ICMP_NE,
|
llvm::Value *result = Builder.CreateICmp(llvm::CmpInst::ICMP_NE,
|
||||||
call, llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
|
val, llvm::ConstantPointerNull::get(valTy));
|
||||||
|
|
||||||
Explosion out(CurExplosionLevel);
|
Explosion out(CurExplosionLevel);
|
||||||
out.add(result);
|
out.add(result);
|
||||||
@@ -1383,9 +1380,7 @@ void IRGenSILFunction::visitDowncastInst(swift::DowncastInst *i) {
|
|||||||
Explosion from = getLoweredExplosion(i->getOperand());
|
Explosion from = getLoweredExplosion(i->getOperand());
|
||||||
Explosion to(from.getKind());
|
Explosion to(from.getKind());
|
||||||
llvm::Value *fromValue = from.claimNext();
|
llvm::Value *fromValue = from.claimNext();
|
||||||
llvm::Value *castValue = emitUnconditionalDowncast(
|
llvm::Value *castValue = emitDowncast(fromValue, i->getType(), i->getMode());
|
||||||
fromValue,
|
|
||||||
i->getType());
|
|
||||||
to.add(castValue);
|
to.add(castValue);
|
||||||
newLoweredExplosion(SILValue(i, 0), to);
|
newLoweredExplosion(SILValue(i, 0), to);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ public:
|
|||||||
void visitProjectDowncastExistentialAddrInst(
|
void visitProjectDowncastExistentialAddrInst(
|
||||||
ProjectDowncastExistentialAddrInst *i);
|
ProjectDowncastExistentialAddrInst *i);
|
||||||
|
|
||||||
void visitIsaInst(IsaInst *i);
|
void visitIsNonnullInst(IsNonnullInst *i);
|
||||||
|
|
||||||
void visitIndexAddrInst(IndexAddrInst *i);
|
void visitIndexAddrInst(IndexAddrInst *i);
|
||||||
void visitIndexRawPointerInst(IndexRawPointerInst *i);
|
void visitIndexRawPointerInst(IndexRawPointerInst *i);
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ static bool isExprPostfix(Expr *expr) {
|
|||||||
case ExprKind::PostfixUnary:
|
case ExprKind::PostfixUnary:
|
||||||
case ExprKind::PrefixUnary:
|
case ExprKind::PrefixUnary:
|
||||||
case ExprKind::Sequence:
|
case ExprKind::Sequence:
|
||||||
case ExprKind::IsSubtype:
|
case ExprKind::Isa:
|
||||||
case ExprKind::UncheckedDowncast:
|
case ExprKind::UnconditionalCheckedCast:
|
||||||
case ExprKind::Assign:
|
case ExprKind::Assign:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -156,11 +156,6 @@ static bool isExprPostfix(Expr *expr) {
|
|||||||
case ExprKind::Specialize:
|
case ExprKind::Specialize:
|
||||||
case ExprKind::TupleElement:
|
case ExprKind::TupleElement:
|
||||||
case ExprKind::TupleShuffle:
|
case ExprKind::TupleShuffle:
|
||||||
case ExprKind::UncheckedSuperToArchetype:
|
|
||||||
case ExprKind::UncheckedArchetypeToArchetype:
|
|
||||||
case ExprKind::UncheckedArchetypeToConcrete:
|
|
||||||
case ExprKind::UncheckedExistentialToArchetype:
|
|
||||||
case ExprKind::UncheckedExistentialToConcrete:
|
|
||||||
case ExprKind::ZeroValue:
|
case ExprKind::ZeroValue:
|
||||||
llvm_unreachable("Not a parsed expression");
|
llvm_unreachable("Not a parsed expression");
|
||||||
|
|
||||||
@@ -256,7 +251,7 @@ NullablePtr<Expr> Parser::parseExprIs() {
|
|||||||
if (parseType(type, diag::expected_type_after_is))
|
if (parseType(type, diag::expected_type_after_is))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return new (Context) IsSubtypeExpr(isLoc, type);
|
return new (Context) IsaExpr(isLoc, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parseExprAs
|
/// parseExprAs
|
||||||
@@ -276,7 +271,7 @@ NullablePtr<Expr> Parser::parseExprAs() {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return bangLoc.isValid()
|
return bangLoc.isValid()
|
||||||
? (Expr*) new (Context) UncheckedDowncastExpr(asLoc, bangLoc, type)
|
? (Expr*) new (Context) UnconditionalCheckedCastExpr(asLoc, bangLoc, type)
|
||||||
: (Expr*) new (Context) CoerceExpr(asLoc, type);
|
: (Expr*) new (Context) CoerceExpr(asLoc, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -531,18 +531,9 @@ public:
|
|||||||
SGFContext C);
|
SGFContext C);
|
||||||
RValue visitErasureExpr(ErasureExpr *E, SGFContext C);
|
RValue visitErasureExpr(ErasureExpr *E, SGFContext C);
|
||||||
RValue visitCoerceExpr(CoerceExpr *E, SGFContext C);
|
RValue visitCoerceExpr(CoerceExpr *E, SGFContext C);
|
||||||
RValue visitUncheckedDowncastExpr(UncheckedDowncastExpr *E, SGFContext C);
|
RValue visitUnconditionalCheckedCastExpr(
|
||||||
RValue visitUncheckedSuperToArchetypeExpr(
|
UnconditionalCheckedCastExpr *E, SGFContext C);
|
||||||
UncheckedSuperToArchetypeExpr *E, SGFContext C);
|
RValue visitIsaExpr(IsaExpr *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 visitParenExpr(ParenExpr *E, SGFContext C);
|
RValue visitParenExpr(ParenExpr *E, SGFContext C);
|
||||||
RValue visitTupleExpr(TupleExpr *E, SGFContext C);
|
RValue visitTupleExpr(TupleExpr *E, SGFContext C);
|
||||||
RValue visitScalarToTupleExpr(ScalarToTupleExpr *E, SGFContext C);
|
RValue visitScalarToTupleExpr(ScalarToTupleExpr *E, SGFContext C);
|
||||||
|
|||||||
@@ -486,58 +486,6 @@ RValue SILGenFunction::visitCoerceExpr(CoerceExpr *E, SGFContext C) {
|
|||||||
return visit(E->getSubExpr(), 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 {
|
namespace {
|
||||||
class CleanupUsedExistentialContainer : public Cleanup {
|
class CleanupUsedExistentialContainer : public Cleanup {
|
||||||
SILValue existential;
|
SILValue existential;
|
||||||
@@ -551,50 +499,94 @@ namespace {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static RValue emitExistentialDowncast(SILGenFunction &gen,
|
/// \brief Emit the cast instruction appropriate to the kind of checked cast.
|
||||||
ExplicitCastExpr *E, SGFContext C) {
|
///
|
||||||
ManagedValue base = gen.visit(E->getSubExpr()).getAsSingleValue(gen);
|
/// \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;
|
Type castTy = E->getCastTypeLoc().getType();
|
||||||
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
|
switch (E->getCastKind()) {
|
||||||
// deallocate the existential buffer when we're done.
|
case CheckedCastKind::Unresolved:
|
||||||
gen.Cleanups.pushCleanup<CleanupUsedExistentialContainer>(base.getValue());
|
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(
|
RValue SILGenFunction::visitUnconditionalCheckedCastExpr(
|
||||||
UncheckedExistentialToArchetypeExpr *E,
|
UnconditionalCheckedCastExpr *E,
|
||||||
SGFContext C) {
|
SGFContext C) {
|
||||||
return emitExistentialDowncast(*this, E, 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(
|
RValue SILGenFunction::visitIsaExpr(IsaExpr *E, SGFContext C) {
|
||||||
UncheckedExistentialToConcreteExpr *E,
|
// Cast the value using a conditional cast.
|
||||||
SGFContext C) {
|
SILValue cast = emitCheckedCast(*this, E, CheckedCastMode::Conditional,
|
||||||
return emitExistentialDowncast(*this, E, C);
|
/*useCastValue*/ false);
|
||||||
}
|
// Check the result.
|
||||||
|
SILValue is = B.createIsNonnull(E, cast,
|
||||||
RValue SILGenFunction::visitIsSubtypeExpr(IsSubtypeExpr *E, SGFContext C)
|
getLoweredLoadableType(E->getType()));
|
||||||
{
|
return RValue(*this, emitManagedRValueWithCleanup(is));
|
||||||
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::visitParenExpr(ParenExpr *E, SGFContext C) {
|
RValue SILGenFunction::visitParenExpr(ParenExpr *E, SGFContext C) {
|
||||||
@@ -1805,7 +1797,8 @@ RValue SILGenFunction::visitRebindThisInConstructorExpr(
|
|||||||
"delegating ctor type mismatch for non-reference type?!");
|
"delegating ctor type mismatch for non-reference type?!");
|
||||||
CleanupsDepth newThisCleanup = newThis.getCleanup();
|
CleanupsDepth newThisCleanup = newThis.getCleanup();
|
||||||
SILValue newThisValue = B.createDowncast(E, newThis.getValue(),
|
SILValue newThisValue = B.createDowncast(E, newThis.getValue(),
|
||||||
getLoweredLoadableType(E->getThis()->getType()));
|
getLoweredLoadableType(E->getThis()->getType()),
|
||||||
|
CheckedCastMode::Unconditional);
|
||||||
newThis = ManagedValue(newThisValue, newThisCleanup);
|
newThis = ManagedValue(newThisValue, newThisCleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -371,6 +371,21 @@ public:
|
|||||||
OS << name << " " << getID(operand) << ", " << CI->getType();
|
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) {
|
void visitConvertFunctionInst(ConvertFunctionInst *CI) {
|
||||||
printConversionInst(CI, CI->getOperand(), "convert_function");
|
printConversionInst(CI, CI->getOperand(), "convert_function");
|
||||||
}
|
}
|
||||||
@@ -429,8 +444,8 @@ public:
|
|||||||
printConversionInst(CI, CI->getOperand(), "downcast_existential_ref");
|
printConversionInst(CI, CI->getOperand(), "downcast_existential_ref");
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitIsaInst(IsaInst *I) {
|
void visitIsNonnullInst(IsNonnullInst *I) {
|
||||||
OS << "isa " << getID(I->getOperand()) << ", " << I->getTestType();
|
OS << "is_nonnull " << getIDAndType(I->getOperand());
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitStructInst(StructInst *SI) {
|
void visitStructInst(StructInst *SI) {
|
||||||
|
|||||||
@@ -894,19 +894,11 @@ public:
|
|||||||
"downcast must convert to a class type");
|
"downcast must convert to a class type");
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkIsaInst(IsaInst *II) {
|
void checkIsNonnullInst(IsNonnullInst *II) {
|
||||||
require(II->getOperand().getType().getSwiftType()
|
require(II->getOperand().getType().getSwiftType()
|
||||||
->getClassOrBoundGenericClass(),
|
->mayHaveSuperclass()
|
||||||
"isa operand must be a class type");
|
|| II->getOperand().getType().isAddress(),
|
||||||
CanType testTy = II->getTestType().getSwiftRValueType();
|
"isa operand must be a class type or address");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkAddressToPointerInst(AddressToPointerInst *AI) {
|
void checkAddressToPointerInst(AddressToPointerInst *AI) {
|
||||||
|
|||||||
@@ -2891,13 +2891,7 @@ namespace {
|
|||||||
|
|
||||||
// Type check the type parameters in cast expressions.
|
// Type check the type parameters in cast expressions.
|
||||||
if (auto cast = dyn_cast<ExplicitCastExpr>(expr)) {
|
if (auto cast = dyn_cast<ExplicitCastExpr>(expr)) {
|
||||||
if (TC.validateType(cast->getTypeLoc()))
|
if (TC.validateType(cast->getCastTypeLoc()))
|
||||||
return nullptr;
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto is = dyn_cast<IsSubtypeExpr>(expr)) {
|
|
||||||
if (TC.validateType(is->getTypeLoc()))
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1458,24 +1458,21 @@ namespace {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr *visitUncheckedDowncastExpr(UncheckedDowncastExpr *expr) {
|
/// Type-check a checked cast expression.
|
||||||
|
CheckedCastKind checkCheckedCastExpr(CheckedCastExpr *expr) {
|
||||||
auto &tc = cs.getTypeChecker();
|
auto &tc = cs.getTypeChecker();
|
||||||
auto &C = cs.getASTContext();
|
|
||||||
|
|
||||||
// Simplify the type we're converting to.
|
// Simplify the type we're converting to.
|
||||||
Type toType = simplifyType(expr->getType());
|
Type toType = expr->getCastTypeLoc().getType();
|
||||||
expr->setType(toType);
|
|
||||||
|
|
||||||
// Type-check the subexpression in isolation.
|
// Type-check the subexpression in isolation.
|
||||||
Expr *sub = expr->getSubExpr();
|
Expr *sub = expr->getSubExpr();
|
||||||
if (tc.typeCheckExpression(sub, cs.DC)) {
|
if (tc.typeCheckExpression(sub, cs.DC)) {
|
||||||
// FIXME: Mark as error.
|
return CheckedCastKind::Unresolved;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
sub = tc.coerceToRValue(sub);
|
sub = tc.coerceToRValue(sub);
|
||||||
if (!sub) {
|
if (!sub) {
|
||||||
// FIXME: Mark as error.
|
return CheckedCastKind::Unresolved;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
expr->setSubExpr(sub);
|
expr->setSubExpr(sub);
|
||||||
|
|
||||||
@@ -1488,24 +1485,9 @@ namespace {
|
|||||||
|
|
||||||
// If the from/to types are equivalent or implicitly convertible,
|
// If the from/to types are equivalent or implicitly convertible,
|
||||||
// this should have been a coercion expression (b as A) rather than a
|
// 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)) {
|
if (fromType->isEqual(toType) || tc.isConvertibleTo(fromType, toType)) {
|
||||||
// Only complain if the cast was explicitly generated.
|
return CheckedCastKind::InvalidCoercible;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can't downcast to an existential.
|
// We can't downcast to an existential.
|
||||||
@@ -1513,45 +1495,31 @@ namespace {
|
|||||||
tc.diagnose(expr->getLoc(), diag::downcast_to_existential,
|
tc.diagnose(expr->getLoc(), diag::downcast_to_existential,
|
||||||
origFromType, toType)
|
origFromType, toType)
|
||||||
.highlight(sub->getSourceRange())
|
.highlight(sub->getSourceRange())
|
||||||
.highlight(expr->getTypeLoc().getSourceRange());
|
.highlight(expr->getCastTypeLoc().getSourceRange());
|
||||||
return nullptr;
|
return CheckedCastKind::Unresolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A downcast can:
|
// A downcast can:
|
||||||
// - convert an archetype to a (different) archetype type.
|
// - convert an archetype to a (different) archetype type.
|
||||||
if (fromArchetype && toArchetype) {
|
if (fromArchetype && toArchetype) {
|
||||||
auto *atoa = new (C) UncheckedArchetypeToArchetypeExpr(sub,
|
return CheckedCastKind::ArchetypeToArchetype;
|
||||||
expr->getLoc(),
|
|
||||||
expr->getBangLoc(),
|
|
||||||
expr->getTypeLoc());
|
|
||||||
atoa->setType(expr->getType());
|
|
||||||
return atoa;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - convert from an existential to an archetype or conforming concrete
|
// - convert from an existential to an archetype or conforming concrete
|
||||||
// type.
|
// type.
|
||||||
if (fromExistential) {
|
if (fromExistential) {
|
||||||
Expr *etox;
|
|
||||||
if (toArchetype) {
|
if (toArchetype) {
|
||||||
etox = new (C) UncheckedExistentialToArchetypeExpr(sub,
|
return CheckedCastKind::ExistentialToArchetype;
|
||||||
expr->getLoc(),
|
|
||||||
expr->getBangLoc(),
|
|
||||||
expr->getTypeLoc());
|
|
||||||
} else if (tc.isConvertibleTo(toType, fromType)) {
|
} else if (tc.isConvertibleTo(toType, fromType)) {
|
||||||
etox = new (C) UncheckedExistentialToConcreteExpr(sub,
|
return CheckedCastKind::ExistentialToConcrete;
|
||||||
expr->getLoc(),
|
|
||||||
expr->getBangLoc(),
|
|
||||||
expr->getTypeLoc());
|
|
||||||
} else {
|
} else {
|
||||||
tc.diagnose(expr->getLoc(),
|
tc.diagnose(expr->getLoc(),
|
||||||
diag::downcast_from_existential_to_unrelated,
|
diag::downcast_from_existential_to_unrelated,
|
||||||
origFromType, toType)
|
origFromType, toType)
|
||||||
.highlight(sub->getSourceRange())
|
.highlight(sub->getSourceRange())
|
||||||
.highlight(expr->getTypeLoc().getSourceRange());
|
.highlight(expr->getCastTypeLoc().getSourceRange());
|
||||||
return nullptr;
|
return CheckedCastKind::Unresolved;
|
||||||
}
|
}
|
||||||
etox->setType(expr->getType());
|
|
||||||
return etox;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - convert an archetype to a concrete type fulfilling its constraints.
|
// - convert an archetype to a concrete type fulfilling its constraints.
|
||||||
@@ -1561,15 +1529,10 @@ namespace {
|
|||||||
diag::downcast_from_archetype_to_unrelated,
|
diag::downcast_from_archetype_to_unrelated,
|
||||||
origFromType, toType)
|
origFromType, toType)
|
||||||
.highlight(sub->getSourceRange())
|
.highlight(sub->getSourceRange())
|
||||||
.highlight(expr->getTypeLoc().getSourceRange());
|
.highlight(expr->getCastTypeLoc().getSourceRange());
|
||||||
return nullptr;
|
return CheckedCastKind::Unresolved;
|
||||||
}
|
}
|
||||||
auto *atoc = new (C) UncheckedArchetypeToConcreteExpr(sub,
|
return CheckedCastKind::ArchetypeToConcrete;
|
||||||
expr->getLoc(),
|
|
||||||
expr->getBangLoc(),
|
|
||||||
expr->getTypeLoc());
|
|
||||||
atoc->setType(expr->getType());
|
|
||||||
return atoc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - convert from a superclass to an archetype.
|
// - convert from a superclass to an archetype.
|
||||||
@@ -1578,17 +1541,13 @@ namespace {
|
|||||||
|
|
||||||
// Coerce to the supertype of the archetype.
|
// Coerce to the supertype of the archetype.
|
||||||
if (tc.convertToType(sub, toSuperType, cs.DC))
|
if (tc.convertToType(sub, toSuperType, cs.DC))
|
||||||
return nullptr;
|
return CheckedCastKind::Unresolved;
|
||||||
|
|
||||||
// Construct the supertype-to-archetype cast.
|
return CheckedCastKind::SuperToArchetype;
|
||||||
auto *stoa = new (C) UncheckedSuperToArchetypeExpr(sub,
|
|
||||||
expr->getLoc(),
|
|
||||||
expr->getBangLoc(),
|
|
||||||
expr->getTypeLoc());
|
|
||||||
stoa->setType(expr->getType());
|
|
||||||
return stoa;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The remaining case is a class downcast.
|
||||||
|
|
||||||
assert(!fromArchetype && "archetypes should have been handled above");
|
assert(!fromArchetype && "archetypes should have been handled above");
|
||||||
assert(!toArchetype && "archetypes should have been handled above");
|
assert(!toArchetype && "archetypes should have been handled above");
|
||||||
assert(!fromExistential && "existentials 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,
|
tc.diagnose(expr->getLoc(), diag::downcast_to_unrelated,
|
||||||
origFromType, toType)
|
origFromType, toType)
|
||||||
.highlight(sub->getSourceRange())
|
.highlight(sub->getSourceRange())
|
||||||
.highlight(expr->getTypeLoc().getSourceRange());
|
.highlight(expr->getCastTypeLoc().getSourceRange());
|
||||||
return nullptr;
|
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;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr *visitUncheckedSuperToArchetypeExpr(
|
Expr *visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *expr){
|
||||||
UncheckedSuperToArchetypeExpr *expr) {
|
Type toType = expr->getCastTypeLoc().getType();
|
||||||
llvm_unreachable("Already type-checked");
|
expr->setType(toType);
|
||||||
}
|
|
||||||
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) {
|
CheckedCastKind castKind = checkCheckedCastExpr(expr);
|
||||||
expr->setType(simplifyType(expr->getType()));
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
auto &tc = cs.getTypeChecker();
|
Expr *coerce = new (cs.getASTContext()) CoerceExpr(expr->getSubExpr(),
|
||||||
Expr *sub = tc.coerceToRValue(expr->getSubExpr());
|
expr->getLoc(),
|
||||||
if (!sub) return nullptr;
|
expr->getCastTypeLoc());
|
||||||
expr->setSubExpr(sub);
|
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;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2498,10 +2495,10 @@ Expr *ConstraintSystem::applySolution(const Solution &solution,
|
|||||||
return { false, expr };
|
return { false, expr };
|
||||||
}
|
}
|
||||||
|
|
||||||
// For unchecked downcast expressions, the subexpression is checked
|
// For checked cast expressions, the subexpression is checked
|
||||||
// separately.
|
// separately.
|
||||||
if (auto unchecked = dyn_cast<UncheckedDowncastExpr>(expr)) {
|
if (auto unchecked = dyn_cast<CheckedCastExpr>(expr)) {
|
||||||
return { false, Rewriter.visitUncheckedDowncastExpr(unchecked) };
|
return { false, Rewriter.visit(unchecked) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a default-value expression, do nothing.
|
// For a default-value expression, do nothing.
|
||||||
|
|||||||
@@ -856,67 +856,21 @@ namespace {
|
|||||||
|
|
||||||
Type visitCoerceExpr(CoerceExpr *expr) {
|
Type visitCoerceExpr(CoerceExpr *expr) {
|
||||||
// FIXME: Could split the system here.
|
// FIXME: Could split the system here.
|
||||||
Type ty = expr->getTypeLoc().getType();
|
Type ty = expr->getCastTypeLoc().getType();
|
||||||
CS.addConstraint(ConstraintKind::Conversion,
|
CS.addConstraint(ConstraintKind::Conversion,
|
||||||
expr->getSubExpr()->getType(), ty,
|
expr->getSubExpr()->getType(), ty,
|
||||||
CS.getConstraintLocator(expr, { }));
|
CS.getConstraintLocator(expr, { }));
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type visitUncheckedDowncastExpr(UncheckedDowncastExpr *expr) {
|
Type visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *expr) {
|
||||||
// FIXME: Open this type.
|
// FIXME: Open this type.
|
||||||
return expr->getTypeLoc().getType();
|
return expr->getCastTypeLoc().getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type visitUncheckedSuperToArchetypeExpr(
|
Type visitIsaExpr(IsaExpr *expr) {
|
||||||
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);
|
|
||||||
|
|
||||||
// The result is Bool.
|
// The result is Bool.
|
||||||
auto &tc = CS.getTypeChecker();
|
return CS.getTypeChecker().lookupBoolType();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type visitAssignExpr(AssignExpr *expr) {
|
Type visitAssignExpr(AssignExpr *expr) {
|
||||||
@@ -1036,10 +990,10 @@ namespace {
|
|||||||
return { false, expr };
|
return { false, expr };
|
||||||
}
|
}
|
||||||
|
|
||||||
// For unchecked downcast expressions, we visit the subexpression
|
// For checked cast expressions, we visit the subexpression
|
||||||
// separately.
|
// separately.
|
||||||
if (auto unchecked = dyn_cast<UncheckedDowncastExpr>(expr)) {
|
if (auto unchecked = dyn_cast<CheckedCastExpr>(expr)) {
|
||||||
auto type = CG.visitUncheckedDowncastExpr(unchecked);
|
auto type = CG.visit(unchecked);
|
||||||
expr->setType(type);
|
expr->setType(type);
|
||||||
return { false, expr };
|
return { false, expr };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,12 +146,8 @@ static InfixData getInfixData(TypeChecker &TC, Expr *E) {
|
|||||||
// Assignment has fixed precedence.
|
// Assignment has fixed precedence.
|
||||||
assert(!assign->isFolded() && "already folded assign expr in sequence?!");
|
assert(!assign->isFolded() && "already folded assign expr in sequence?!");
|
||||||
return InfixData(90, Associativity::Right);
|
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)) {
|
} 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?!");
|
assert(!as->isFolded() && "already folded 'as' expr in sequence?!");
|
||||||
return InfixData(95, Associativity::None);
|
return InfixData(95, Associativity::None);
|
||||||
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
|
} 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;
|
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)) {
|
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(!as->isFolded() && "already folded 'as' expr in sequence?!");
|
||||||
assert(RHS == as && "'as' with non-type RHS?!");
|
assert(RHS == as && "'as' with non-type RHS?!");
|
||||||
as->setSubExpr(LHS);
|
as->setSubExpr(LHS);
|
||||||
|
|||||||
@@ -187,6 +187,24 @@ ProtocolDecl *TypeChecker::getLiteralProtocol(Expr *expr) {
|
|||||||
llvm_unreachable("Unhandled literal kind");
|
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.
|
/// \brief Check for circular inheritance of protocols.
|
||||||
///
|
///
|
||||||
/// \param Path The circular path through the protocol inheritance hierarchy,
|
/// \param Path The circular path through the protocol inheritance hierarchy,
|
||||||
|
|||||||
@@ -267,6 +267,8 @@ private:
|
|||||||
/// implicitly defined.
|
/// implicitly defined.
|
||||||
llvm::DenseSet<StructDecl *> structsNeedingImplicitDefaultConstructor;
|
llvm::DenseSet<StructDecl *> structsNeedingImplicitDefaultConstructor;
|
||||||
|
|
||||||
|
Optional<Type> boolType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief Determine whether the given type can be default-initialized.
|
/// \brief Determine whether the given type can be default-initialized.
|
||||||
///
|
///
|
||||||
@@ -449,6 +451,9 @@ public:
|
|||||||
/// \returns true if any members were found, false otherwise.
|
/// \returns true if any members were found, false otherwise.
|
||||||
bool lookupConstructors(Type type,SmallVectorImpl<ValueDecl *> &constructors);
|
bool lookupConstructors(Type type,SmallVectorImpl<ValueDecl *> &constructors);
|
||||||
|
|
||||||
|
/// \brief Look up the Bool type in the standard library.
|
||||||
|
Type lookupBoolType();
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// \name Overload resolution
|
/// \name Overload resolution
|
||||||
|
|||||||
Reference in New Issue
Block a user