diff --git a/include/swift/AST/Diagnostics.def b/include/swift/AST/Diagnostics.def index beb2aca2aa3..48cebe8b70d 100644 --- a/include/swift/AST/Diagnostics.def +++ b/include/swift/AST/Diagnostics.def @@ -964,6 +964,9 @@ ERROR(cannot_construct_type,sema_tcc,none, ERROR(downcast_to_supertype,sema_tcc,none, "downcast from %0 to supertype %1 is a coercion; remove the '!'", (Type, Type)) +ERROR(isa_is_always_true,sema_tcc,none, + "'is' test is always true", + (Type, Type)) ERROR(downcast_to_unrelated,sema_tcc,none, "downcast from %0 to unrelated type %1", (Type, Type)) ERROR(downcast_to_existential,sema_tcc,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 69dcd9ee2a2..7d8c9ddd1b4 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2142,23 +2142,30 @@ public: } }; -/// \brief Represents an explicit cast, 'a as T', 'a as? T', or 'a as! T', -/// where "T" is a type, and "a" is the expression that will be converted to -/// the type. +/// \brief Represents an explicit cast, 'a as T', 'a as? T', 'a as! T', or +/// 'a is T', where "T" is a type, and "a" is the expression that will be +/// converted to the type. class ExplicitCastExpr : public Expr { Expr *SubExpr; SourceLoc AsLoc; - TypeLoc Ty; + TypeLoc CastTy; protected: - ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeLoc type) - : Expr(kind, type.getType()), SubExpr(sub), AsLoc(AsLoc), Ty(type) + ExplicitCastExpr(ExprKind kind, Expr *sub, SourceLoc AsLoc, TypeLoc castTy, + Type resultTy) + : Expr(kind), SubExpr(sub), AsLoc(AsLoc), CastTy(castTy) {} public: Expr *getSubExpr() const { return SubExpr; } - TypeLoc &getTypeLoc() { return Ty; } - TypeLoc getTypeLoc() const { return Ty; } + + /// Get the type syntactically spelled in the cast. For some forms of checked + /// cast this is different from the result type of the expression. + TypeLoc &getCastTypeLoc() { return CastTy; } + + /// Get the type syntactically spelled in the cast. For some forms of checked + /// cast this is different from the result type of the expression. + TypeLoc getCastTypeLoc() const { return CastTy; } void setSubExpr(Expr *E) { SubExpr = E; } @@ -2166,8 +2173,8 @@ public: SourceRange getSourceRange() const { return SubExpr - ? SourceRange{SubExpr->getStartLoc(), Ty.getSourceRange().End} - : SourceRange{AsLoc, Ty.getSourceRange().End}; + ? SourceRange{SubExpr->getStartLoc(), CastTy.getSourceRange().End} + : SourceRange{AsLoc, CastTy.getSourceRange().End}; } /// True if the node has been processed by SequenceExpr folding. @@ -2188,7 +2195,8 @@ public: class CoerceExpr : public ExplicitCastExpr { public: CoerceExpr(Expr *sub, SourceLoc asLoc, TypeLoc type) - : ExplicitCastExpr(ExprKind::Coerce, sub, asLoc, type) { } + : ExplicitCastExpr(ExprKind::Coerce, sub, asLoc, type, + type.getType()) { } CoerceExpr(SourceLoc asLoc, TypeLoc type) : CoerceExpr(nullptr, asLoc, type) @@ -2198,169 +2206,103 @@ public: return E->getKind() == ExprKind::Coerce; } }; + +/// Discriminates the different kinds of checked cast supported. +enum class CheckedCastKind { + /// The kind has not been determined yet. + Unresolved, + /// The requested conversion is implicit and should be represented as a + /// coercion. + InvalidCoercible, + + /// Valid resolved kinds start here. + First_Resolved, + + /// A cast from a class to one of its subclasses. + Downcast = First_Resolved, + /// A cast from a class to a type parameter constrained by that class as a + /// base class. + SuperToArchetype, + /// A cast from a type parameter to another type parameter. + ArchetypeToArchetype, + /// A cast from a type parameter to a concrete type. + ArchetypeToConcrete, + /// A cast from an existential type to a type parameter. + ExistentialToArchetype, + /// A cast from an existential type to a concrete type. + ExistentialToConcrete, +}; + +/// \brief Abstract base class for checked casts 'as!' and 'is'. These represent +/// casts that can dynamically fail. +class CheckedCastExpr : public ExplicitCastExpr { + CheckedCastKind CastKind; +public: + CheckedCastExpr(ExprKind kind, + Expr *sub, SourceLoc asLoc, TypeLoc castTy, Type resultTy) + : ExplicitCastExpr(kind, sub, asLoc, castTy, resultTy), + CastKind(CheckedCastKind::Unresolved) + {} + + /// Return the semantic kind of cast performed. + CheckedCastKind getCastKind() const { return CastKind; } + void setCastKind(CheckedCastKind kind) { CastKind = kind; } + + /// True if the cast has been type-checked and its kind has been set. + bool isResolved() const { + return CastKind >= CheckedCastKind::First_Resolved; + } + + static bool classof(const Expr *E) { + return E->getKind() >= ExprKind::First_CheckedCastExpr + && E->getKind() <= ExprKind::Last_CheckedCastExpr; + } +}; -/// \brief Represents an explicit unchecked downcast, converting from a -/// supertype to its subtype or crashing if the cast is not possible, +/// \brief Represents an explicit unconditional checked cast, which converts +/// from a type to some subtype or aborts if the cast is not possible, /// spelled 'a as! T'. /// -/// FIXME: At present, only class downcasting is supported. -/// FIXME: All downcasts are currently unchecked, which is horrible. -class UncheckedDowncastExpr : public ExplicitCastExpr { +/// FIXME: All downcasts are currently unconditional, which is horrible. +class UnconditionalCheckedCastExpr : public CheckedCastExpr { SourceLoc BangLoc; public: - UncheckedDowncastExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc, - TypeLoc type) - : ExplicitCastExpr(ExprKind::UncheckedDowncast, sub, asLoc, type), + UnconditionalCheckedCastExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc, + TypeLoc type) + : CheckedCastExpr(ExprKind::UnconditionalCheckedCast, + sub, asLoc, type, type.getType()), BangLoc(bangLoc) { } - UncheckedDowncastExpr(SourceLoc asLoc, SourceLoc bangLoc, TypeLoc type) - : UncheckedDowncastExpr(nullptr, asLoc, bangLoc, type) + UnconditionalCheckedCastExpr(SourceLoc asLoc, SourceLoc bangLoc, TypeLoc type) + : UnconditionalCheckedCastExpr(nullptr, asLoc, bangLoc, type) {} SourceLoc getBangLoc() const { return BangLoc; } - + static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UncheckedDowncast; + return E->getKind() == ExprKind::UnconditionalCheckedCast; } }; -/// \brief Represents an explicit unchecked downcast, converting from a -/// superclass of an archetype to the archetype iself or crashing if the cast -/// is not possible, spelled 'a as! T' for an archetype type T. -/// -/// FIXME: All downcasts are currently unchecked, which is horrible. -class UncheckedSuperToArchetypeExpr : public ExplicitCastExpr { - SourceLoc BangLoc; - -public: - UncheckedSuperToArchetypeExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc, - TypeLoc type) - : ExplicitCastExpr(ExprKind::UncheckedSuperToArchetype, sub, asLoc, type), - BangLoc(bangLoc) { } - - SourceLoc getBangLoc() const { return BangLoc; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UncheckedSuperToArchetype; - } -}; - -/// \brief Represents an explicit unchecked cast from an archetype value to a -/// different archetype, spelled 't as! U' for an archetype value t and -/// archetype type U. -class UncheckedArchetypeToArchetypeExpr : public ExplicitCastExpr { - SourceLoc BangLoc; - -public: - UncheckedArchetypeToArchetypeExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc, - TypeLoc type) - : ExplicitCastExpr(ExprKind::UncheckedArchetypeToArchetype, sub, asLoc, type), - BangLoc(bangLoc) { } - - SourceLoc getBangLoc() const { return BangLoc; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UncheckedArchetypeToArchetype; - } -}; - -/// \brief Represents an explicit unchecked cast from an archetype value to a -/// concrete type, spelled 't as! A' for an archetype value t -/// and concrete type 'A'. -class UncheckedArchetypeToConcreteExpr : public ExplicitCastExpr { - SourceLoc BangLoc; - -public: - UncheckedArchetypeToConcreteExpr(Expr *sub, SourceLoc asLoc, SourceLoc bangLoc, - TypeLoc type) - : ExplicitCastExpr(ExprKind::UncheckedArchetypeToConcrete, sub, asLoc, type), - BangLoc(bangLoc) { } - - SourceLoc getBangLoc() const { return BangLoc; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UncheckedArchetypeToConcrete; - } -}; - -/// \brief Represents an explicit unchecked cast from an existential type value -/// to an archetype, spelled 'p as! T' for a protocol value p -/// and archetype type 'T'. -class UncheckedExistentialToArchetypeExpr : public ExplicitCastExpr { - SourceLoc BangLoc; - -public: - UncheckedExistentialToArchetypeExpr(Expr *sub, SourceLoc asLoc, - SourceLoc bangLoc, - TypeLoc type) - : ExplicitCastExpr(ExprKind::UncheckedExistentialToArchetype, - sub, asLoc, type), - BangLoc(bangLoc) { } - - SourceLoc getBangLoc() const { return BangLoc; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UncheckedExistentialToArchetype; - } -}; - -/// \brief Represents an explicit unchecked cast from an existential type value -/// to a concrete type, spelled 'p as! A' for a protocol value p -/// and conforming type 'A'. -class UncheckedExistentialToConcreteExpr : public ExplicitCastExpr { - SourceLoc BangLoc; - -public: - UncheckedExistentialToConcreteExpr(Expr *sub, SourceLoc asLoc, - SourceLoc bangLoc, - TypeLoc type) - : ExplicitCastExpr(ExprKind::UncheckedExistentialToConcrete, - sub, asLoc, type), - BangLoc(bangLoc) { } - - SourceLoc getBangLoc() const { return BangLoc; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UncheckedExistentialToConcrete; - } -}; - /// \brief Represents a runtime type check query, 'a is T', where 'T' is a type -/// and 'a' is a value of a supertype of T. Evaluates to true if 'a' is of the +/// and 'a' is a value of some related type. Evaluates to true if 'a' is of the /// type and 'a as! T' would succeed, false otherwise. -class IsSubtypeExpr : public Expr { - Expr *SubExpr; - TypeLoc Type; - SourceLoc IsLoc; - +/// +/// FIXME: We should support type queries with a runtime metatype value too. +class IsaExpr : public CheckedCastExpr { public: - IsSubtypeExpr(Expr *sub, SourceLoc isLoc, TypeLoc type) - : Expr(ExprKind::IsSubtype), SubExpr(sub), Type(type), IsLoc(isLoc) + IsaExpr(Expr *sub, SourceLoc isLoc, TypeLoc type) + : CheckedCastExpr(ExprKind::Isa, + sub, isLoc, type, Type()) {} - IsSubtypeExpr(SourceLoc isLoc, TypeLoc type) - : IsSubtypeExpr(nullptr, isLoc, type) + IsaExpr(SourceLoc isLoc, TypeLoc type) + : IsaExpr(nullptr, isLoc, type) {} - Expr *getSubExpr() const { return SubExpr; } - TypeLoc &getTypeLoc() { return Type; } - TypeLoc getTypeLoc() const { return Type; } - - void setSubExpr(Expr *E) { SubExpr = E; } - - SourceLoc getLoc() const { return IsLoc; } - SourceRange getSourceRange() const { - return SubExpr - ? SourceRange{SubExpr->getStartLoc(), Type.getSourceRange().End} - : SourceRange{IsLoc, Type.getSourceRange().End}; - } - - /// True if the node has been processed by SequenceExpr folding. - bool isFolded() const { return SubExpr; } - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::IsSubtype; + return E->getKind() == ExprKind::Isa; } }; diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 7172757026e..700b9975d41 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -121,15 +121,12 @@ ABSTRACT_EXPR(ImplicitConversion, Expr) EXPR_RANGE(ImplicitConversion, Load, BridgeToBlock) ABSTRACT_EXPR(ExplicitCast, Expr) EXPR(Coerce, ExplicitCastExpr) - EXPR(UncheckedDowncast, ExplicitCastExpr) - EXPR(UncheckedSuperToArchetype, ExplicitCastExpr) - EXPR(UncheckedArchetypeToConcrete, ExplicitCastExpr) - EXPR(UncheckedArchetypeToArchetype, ExplicitCastExpr) - EXPR(UncheckedExistentialToArchetype, ExplicitCastExpr) - EXPR(UncheckedExistentialToConcrete, ExplicitCastExpr) - EXPR_RANGE(ExplicitCast, Coerce, UncheckedExistentialToConcrete) + ABSTRACT_EXPR(CheckedCast, ExplicitCastExpr) + EXPR(UnconditionalCheckedCast, CheckedCastExpr) + EXPR(Isa, CheckedCastExpr) + EXPR_RANGE(CheckedCast, UnconditionalCheckedCast, Isa) + EXPR_RANGE(ExplicitCast, Coerce, Isa) EXPR(If, Expr) -EXPR(IsSubtype, Expr) EXPR(Assign, Expr) EXPR(ZeroValue, Expr) EXPR(DefaultValue, Expr) diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 83fe8d709d6..3f0282b3553 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -241,11 +241,6 @@ public: UpcastInst(Loc, Op, Ty)); } - DowncastInst *createDowncast(SILLocation Loc, SILValue Op, SILType Ty) { - return insert(new (F.getModule()) - DowncastInst(Loc, Op, Ty)); - } - AddressToPointerInst *createAddressToPointer(SILLocation Loc, SILValue Op, SILType Ty) { return insert(new (F.getModule()) @@ -306,44 +301,55 @@ public: ArchetypeRefToSuperInst(Loc, Archetype, BaseTy)); } + DowncastInst *createDowncast(SILLocation Loc, SILValue Op, SILType Ty, + CheckedCastMode Mode) { + return insert(new (F.getModule()) + DowncastInst(Loc, Op, Ty, Mode)); + } + SuperToArchetypeRefInst *createSuperToArchetypeRef(SILLocation Loc, SILValue Archetype, - SILType BaseTy) { + SILType BaseTy, + CheckedCastMode Mode) { return insert(new (F.getModule()) - SuperToArchetypeRefInst(Loc, Archetype, BaseTy)); + SuperToArchetypeRefInst(Loc, Archetype, BaseTy, Mode)); } DowncastArchetypeAddrInst *createDowncastArchetypeAddr(SILLocation Loc, SILValue Archetype, - SILType Ty) { + SILType Ty, + CheckedCastMode Mode) { return insert(new (F.getModule()) - DowncastArchetypeAddrInst(Loc, Archetype, Ty)); + DowncastArchetypeAddrInst(Loc, Archetype, Ty, Mode)); } DowncastArchetypeRefInst *createDowncastArchetypeRef(SILLocation Loc, SILValue Archetype, - SILType Ty) { + SILType Ty, + CheckedCastMode Mode) { return insert(new (F.getModule()) - DowncastArchetypeRefInst(Loc, Archetype, Ty)); + DowncastArchetypeRefInst(Loc, Archetype, Ty, Mode)); } - ProjectDowncastExistentialAddrInst *createProjectDowncastExistentialAddr(SILLocation Loc, + ProjectDowncastExistentialAddrInst *createProjectDowncastExistentialAddr( + SILLocation Loc, SILValue Existential, - SILType Ty) { + SILType Ty, + CheckedCastMode Mode) { return insert(new (F.getModule()) - ProjectDowncastExistentialAddrInst(Loc, Existential, Ty)); + ProjectDowncastExistentialAddrInst(Loc, Existential, Ty, Mode)); } DowncastExistentialRefInst *createDowncastExistentialRef(SILLocation Loc, SILValue Existential, - SILType Ty) { + SILType Ty, + CheckedCastMode Mode) { return insert(new (F.getModule()) - DowncastExistentialRefInst(Loc, Existential, Ty)); + DowncastExistentialRefInst(Loc, Existential, Ty, Mode)); } - IsaInst *createIsa(SILLocation Loc, - SILValue Operand, - SILType TestType, - SILType ResultType) { + IsNonnullInst *createIsNonnull(SILLocation Loc, + SILValue Operand, + SILType ResultType) { return insert(new (F.getModule()) - IsaInst(Loc, Operand, TestType, ResultType)); + IsNonnullInst(Loc, Operand, ResultType)); } StructInst *createStruct(SILLocation Loc, SILType Ty, diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 7e19f084a3e..22efaf6b407 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -701,20 +701,11 @@ public: UpcastInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; - -/// DowncastInst - Perform an unchecked conversion of a class instance to a -/// subclass type. -class DowncastInst - : public UnaryInstructionBase -{ -public: - DowncastInst(SILLocation Loc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(Loc, Operand, Ty) {} -}; /// AddressToPointerInst - Convert a SIL address to a Builtin.RawPointer value. class AddressToPointerInst - : public UnaryInstructionBase + : public UnaryInstructionBase { public: AddressToPointerInst(SILLocation Loc, SILValue Operand, SILType Ty) @@ -811,29 +802,54 @@ public: : UnaryInstructionBase(Loc, Operand, Ty) {} }; +/// Test that an address or reference type is not null. +class IsNonnullInst : public UnaryInstructionBase { +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 +{ +public: + DowncastInst(SILLocation Loc, SILValue Operand, SILType Ty, + CheckedCastMode Mode) + : UnaryInstructionBase(Loc, Operand, Ty, Mode) {} +}; + /// SuperToArchetypeRefInst - Given a value of a class type, initializes a /// class archetype with a base class constraint to contain a reference to /// the value. class SuperToArchetypeRefInst : public UnaryInstructionBase + CheckedConversionInst> { public: - SuperToArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(Loc, Operand, Ty) {} -}; - -/// IsaInst - Perform a runtime check of a class instance's type. -class IsaInst : public UnaryInstructionBase { - SILType TestType; -public: - IsaInst(SILLocation Loc, - SILValue Operand, - SILType TestTy, - SILType BoolTy) - : UnaryInstructionBase(Loc, Operand, BoolTy), TestType(TestTy) {} - - SILType getTestType() const { return TestType; } + SuperToArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty, + CheckedCastMode Mode) + : UnaryInstructionBase(Loc, Operand, Ty, Mode) {} }; /// Given the address of an opaque archetype value, dynamically checks the concrete @@ -841,11 +857,12 @@ public: /// successful or crashes if not. class DowncastArchetypeAddrInst : public UnaryInstructionBase + CheckedConversionInst> { public: - DowncastArchetypeAddrInst(SILLocation Loc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(Loc, Operand, Ty) {} + DowncastArchetypeAddrInst(SILLocation Loc, SILValue Operand, SILType Ty, + CheckedCastMode Mode) + : UnaryInstructionBase(Loc, Operand, Ty, Mode) {} }; /// Given a value of class archetype type, dynamically checks the concrete @@ -853,11 +870,12 @@ public: /// successful or crashes if not. class DowncastArchetypeRefInst : public UnaryInstructionBase + CheckedConversionInst> { public: - DowncastArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(Loc, Operand, Ty) {} + DowncastArchetypeRefInst(SILLocation Loc, SILValue Operand, SILType Ty, + CheckedCastMode Mode) + : UnaryInstructionBase(Loc, Operand, Ty, Mode) {} }; /// Given the address of an opaque existential container, dynamically checks the @@ -865,11 +883,13 @@ public: /// the contained value if successful or crashes if not. class ProjectDowncastExistentialAddrInst : public UnaryInstructionBase + CheckedConversionInst> { public: - ProjectDowncastExistentialAddrInst(SILLocation Loc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(Loc, Operand, Ty) {} + ProjectDowncastExistentialAddrInst(SILLocation Loc, SILValue Operand, + SILType Ty, + CheckedCastMode Mode) + : UnaryInstructionBase(Loc, Operand, Ty, Mode) {} }; /// Given a value of class archetype type, dynamically checks the concrete @@ -877,11 +897,12 @@ public: /// successful or crashes if not. class DowncastExistentialRefInst : public UnaryInstructionBase + CheckedConversionInst> { public: - DowncastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(Loc, Operand, Ty) {} + DowncastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty, + CheckedCastMode Mode) + : UnaryInstructionBase(Loc, Operand, Ty, Mode) {} }; /// StructInst - Represents a constructed tuple. diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 4cd760f40eb..78e05c432bd 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -115,7 +115,6 @@ ABSTRACT_VALUE(SILInstruction, ValueBase) INST(ConvertFunctionInst, ConversionInst) INST(CoerceInst, ConversionInst) INST(UpcastInst, ConversionInst) - INST(DowncastInst, ConversionInst) INST(AddressToPointerInst, ConversionInst) INST(PointerToAddressInst, ConversionInst) INST(RefToObjectPointerInst, ConversionInst) @@ -126,13 +125,16 @@ ABSTRACT_VALUE(SILInstruction, ValueBase) INST(ConvertCCInst, ConversionInst) INST(BridgeToBlockInst, ConversionInst) INST(ArchetypeRefToSuperInst, ConversionInst) - INST(SuperToArchetypeRefInst, ConversionInst) - INST(DowncastArchetypeAddrInst, ConversionInst) - INST(DowncastArchetypeRefInst, ConversionInst) - INST(ProjectDowncastExistentialAddrInst, ConversionInst) - INST(DowncastExistentialRefInst, ConversionInst) + ABSTRACT_VALUE(CheckedConversionInst, ConversionInst) + INST(DowncastInst, CheckedConversionInst) + INST(SuperToArchetypeRefInst, CheckedConversionInst) + INST(DowncastArchetypeAddrInst, CheckedConversionInst) + INST(DowncastArchetypeRefInst, CheckedConversionInst) + INST(ProjectDowncastExistentialAddrInst, CheckedConversionInst) + INST(DowncastExistentialRefInst, CheckedConversionInst) + VALUE_RANGE(CheckedConversionInst, DowncastInst, DowncastExistentialRefInst) VALUE_RANGE(ConversionInst, ConvertFunctionInst, DowncastExistentialRefInst) - INST(IsaInst, SILInstruction) + INST(IsNonnullInst, SILInstruction) // Array indexing instructions. ABSTRACT_VALUE(IndexingInst, SILInstruction) diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 3697906cc39..1b46dd58028 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -363,16 +363,6 @@ class Traversal : public ASTVisitor { return E; } - Expr *visitIsSubtypeExpr(IsSubtypeExpr *E) { - if (Expr *Sub = E->getSubExpr()) { - Sub = doIt(Sub); - if (!Sub) return nullptr; - E->setSubExpr(Sub); - } - - return E; - } - Expr *visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) { Expr *Sub = doIt(E->getSubExpr()); if (!Sub) return nullptr; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 62dfb127d10..3f6c6ef9f62 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -130,7 +130,7 @@ bool Expr::isImplicit() const { return true; } - if (auto downcast = dyn_cast(this)) { + if (auto downcast = dyn_cast(this)) { return downcast->getLoc().isInvalid() && downcast->getSubExpr()->isImplicit(); } @@ -863,7 +863,7 @@ public: void printExplicitCastExpr(ExplicitCastExpr *E, const char *name) { printCommon(E, name) << ' '; - E->getTypeLoc().getType()->print(OS); + E->getCastTypeLoc().getType()->print(OS); OS << '\n'; printRec(E->getSubExpr()); OS << ')'; @@ -872,23 +872,11 @@ public: void visitCoerceExpr(CoerceExpr *E) { printExplicitCastExpr(E, "coerce_expr"); } - void visitUncheckedDowncastExpr(UncheckedDowncastExpr *E) { - printExplicitCastExpr(E, "unchecked_downcast_expr"); + void visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *E) { + printExplicitCastExpr(E, "unconditional_checked_cast_expr"); } - void visitUncheckedSuperToArchetypeExpr(UncheckedSuperToArchetypeExpr *E) { - printExplicitCastExpr(E, "unchecked_super_to_archetype_expr"); - } - void visitUncheckedArchetypeToArchetypeExpr(UncheckedArchetypeToArchetypeExpr *E) { - printExplicitCastExpr(E, "unchecked_archetype_to_archetype_expr"); - } - void visitUncheckedArchetypeToConcreteExpr(UncheckedArchetypeToConcreteExpr *E) { - printExplicitCastExpr(E, "unchecked_archetype_to_concrete_expr"); - } - void visitUncheckedExistentialToArchetypeExpr(UncheckedExistentialToArchetypeExpr *E) { - printExplicitCastExpr(E, "unchecked_existential_to_archetype_expr"); - } - void visitUncheckedExistentialToConcreteExpr(UncheckedExistentialToConcreteExpr *E) { - printExplicitCastExpr(E, "unchecked_existential_to_concrete_expr"); + void visitIsaExpr(IsaExpr *E) { + printExplicitCastExpr(E, "is_subtype_expr"); } void visitRebindThisInConstructorExpr(RebindThisInConstructorExpr *E) { printCommon(E, "rebind_this_in_constructor_expr") << '\n'; @@ -904,13 +892,6 @@ public: printRec(E->getElseExpr()); OS << ')'; } - void visitIsSubtypeExpr(IsSubtypeExpr *E) { - printCommon(E, "is_subtype_expr") << ' '; - E->getTypeLoc().getType()->print(OS); - OS << '\n'; - printRec(E->getSubExpr()); - OS << ')'; - } void visitDefaultValueExpr(DefaultValueExpr *E) { printCommon(E, "default_value_expr") << ' '; printRec(E->getSubExpr()); diff --git a/lib/AST/Verifier.cpp b/lib/AST/Verifier.cpp index b02a18f22f1..6bda922552a 100644 --- a/lib/AST/Verifier.cpp +++ b/lib/AST/Verifier.cpp @@ -508,13 +508,32 @@ namespace { } void verifyChecked(CoerceExpr *E) { - Type Ty = E->getTypeLoc().getType(); + Type Ty = E->getCastTypeLoc().getType(); if (!Ty->isEqual(E->getType()) || !Ty->isEqual(E->getSubExpr()->getType())) { Out << "CoerceExpr types don't match\n"; abort(); } } + + void verifyChecked(UnconditionalCheckedCastExpr *E) { + Type Ty = E->getCastTypeLoc().getType(); + if (!Ty->isEqual(E->getType())) { + Out << "UnconditionalCheckedCast types don't match\n"; + abort(); + } + if (!E->isResolved()) { + Out << "UnconditionalCheckedCast kind not resolved\n"; + abort(); + } + } + + void verifyChecked(CheckedCastExpr *E) { + if (!E->isResolved()) { + Out << "CheckedCast kind not resolved\n"; + abort(); + } + } void verifyChecked(SpecializeExpr *E) { if (!E->getType()->is()) { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 9bb33e357a7..5794fefb0f1 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1210,11 +1210,13 @@ namespace { // Cast the result of the alloc call to the (metatype) 'this'. // FIXME: instancetype should make this unnecessary. - initExpr = new (Impl.SwiftContext) UncheckedDowncastExpr( + auto cast = new (Impl.SwiftContext) UnconditionalCheckedCastExpr( initExpr, SourceLoc(), SourceLoc(), TypeLoc::withoutLoc(thisTy)); + cast->setCastKind(CheckedCastKind::Downcast); + initExpr = cast; result->setAllocThisExpr(initExpr); } @@ -1281,11 +1283,13 @@ namespace { // Cast the result of the alloc call to the (metatype) 'this'. // FIXME: instancetype should make this unnecessary. - initExpr = new (Impl.SwiftContext) UncheckedDowncastExpr( + auto cast = new (Impl.SwiftContext) UnconditionalCheckedCastExpr( initExpr, SourceLoc(), SourceLoc(), TypeLoc::withoutLoc(thisTy)); + cast->setCastKind(CheckedCastKind::Downcast); + initExpr = cast; // Form the assignment statement. auto refThis @@ -2581,11 +2585,16 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, TypeLoc::withoutLoc(type)); break; - case ConstantConvertKind::Downcast: - expr = new (context) UncheckedDowncastExpr(expr, SourceLoc(), SourceLoc(), - TypeLoc::withoutLoc(type)); + case ConstantConvertKind::Downcast: { + auto cast = new (context) UnconditionalCheckedCastExpr(expr, + SourceLoc(), + SourceLoc(), + TypeLoc::withoutLoc(type)); + cast->setCastKind(CheckedCastKind::Downcast); + expr = cast; break; } + } // Create the return statement. auto ret = new (context) ReturnStmt(SourceLoc(), expr); diff --git a/lib/IRGen/GenExpr.cpp b/lib/IRGen/GenExpr.cpp index af5cff882cb..030d6fa2d13 100644 --- a/lib/IRGen/GenExpr.cpp +++ b/lib/IRGen/GenExpr.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/Types.h" #include "swift/SIL/SILType.h" +#include "swift/SIL/SILInstruction.h" #include "swift/Basic/Optional.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -39,8 +40,8 @@ using namespace swift; using namespace irgen; /// Emit a checked unconditional downcast. -llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from, - SILType toType) { +llvm::Value *IRGenFunction::emitDowncast(llvm::Value *from, SILType toType, + CheckedCastMode mode) { // Emit the value we're casting from. if (from->getType() != IGM.Int8PtrTy) from = Builder.CreateBitCast(from, IGM.Int8PtrTy); @@ -50,16 +51,30 @@ llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from, llvm::Value *metadataRef; llvm::Constant *castFn; if (isClass) { - // If the dest type is a concrete class, get the class metadata + // If the dest type is a concrete class, get the full class metadata // and call dynamicCastClass directly. metadataRef = IGM.getAddrOfTypeMetadata(toType.getSwiftRValueType(), false, false); - castFn = IGM.getDynamicCastClassUnconditionalFn(); + switch (mode) { + case CheckedCastMode::Unconditional: + castFn = IGM.getDynamicCastClassUnconditionalFn(); + break; + case CheckedCastMode::Conditional: + castFn = IGM.getDynamicCastClassFn(); + break; + } } else { // Otherwise, get the type metadata, which may be local, and go through // the more general dynamicCast entry point. metadataRef = emitTypeMetadataRef(toType); - castFn = IGM.getDynamicCastUnconditionalFn(); + switch (mode) { + case CheckedCastMode::Unconditional: + castFn = IGM.getDynamicCastUnconditionalFn(); + break; + case CheckedCastMode::Conditional: + castFn = IGM.getDynamicCastFn(); + break; + } } if (metadataRef->getType() != IGM.Int8PtrTy) @@ -76,7 +91,8 @@ llvm::Value *IRGenFunction::emitUnconditionalDowncast(llvm::Value *from, } -void IRGenFunction::emitFakeExplosion(const TypeInfo &type, Explosion &explosion) { +void IRGenFunction::emitFakeExplosion(const TypeInfo &type, + Explosion &explosion) { ExplosionSchema schema(explosion.getKind()); type.getSchema(schema); for (auto &element : schema) { diff --git a/lib/IRGen/GenPoly.cpp b/lib/IRGen/GenPoly.cpp index f7ff36f3d97..f9ca6553d4a 100644 --- a/lib/IRGen/GenPoly.cpp +++ b/lib/IRGen/GenPoly.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Types.h" #include "swift/AST/Decl.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILType.h" #include "llvm/IR/DerivedTypes.h" @@ -684,7 +685,8 @@ void irgen::reemitAsSubstituted(IRGenFunction &IGF, llvm::Value * IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super, - SILType destType) { + SILType destType, + CheckedCastMode mode) { assert(destType.is() && "expected archetype type"); assert(destType.castTo()->requiresClass() && "expected class archetype type"); @@ -698,9 +700,18 @@ IRGenFunction::emitSuperToClassArchetypeConversion(llvm::Value *super, metadataRef = Builder.CreateBitCast(metadataRef, IGM.Int8PtrTy); // Call the (unconditional) dynamic cast. + llvm::Value *castFn; + switch (mode) { + case CheckedCastMode::Unconditional: + castFn = IGM.getDynamicCastUnconditionalFn(); + break; + case CheckedCastMode::Conditional: + castFn = IGM.getDynamicCastFn(); + break; + } + auto call - = Builder.CreateCall2(IGM.getDynamicCastUnconditionalFn(), - super, metadataRef); + = Builder.CreateCall2(castFn, super, metadataRef); // FIXME: Eventually, we may want to throw. call->setDoesNotThrow(); diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index b9e0efb7504..5bab605a522 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3897,10 +3897,11 @@ llvm::Value *irgen::emitClassExistentialProjection(IRGenFunction &IGF, } static Address -emitUnconditionalOpaqueDowncast(IRGenFunction &IGF, - Address value, - llvm::Value *srcMetadata, - SILType destType) { +emitOpaqueDowncast(IRGenFunction &IGF, + Address value, + llvm::Value *srcMetadata, + SILType destType, + CheckedCastMode mode) { llvm::Value *addr = IGF.Builder.CreateBitCast(value.getAddress(), IGF.IGM.OpaquePtrTy); @@ -3908,9 +3909,17 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF, llvm::Value *destMetadata = IGF.emitTypeMetadataRef(destType); destMetadata = IGF.Builder.CreateBitCast(destMetadata, IGF.IGM.Int8PtrTy); - auto *call - = IGF.Builder.CreateCall3(IGF.IGM.getDynamicCastIndirectUnconditionalFn(), - addr, srcMetadata, destMetadata); + llvm::Value *castFn; + switch (mode) { + case CheckedCastMode::Unconditional: + castFn = IGF.IGM.getDynamicCastIndirectUnconditionalFn(); + break; + case CheckedCastMode::Conditional: + castFn = IGF.IGM.getDynamicCastIndirectFn(); + break; + } + + auto *call = IGF.Builder.CreateCall3(castFn, addr, srcMetadata, destMetadata); // FIXME: Eventually, we may want to throw. call->setDoesNotThrow(); @@ -3921,24 +3930,26 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF, return destTI.getAddressForPointer(ptr); } -/// Emit a checked unconditional cast of an opaque archetype. -Address irgen::emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF, - Address value, - SILType srcType, - SILType destType) { +/// Emit a checked cast of an opaque archetype. +Address irgen::emitOpaqueArchetypeDowncast(IRGenFunction &IGF, + Address value, + SILType srcType, + SILType destType, + CheckedCastMode mode) { assert(srcType.is()); assert(!srcType.castTo()->requiresClass()); llvm::Value *srcMetadata = IGF.emitTypeMetadataRef(srcType); - return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType); + return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode); } /// Emit a checked unconditional cast of an opaque existential container's /// contained value. -Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF, - Address container, - SILType srcType, - SILType destType) { +Address irgen::emitOpaqueExistentialDowncast(IRGenFunction &IGF, + Address container, + SILType srcType, + SILType destType, + CheckedCastMode mode) { assert(srcType.isExistentialType()); assert(!srcType.isClassExistentialType()); @@ -3949,5 +3960,5 @@ Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF, std::tie(value, srcMetadata) = emitOpaqueExistentialProjectionWithMetadata(IGF, container, srcType); - return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType); + return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode); } \ No newline at end of file diff --git a/lib/IRGen/GenProto.h b/lib/IRGen/GenProto.h index 08a54afcb1d..8045d9b8f90 100644 --- a/lib/IRGen/GenProto.h +++ b/lib/IRGen/GenProto.h @@ -34,6 +34,7 @@ namespace swift { class ProtocolConformance; struct SILConstant; class SILType; + enum class CheckedCastMode : unsigned char; namespace irgen { class AbstractCallee; @@ -173,18 +174,20 @@ namespace irgen { Explosion &value, CanType type); - /// Emit a checked unconditional cast of an opaque archetype. - Address emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF, - Address value, - SILType srcType, - SILType destType); + /// Emit a checked cast of an opaque archetype. + Address emitOpaqueArchetypeDowncast(IRGenFunction &IGF, + Address value, + SILType srcType, + SILType destType, + CheckedCastMode mode); - /// Emit a checked unconditional cast of an opaque existential container's + /// Emit a checked cast of an opaque existential container's /// contained value. - Address emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF, - Address value, - SILType srcType, - SILType destType); + Address emitOpaqueExistentialDowncast(IRGenFunction &IGF, + Address value, + SILType srcType, + SILType destType, + CheckedCastMode mode); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index 8fccb60c018..ff3ac587707 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -51,6 +51,7 @@ namespace swift { class TranslationUnit; class ValueDecl; class VarDecl; + enum class CheckedCastMode : unsigned char; namespace Mangle { enum class ExplosionKind : unsigned; @@ -181,12 +182,14 @@ public: /// \brief Convert the given explosion to the given destination archetype, /// using a runtime-checked cast. llvm::Value *emitSuperToClassArchetypeConversion(llvm::Value *super, - SILType destType); + SILType destType, + CheckedCastMode mode); /// \brief Convert the given value to the given destination type, using a /// runtime-checked cast. - llvm::Value *emitUnconditionalDowncast(llvm::Value *from, - SILType toType); + llvm::Value *emitDowncast(llvm::Value *from, + SILType toType, + CheckedCastMode mode); //--- Declaration emission ----------------------------------------------------- diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 3a0cde4e98c..e63cd26b641 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1291,7 +1291,7 @@ void IRGenSILFunction::visitSuperToArchetypeRefInst( llvm::Value *in = super.claimNext(); Explosion out(CurExplosionLevel); llvm::Value *cast - = emitSuperToClassArchetypeConversion(in, i->getType()); + = emitSuperToClassArchetypeConversion(in, i->getType(), i->getMode()); out.add(cast); newLoweredExplosion(SILValue(i, 0), out); } @@ -1300,7 +1300,7 @@ void IRGenSILFunction::visitDowncastArchetypeRefInst( swift::DowncastArchetypeRefInst *i) { Explosion archetype = getLoweredExplosion(i->getOperand()); llvm::Value *fromValue = archetype.claimNext(); - llvm::Value *toValue = emitUnconditionalDowncast(fromValue, i->getType()); + llvm::Value *toValue = emitDowncast(fromValue, i->getType(), i->getMode()); Explosion to(archetype.getKind()); to.add(toValue); newLoweredExplosion(SILValue(i,0), to); @@ -1313,7 +1313,7 @@ void IRGenSILFunction::visitDowncastExistentialRefInst( = emitClassExistentialProjection(*this, existential, i->getOperand().getType()); - llvm::Value *toValue = emitUnconditionalDowncast(instance, i->getType()); + llvm::Value *toValue = emitDowncast(instance, i->getType(), i->getMode()); Explosion to(existential.getKind()); to.add(toValue); newLoweredExplosion(SILValue(i,0), to); @@ -1322,42 +1322,39 @@ void IRGenSILFunction::visitDowncastExistentialRefInst( void IRGenSILFunction::visitDowncastArchetypeAddrInst( swift::DowncastArchetypeAddrInst *i) { Address archetype = getLoweredAddress(i->getOperand()); - Address cast = emitUnconditionalOpaqueArchetypeDowncast(*this, archetype, - i->getOperand().getType(), - i->getType()); + Address cast = emitOpaqueArchetypeDowncast(*this, archetype, + i->getOperand().getType(), + i->getType(), + i->getMode()); newLoweredAddress(SILValue(i,0), cast); } void IRGenSILFunction::visitProjectDowncastExistentialAddrInst( swift::ProjectDowncastExistentialAddrInst *i) { Address existential = getLoweredAddress(i->getOperand()); - Address cast = emitUnconditionalOpaqueExistentialDowncast(*this, existential, - i->getOperand().getType(), - i->getType()); + Address cast = emitOpaqueExistentialDowncast(*this, existential, + i->getOperand().getType(), + i->getType(), + i->getMode()); newLoweredAddress(SILValue(i,0), cast); } -void IRGenSILFunction::visitIsaInst(swift::IsaInst *i) { - // Emit the value we're testing. - Explosion from = getLoweredExplosion(i->getOperand()); - llvm::Value *fromValue = from.claimNext(); - fromValue = Builder.CreateBitCast(fromValue, IGM.Int8PtrTy); - - // Emit the metadata of the type we're testing against. - CanType toType = i->getTestType().getSwiftRValueType(); - Explosion metadata(ExplosionKind::Minimal); - emitMetaTypeRef(*this, toType, metadata); - llvm::Value *metadataValue = metadata.claimNext(); - metadataValue = Builder.CreateBitCast(metadataValue, IGM.Int8PtrTy); - - // Perform a checked cast. - auto call = Builder.CreateCall2(IGM.getDynamicCastClassFn(), - fromValue, metadataValue); - call->setDoesNotThrow(); +void IRGenSILFunction::visitIsNonnullInst(swift::IsNonnullInst *i) { + // Get the value we're testing, which may be an address or an instance + // pointer. + llvm::Value *val; + LoweredValue const &lv = getLoweredValue(i->getOperand()); + if (lv.isAddress()) { + val = lv.getAddress().getAddress(); + } else { + Explosion values = lv.getExplosion(*this); + val = values.claimNext(); + } // Check that the result isn't null. + auto *valTy = cast(val->getType()); llvm::Value *result = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, - call, llvm::ConstantPointerNull::get(IGM.Int8PtrTy)); + val, llvm::ConstantPointerNull::get(valTy)); Explosion out(CurExplosionLevel); out.add(result); @@ -1383,9 +1380,7 @@ void IRGenSILFunction::visitDowncastInst(swift::DowncastInst *i) { Explosion from = getLoweredExplosion(i->getOperand()); Explosion to(from.getKind()); llvm::Value *fromValue = from.claimNext(); - llvm::Value *castValue = emitUnconditionalDowncast( - fromValue, - i->getType()); + llvm::Value *castValue = emitDowncast(fromValue, i->getType(), i->getMode()); to.add(castValue); newLoweredExplosion(SILValue(i, 0), to); } diff --git a/lib/IRGen/IRGenSIL.h b/lib/IRGen/IRGenSIL.h index b2362510da9..dc4ee2e6a2e 100644 --- a/lib/IRGen/IRGenSIL.h +++ b/lib/IRGen/IRGenSIL.h @@ -539,7 +539,7 @@ public: void visitProjectDowncastExistentialAddrInst( ProjectDowncastExistentialAddrInst *i); - void visitIsaInst(IsaInst *i); + void visitIsNonnullInst(IsNonnullInst *i); void visitIndexAddrInst(IndexAddrInst *i); void visitIndexRawPointerInst(IndexRawPointerInst *i); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 258015738d3..cd809c06e46 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -92,8 +92,8 @@ static bool isExprPostfix(Expr *expr) { case ExprKind::PostfixUnary: case ExprKind::PrefixUnary: case ExprKind::Sequence: - case ExprKind::IsSubtype: - case ExprKind::UncheckedDowncast: + case ExprKind::Isa: + case ExprKind::UnconditionalCheckedCast: case ExprKind::Assign: return false; @@ -156,11 +156,6 @@ static bool isExprPostfix(Expr *expr) { case ExprKind::Specialize: case ExprKind::TupleElement: case ExprKind::TupleShuffle: - case ExprKind::UncheckedSuperToArchetype: - case ExprKind::UncheckedArchetypeToArchetype: - case ExprKind::UncheckedArchetypeToConcrete: - case ExprKind::UncheckedExistentialToArchetype: - case ExprKind::UncheckedExistentialToConcrete: case ExprKind::ZeroValue: llvm_unreachable("Not a parsed expression"); @@ -256,7 +251,7 @@ NullablePtr Parser::parseExprIs() { if (parseType(type, diag::expected_type_after_is)) return nullptr; - return new (Context) IsSubtypeExpr(isLoc, type); + return new (Context) IsaExpr(isLoc, type); } /// parseExprAs @@ -276,7 +271,7 @@ NullablePtr Parser::parseExprAs() { return nullptr; return bangLoc.isValid() - ? (Expr*) new (Context) UncheckedDowncastExpr(asLoc, bangLoc, type) + ? (Expr*) new (Context) UnconditionalCheckedCastExpr(asLoc, bangLoc, type) : (Expr*) new (Context) CoerceExpr(asLoc, type); } diff --git a/lib/SIL/SILGen/SILGen.h b/lib/SIL/SILGen/SILGen.h index c1f1d1d8711..c0b8c286ea1 100644 --- a/lib/SIL/SILGen/SILGen.h +++ b/lib/SIL/SILGen/SILGen.h @@ -531,18 +531,9 @@ public: SGFContext C); RValue visitErasureExpr(ErasureExpr *E, SGFContext C); RValue visitCoerceExpr(CoerceExpr *E, SGFContext C); - RValue visitUncheckedDowncastExpr(UncheckedDowncastExpr *E, SGFContext C); - RValue visitUncheckedSuperToArchetypeExpr( - UncheckedSuperToArchetypeExpr *E, SGFContext C); - RValue visitUncheckedArchetypeToArchetypeExpr( - UncheckedArchetypeToArchetypeExpr *E, SGFContext C); - RValue visitUncheckedArchetypeToConcreteExpr( - UncheckedArchetypeToConcreteExpr *E, SGFContext C); - RValue visitUncheckedExistentialToArchetypeExpr( - UncheckedExistentialToArchetypeExpr *E, SGFContext C); - RValue visitUncheckedExistentialToConcreteExpr( - UncheckedExistentialToConcreteExpr *E, SGFContext C); - RValue visitIsSubtypeExpr(IsSubtypeExpr *E, SGFContext C); + RValue visitUnconditionalCheckedCastExpr( + UnconditionalCheckedCastExpr *E, SGFContext C); + RValue visitIsaExpr(IsaExpr *E, SGFContext C); RValue visitParenExpr(ParenExpr *E, SGFContext C); RValue visitTupleExpr(TupleExpr *E, SGFContext C); RValue visitScalarToTupleExpr(ScalarToTupleExpr *E, SGFContext C); diff --git a/lib/SIL/SILGen/SILGenExpr.cpp b/lib/SIL/SILGen/SILGenExpr.cpp index e0fed1ea507..4b9f22432f2 100644 --- a/lib/SIL/SILGen/SILGenExpr.cpp +++ b/lib/SIL/SILGen/SILGenExpr.cpp @@ -486,58 +486,6 @@ RValue SILGenFunction::visitCoerceExpr(CoerceExpr *E, SGFContext C) { return visit(E->getSubExpr(), C); } -RValue SILGenFunction::visitUncheckedDowncastExpr(UncheckedDowncastExpr *E, - SGFContext C) { - ManagedValue original = visit(E->getSubExpr()).getAsSingleValue(*this); - SILValue converted = B.createDowncast(E, original.getValue(), - getLoweredLoadableType(E->getType())); - return RValue(*this, ManagedValue(converted, original.getCleanup())); -} - -RValue SILGenFunction::visitUncheckedSuperToArchetypeExpr( - UncheckedSuperToArchetypeExpr *E, - SGFContext C) { - ManagedValue base = visit(E->getSubExpr()).getAsSingleValue(*this); - // Initialize it with a SuperToArchetypeInst. - SILValue archetype = B.createSuperToArchetypeRef(E, base.getValue(), - getLoweredLoadableType(E->getType())); - // Keep the base-class-typed cleanup so we use a concrete release. - return RValue(*this, ManagedValue(archetype, base.getCleanup())); -} - -static RValue emitArchetypeDowncast(SILGenFunction &gen, - ExplicitCastExpr *E, SGFContext C) { - ManagedValue base = gen.visit(E->getSubExpr()).getAsSingleValue(gen); - - // Cast to the concrete type and replace the cleanup with a new one on the - // concrete value, which should be more specific and more efficient than the - // one on the original archetype. - SILValue cast; - if (E->getSubExpr()->getType()->castTo()->requiresClass()) { - cast = gen.B.createDowncastArchetypeRef(E, base.forward(gen), - gen.getLoweredLoadableType(E->getType())); - } else { - SILType castTy = gen.getLoweredType(E->getType()); - cast = gen.B.createDowncastArchetypeAddr(E, base.forward(gen), - castTy.getAddressType()); - if (castTy.isLoadable(gen.F.getModule())) - cast = gen.B.createLoad(E, cast); - } - return RValue(gen, gen.emitManagedRValueWithCleanup(cast)); -} - -RValue SILGenFunction::visitUncheckedArchetypeToArchetypeExpr( - UncheckedArchetypeToArchetypeExpr *E, - SGFContext C) { - return emitArchetypeDowncast(*this, E, C); -} - -RValue SILGenFunction::visitUncheckedArchetypeToConcreteExpr( - UncheckedArchetypeToConcreteExpr *E, - SGFContext C) { - return emitArchetypeDowncast(*this, E, C); -} - namespace { class CleanupUsedExistentialContainer : public Cleanup { SILValue existential; @@ -551,50 +499,94 @@ namespace { }; } -static RValue emitExistentialDowncast(SILGenFunction &gen, - ExplicitCastExpr *E, SGFContext C) { - ManagedValue base = gen.visit(E->getSubExpr()).getAsSingleValue(gen); +/// \brief Emit the cast instruction appropriate to the kind of checked cast. +/// +/// \param gen The SILGenFunction. +/// \param E The CheckedCastExpr to emit. +/// \param mode Whether to emit an unconditional or conditional cast. +/// \param useCastValue If true, the cleanup on the original value will be +/// disabled, and the callee will be expected to take +/// ownership of the returned value. If false, the original +/// value's cleanup is left intact, and an unowned reference +/// or address is returned. +static SILValue emitCheckedCast(SILGenFunction &gen, + CheckedCastExpr *E, + CheckedCastMode mode, + bool useCastValue) { + ManagedValue originalMV = gen.visit(E->getSubExpr()).getAsSingleValue(gen); + SILValue original = useCastValue + ? originalMV.forward(gen) + : originalMV.getValue(); - SILValue cast; - if (E->getSubExpr()->getType()->isClassExistentialType()) { - // Cast to the concrete type and replace the cleanup with a new one on the - // archetype, which may be more specific. - cast = gen.B.createDowncastExistentialRef(E, base.forward(gen), - gen.getLoweredLoadableType(E->getType())); - } else { - // Project the concrete value address out of the container. - SILType castTy = gen.getLoweredType(E->getType()); - cast = gen.B.createProjectDowncastExistentialAddr(E, base.forward(gen), - castTy.getAddressType()); - if (castTy.isLoadable(gen.F.getModule())) - cast = gen.B.createLoad(E, cast); - - // We'll pass on ownership of the contained value, but we still need to - // deallocate the existential buffer when we're done. - gen.Cleanups.pushCleanup(base.getValue()); + Type castTy = E->getCastTypeLoc().getType(); + + switch (E->getCastKind()) { + case CheckedCastKind::Unresolved: + case CheckedCastKind::InvalidCoercible: + llvm_unreachable("invalid checked cast?!"); + + case CheckedCastKind::Downcast: + return gen.B.createDowncast(E, original, + gen.getLoweredLoadableType(castTy), mode); + case CheckedCastKind::SuperToArchetype: + return gen.B.createSuperToArchetypeRef(E, original, + gen.getLoweredLoadableType(castTy), mode); + case CheckedCastKind::ArchetypeToArchetype: + case CheckedCastKind::ArchetypeToConcrete: + if (E->getSubExpr()->getType()->castTo()->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(original); + } + + return cast; + } } - return RValue(gen, gen.emitManagedRValueWithCleanup(cast)); } -RValue SILGenFunction::visitUncheckedExistentialToArchetypeExpr( - UncheckedExistentialToArchetypeExpr *E, - SGFContext C) { - return emitExistentialDowncast(*this, E, C); +RValue SILGenFunction::visitUnconditionalCheckedCastExpr( + UnconditionalCheckedCastExpr *E, + SGFContext C) { + // Disable the original cleanup because the cast-to type is more specific and + // should have a more efficient cleanup. + SILValue cast = emitCheckedCast(*this, E, CheckedCastMode::Unconditional, + /*useCastValue*/ true); + return RValue(*this, emitManagedRValueWithCleanup(cast)); } -RValue SILGenFunction::visitUncheckedExistentialToConcreteExpr( - UncheckedExistentialToConcreteExpr *E, - SGFContext C) { - return emitExistentialDowncast(*this, E, C); -} - -RValue SILGenFunction::visitIsSubtypeExpr(IsSubtypeExpr *E, SGFContext C) -{ - ManagedValue base = visit(E->getSubExpr()).getAsSingleValue(*this); - SILValue res = B.createIsa(E, base.getValue(), - getLoweredType(E->getTypeLoc().getType()), - getLoweredLoadableType(E->getType())); - return RValue(*this, emitManagedRValueWithCleanup(res)); +RValue SILGenFunction::visitIsaExpr(IsaExpr *E, SGFContext C) { + // Cast the value using a conditional cast. + SILValue cast = emitCheckedCast(*this, E, CheckedCastMode::Conditional, + /*useCastValue*/ false); + // Check the result. + SILValue is = B.createIsNonnull(E, cast, + getLoweredLoadableType(E->getType())); + return RValue(*this, emitManagedRValueWithCleanup(is)); } RValue SILGenFunction::visitParenExpr(ParenExpr *E, SGFContext C) { @@ -1805,7 +1797,8 @@ RValue SILGenFunction::visitRebindThisInConstructorExpr( "delegating ctor type mismatch for non-reference type?!"); CleanupsDepth newThisCleanup = newThis.getCleanup(); SILValue newThisValue = B.createDowncast(E, newThis.getValue(), - getLoweredLoadableType(E->getThis()->getType())); + getLoweredLoadableType(E->getThis()->getType()), + CheckedCastMode::Unconditional); newThis = ManagedValue(newThisValue, newThisCleanup); } diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 6a1823b8805..2335d4b99fc 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -370,6 +370,21 @@ public: llvm::StringRef name) { OS << name << " " << getID(operand) << ", " << CI->getType(); } + + void printConversionInst(CheckedConversionInst *CI, + SILValue operand, + llvm::StringRef name) { + OS << name; + switch (CI->getMode()) { + case CheckedCastMode::Conditional: + OS << " conditional "; + break; + case CheckedCastMode::Unconditional: + OS << " unconditional "; + break; + } + OS << getID(operand) << ", " << CI->getType(); + } void visitConvertFunctionInst(ConvertFunctionInst *CI) { printConversionInst(CI, CI->getOperand(), "convert_function"); @@ -429,8 +444,8 @@ public: printConversionInst(CI, CI->getOperand(), "downcast_existential_ref"); } - void visitIsaInst(IsaInst *I) { - OS << "isa " << getID(I->getOperand()) << ", " << I->getTestType(); + void visitIsNonnullInst(IsNonnullInst *I) { + OS << "is_nonnull " << getIDAndType(I->getOperand()); } void visitStructInst(StructInst *SI) { diff --git a/lib/SIL/Verifier.cpp b/lib/SIL/Verifier.cpp index 906598da366..caeb3052bdb 100644 --- a/lib/SIL/Verifier.cpp +++ b/lib/SIL/Verifier.cpp @@ -894,19 +894,11 @@ public: "downcast must convert to a class type"); } - void checkIsaInst(IsaInst *II) { + void checkIsNonnullInst(IsNonnullInst *II) { require(II->getOperand().getType().getSwiftType() - ->getClassOrBoundGenericClass(), - "isa operand must be a class type"); - CanType testTy = II->getTestType().getSwiftRValueType(); - if (auto *archetype = dyn_cast(testTy)) - require((bool)archetype->getSuperclass(), - "isa must test against a class type or base-class-constrained " - "archetype"); - else - require(testTy->getClassOrBoundGenericClass(), - "isa must test against a class type or base-class-constrained " - "archetype"); + ->mayHaveSuperclass() + || II->getOperand().getType().isAddress(), + "isa operand must be a class type or address"); } void checkAddressToPointerInst(AddressToPointerInst *AI) { diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7b3465d3818..db69a28e43c 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2891,13 +2891,7 @@ namespace { // Type check the type parameters in cast expressions. if (auto cast = dyn_cast(expr)) { - if (TC.validateType(cast->getTypeLoc())) - return nullptr; - return expr; - } - - if (auto is = dyn_cast(expr)) { - if (TC.validateType(is->getTypeLoc())) + if (TC.validateType(cast->getCastTypeLoc())) return nullptr; return expr; } diff --git a/lib/Sema/TypeCheckConstraintsApply.cpp b/lib/Sema/TypeCheckConstraintsApply.cpp index 143136dca6c..ba47578e025 100644 --- a/lib/Sema/TypeCheckConstraintsApply.cpp +++ b/lib/Sema/TypeCheckConstraintsApply.cpp @@ -1457,25 +1457,22 @@ namespace { expr->setSubExpr(subExpr); return expr; } - - Expr *visitUncheckedDowncastExpr(UncheckedDowncastExpr *expr) { + + /// Type-check a checked cast expression. + CheckedCastKind checkCheckedCastExpr(CheckedCastExpr *expr) { auto &tc = cs.getTypeChecker(); - auto &C = cs.getASTContext(); // Simplify the type we're converting to. - Type toType = simplifyType(expr->getType()); - expr->setType(toType); + Type toType = expr->getCastTypeLoc().getType(); // Type-check the subexpression in isolation. Expr *sub = expr->getSubExpr(); if (tc.typeCheckExpression(sub, cs.DC)) { - // FIXME: Mark as error. - return nullptr; + return CheckedCastKind::Unresolved; } sub = tc.coerceToRValue(sub); if (!sub) { - // FIXME: Mark as error. - return nullptr; + return CheckedCastKind::Unresolved; } expr->setSubExpr(sub); @@ -1488,24 +1485,9 @@ namespace { // If the from/to types are equivalent or implicitly convertible, // this should have been a coercion expression (b as A) rather than a - // cast (a as! B). Complain. + // checked cast (a as! B). Complain. if (fromType->isEqual(toType) || tc.isConvertibleTo(fromType, toType)) { - // Only complain if the cast was explicitly generated. - // FIXME: This leniency is here for the Clang module importer, - // which doesn't necessarily know whether it needs to force the - // cast or not. instancetype should eliminate the need for it. - if (!expr->isImplicit()) { - tc.diagnose(expr->getLoc(), diag::downcast_to_supertype, - origFromType, toType) - .highlight(sub->getSourceRange()) - .highlight(expr->getTypeLoc().getSourceRange()) - .fixItRemove(SourceRange(expr->getBangLoc())); - } - - Expr *coerce = new (C) CoerceExpr(sub, expr->getLoc(), - expr->getTypeLoc()); - coerce->setType(expr->getType()); - return coerce; + return CheckedCastKind::InvalidCoercible; } // We can't downcast to an existential. @@ -1513,45 +1495,31 @@ namespace { tc.diagnose(expr->getLoc(), diag::downcast_to_existential, origFromType, toType) .highlight(sub->getSourceRange()) - .highlight(expr->getTypeLoc().getSourceRange()); - return nullptr; + .highlight(expr->getCastTypeLoc().getSourceRange()); + return CheckedCastKind::Unresolved; } // A downcast can: // - convert an archetype to a (different) archetype type. if (fromArchetype && toArchetype) { - auto *atoa = new (C) UncheckedArchetypeToArchetypeExpr(sub, - expr->getLoc(), - expr->getBangLoc(), - expr->getTypeLoc()); - atoa->setType(expr->getType()); - return atoa; + return CheckedCastKind::ArchetypeToArchetype; } // - convert from an existential to an archetype or conforming concrete // type. if (fromExistential) { - Expr *etox; if (toArchetype) { - etox = new (C) UncheckedExistentialToArchetypeExpr(sub, - expr->getLoc(), - expr->getBangLoc(), - expr->getTypeLoc()); + return CheckedCastKind::ExistentialToArchetype; } else if (tc.isConvertibleTo(toType, fromType)) { - etox = new (C) UncheckedExistentialToConcreteExpr(sub, - expr->getLoc(), - expr->getBangLoc(), - expr->getTypeLoc()); + return CheckedCastKind::ExistentialToConcrete; } else { tc.diagnose(expr->getLoc(), diag::downcast_from_existential_to_unrelated, origFromType, toType) .highlight(sub->getSourceRange()) - .highlight(expr->getTypeLoc().getSourceRange()); - return nullptr; + .highlight(expr->getCastTypeLoc().getSourceRange()); + return CheckedCastKind::Unresolved; } - etox->setType(expr->getType()); - return etox; } // - convert an archetype to a concrete type fulfilling its constraints. @@ -1561,15 +1529,10 @@ namespace { diag::downcast_from_archetype_to_unrelated, origFromType, toType) .highlight(sub->getSourceRange()) - .highlight(expr->getTypeLoc().getSourceRange()); - return nullptr; + .highlight(expr->getCastTypeLoc().getSourceRange()); + return CheckedCastKind::Unresolved; } - auto *atoc = new (C) UncheckedArchetypeToConcreteExpr(sub, - expr->getLoc(), - expr->getBangLoc(), - expr->getTypeLoc()); - atoc->setType(expr->getType()); - return atoc; + return CheckedCastKind::ArchetypeToConcrete; } // - convert from a superclass to an archetype. @@ -1578,17 +1541,13 @@ namespace { // Coerce to the supertype of the archetype. if (tc.convertToType(sub, toSuperType, cs.DC)) - return nullptr; + return CheckedCastKind::Unresolved; - // Construct the supertype-to-archetype cast. - auto *stoa = new (C) UncheckedSuperToArchetypeExpr(sub, - expr->getLoc(), - expr->getBangLoc(), - expr->getTypeLoc()); - stoa->setType(expr->getType()); - return stoa; + return CheckedCastKind::SuperToArchetype; } + // The remaining case is a class downcast. + assert(!fromArchetype && "archetypes should have been handled above"); assert(!toArchetype && "archetypes should have been handled above"); assert(!fromExistential && "existentials should have been handled above"); @@ -1599,43 +1558,81 @@ namespace { tc.diagnose(expr->getLoc(), diag::downcast_to_unrelated, origFromType, toType) .highlight(sub->getSourceRange()) - .highlight(expr->getTypeLoc().getSourceRange()); - return nullptr; + .highlight(expr->getCastTypeLoc().getSourceRange()); + return CheckedCastKind::Unresolved; } - // Okay, we're done. + return CheckedCastKind::Downcast; + } + + Expr *visitIsaExpr(IsaExpr *expr) { + CheckedCastKind castKind = checkCheckedCastExpr(expr); + switch (castKind) { + // Invalid type check. + case CheckedCastKind::Unresolved: + return nullptr; + // Check is trivially true. + case CheckedCastKind::InvalidCoercible: + cs.getTypeChecker().diagnose(expr->getLoc(), diag::isa_is_always_true, + expr->getSubExpr()->getType(), + expr->getCastTypeLoc().getType()); + break; + + // Valid checks. + case CheckedCastKind::Downcast: + case CheckedCastKind::SuperToArchetype: + case CheckedCastKind::ArchetypeToArchetype: + case CheckedCastKind::ArchetypeToConcrete: + case CheckedCastKind::ExistentialToArchetype: + case CheckedCastKind::ExistentialToConcrete: + expr->setCastKind(castKind); + break; + } return expr; } - Expr *visitUncheckedSuperToArchetypeExpr( - UncheckedSuperToArchetypeExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Expr *visitUncheckedArchetypeToArchetypeExpr( - UncheckedArchetypeToArchetypeExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Expr *visitUncheckedArchetypeToConcreteExpr( - UncheckedArchetypeToConcreteExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Expr *visitUncheckedExistentialToArchetypeExpr( - UncheckedExistentialToArchetypeExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Expr *visitUncheckedExistentialToConcreteExpr( - UncheckedExistentialToConcreteExpr *expr) { - llvm_unreachable("Already type-checked"); - } - - Expr *visitIsSubtypeExpr(IsSubtypeExpr *expr) { - expr->setType(simplifyType(expr->getType())); - - auto &tc = cs.getTypeChecker(); - Expr *sub = tc.coerceToRValue(expr->getSubExpr()); - if (!sub) return nullptr; - expr->setSubExpr(sub); + Expr *visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *expr){ + Type toType = expr->getCastTypeLoc().getType(); + expr->setType(toType); + CheckedCastKind castKind = checkCheckedCastExpr(expr); + switch (castKind) { + /// Invalid cast. + case CheckedCastKind::Unresolved: + return nullptr; + /// Cast trivially succeeds. Emit a fixit and reduce to a coercion. + case CheckedCastKind::InvalidCoercible: { + // Only complain if the cast was explicitly generated. + // FIXME: This leniency is here for the Clang module importer, + // which doesn't necessarily know whether it needs to force the + // cast or not. instancetype should eliminate the need for it. + if (!expr->isImplicit()) { + cs.getTypeChecker().diagnose(expr->getLoc(), + diag::downcast_to_supertype, + expr->getSubExpr()->getType(), + expr->getCastTypeLoc().getType()) + .highlight(expr->getSubExpr()->getSourceRange()) + .highlight(expr->getCastTypeLoc().getSourceRange()) + .fixItRemove(SourceRange(expr->getBangLoc())); + } + + Expr *coerce = new (cs.getASTContext()) CoerceExpr(expr->getSubExpr(), + expr->getLoc(), + expr->getCastTypeLoc()); + coerce->setType(expr->getType()); + return coerce; + } + + // Valid casts. + case CheckedCastKind::Downcast: + case CheckedCastKind::SuperToArchetype: + case CheckedCastKind::ArchetypeToArchetype: + case CheckedCastKind::ArchetypeToConcrete: + case CheckedCastKind::ExistentialToArchetype: + case CheckedCastKind::ExistentialToConcrete: + expr->setCastKind(castKind); + break; + } return expr; } @@ -2498,10 +2495,10 @@ Expr *ConstraintSystem::applySolution(const Solution &solution, return { false, expr }; } - // For unchecked downcast expressions, the subexpression is checked + // For checked cast expressions, the subexpression is checked // separately. - if (auto unchecked = dyn_cast(expr)) { - return { false, Rewriter.visitUncheckedDowncastExpr(unchecked) }; + if (auto unchecked = dyn_cast(expr)) { + return { false, Rewriter.visit(unchecked) }; } // For a default-value expression, do nothing. diff --git a/lib/Sema/TypeCheckConstraintsGen.cpp b/lib/Sema/TypeCheckConstraintsGen.cpp index 3839f58a920..83d418a1710 100644 --- a/lib/Sema/TypeCheckConstraintsGen.cpp +++ b/lib/Sema/TypeCheckConstraintsGen.cpp @@ -856,67 +856,21 @@ namespace { Type visitCoerceExpr(CoerceExpr *expr) { // FIXME: Could split the system here. - Type ty = expr->getTypeLoc().getType(); + Type ty = expr->getCastTypeLoc().getType(); CS.addConstraint(ConstraintKind::Conversion, expr->getSubExpr()->getType(), ty, CS.getConstraintLocator(expr, { })); return ty; } - Type visitUncheckedDowncastExpr(UncheckedDowncastExpr *expr) { + Type visitUnconditionalCheckedCastExpr(UnconditionalCheckedCastExpr *expr) { // FIXME: Open this type. - return expr->getTypeLoc().getType(); + return expr->getCastTypeLoc().getType(); } - Type visitUncheckedSuperToArchetypeExpr( - UncheckedSuperToArchetypeExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Type visitUncheckedArchetypeToArchetypeExpr( - UncheckedArchetypeToArchetypeExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Type visitUncheckedArchetypeToConcreteExpr( - UncheckedArchetypeToConcreteExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Type visitUncheckedExistentialToArchetypeExpr( - UncheckedExistentialToArchetypeExpr *expr) { - llvm_unreachable("Already type-checked"); - } - Type visitUncheckedExistentialToConcreteExpr( - UncheckedExistentialToConcreteExpr *expr) { - llvm_unreachable("Already type-checked"); - } - - Type visitIsSubtypeExpr(IsSubtypeExpr *expr) { - ASTContext &C = CS.getASTContext(); - - // The subexpression must be castable to the destination type. - auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { })); - CS.addConstraint(ConstraintKind::EqualRvalue, tv, - expr->getSubExpr()->getType(), - CS.getConstraintLocator(expr, ConstraintLocator::RvalueAdjustment)); - - CS.addConstraint(ConstraintKind::Subtype, - expr->getTypeLoc().getType(), tv); - + Type visitIsaExpr(IsaExpr *expr) { // The result is Bool. - auto &tc = CS.getTypeChecker(); - UnqualifiedLookup boolLookup(C.getIdentifier("Bool"), - &tc.TU); - if (!boolLookup.isSuccess()) { - tc.diagnose(expr->getLoc(), diag::bool_type_broken); - return nullptr; - } - TypeDecl *tyDecl = boolLookup.getSingleTypeResult(); - - if (!tyDecl) { - tc.diagnose(expr->getLoc(), diag::bool_type_broken); - return nullptr; - } - - return tyDecl->getDeclaredType(); + return CS.getTypeChecker().lookupBoolType(); } Type visitAssignExpr(AssignExpr *expr) { @@ -1036,10 +990,10 @@ namespace { return { false, expr }; } - // For unchecked downcast expressions, we visit the subexpression + // For checked cast expressions, we visit the subexpression // separately. - if (auto unchecked = dyn_cast(expr)) { - auto type = CG.visitUncheckedDowncastExpr(unchecked); + if (auto unchecked = dyn_cast(expr)) { + auto type = CG.visit(unchecked); expr->setType(type); return { false, expr }; } diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 981713760f9..67d3adf9223 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -146,12 +146,8 @@ static InfixData getInfixData(TypeChecker &TC, Expr *E) { // Assignment has fixed precedence. assert(!assign->isFolded() && "already folded assign expr in sequence?!"); return InfixData(90, Associativity::Right); - } else if (auto *is = dyn_cast(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(E)) { - // 'as' casts have fixed precedence. + // 'as' and 'is' casts have fixed precedence. assert(!as->isFolded() && "already folded 'as' expr in sequence?!"); return InfixData(95, Associativity::None); } else if (DeclRefExpr *DRE = dyn_cast(E)) { @@ -198,16 +194,8 @@ static Expr *makeBinOp(TypeChecker &TC, Expr *Op, Expr *LHS, Expr *RHS) { return assign; } - if (auto *is = dyn_cast(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(Op)) { - // Resolve the 'as' expression. + // Resolve the 'as' or 'is' expression. assert(!as->isFolded() && "already folded 'as' expr in sequence?!"); assert(RHS == as && "'as' with non-type RHS?!"); as->setSubExpr(LHS); diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 3e794c68c13..8ecb3cf3757 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -187,6 +187,24 @@ ProtocolDecl *TypeChecker::getLiteralProtocol(Expr *expr) { llvm_unreachable("Unhandled literal kind"); } +Type TypeChecker::lookupBoolType() { + return boolType.cache([&]{ + UnqualifiedLookup boolLookup(Context.getIdentifier("Bool"), &TU); + if (!boolLookup.isSuccess()) { + diagnose(SourceLoc(), diag::bool_type_broken); + return Type(); + } + TypeDecl *tyDecl = boolLookup.getSingleTypeResult(); + + if (!tyDecl) { + diagnose(SourceLoc(), diag::bool_type_broken); + return Type(); + } + + return tyDecl->getDeclaredType(); + }); +} + /// \brief Check for circular inheritance of protocols. /// /// \param Path The circular path through the protocol inheritance hierarchy, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 752a2dc6786..2db7beb8ec1 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -267,6 +267,8 @@ private: /// implicitly defined. llvm::DenseSet structsNeedingImplicitDefaultConstructor; + Optional boolType; + public: /// \brief Determine whether the given type can be default-initialized. /// @@ -449,6 +451,9 @@ public: /// \returns true if any members were found, false otherwise. bool lookupConstructors(Type type,SmallVectorImpl &constructors); + /// \brief Look up the Bool type in the standard library. + Type lookupBoolType(); + /// @} /// \name Overload resolution