diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index a6f892029a243..530bd7d66bd91 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -589,6 +589,9 @@ class ASTContext final { /// Retrieve the type Swift.AnyObject as a constraint. CanType getAnyObjectConstraint() const; + /// Retrieve the type Swift.Reflectable as a constraint. + CanType getReflectableConstraint() const; + /// Retrieve the type Swift.AnyObject as an existential type. CanType getAnyObjectType() const; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index fce002173c8a6..fa9016b05903e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5143,6 +5143,8 @@ class ProtocolDecl final : public NominalTypeDecl { /// True if this protocol can only be conformed to by class types. bool requiresClass() const; + bool inheritsReflectable() const; + /// Determine whether an existential conforming to this protocol can be /// matched with a generic type parameter constrained to this protocol. /// This is only permitted if there is nothing "non-trivial" that we diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 06723d7a3b931..ee43d97f642ab 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7708,5 +7708,13 @@ ERROR(referencebindings_binding_must_be_to_lvalue,none, ERROR(result_depends_on_no_result,none, "Incorrect use of %0 with no result", (StringRef)) +//------------------------------------------------------------------------------ +// MARK: Reflectable +//------------------------------------------------------------------------------ + +ERROR(type_does_not_conform_reflectable_decl_owner,none, + "%kind0 requires that %1 be a Reflectable type", + (const ValueDecl *, Type, Type)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/ExistentialLayout.h b/include/swift/AST/ExistentialLayout.h index dd3286e91b944..977fd4de1f54e 100644 --- a/include/swift/AST/ExistentialLayout.h +++ b/include/swift/AST/ExistentialLayout.h @@ -31,6 +31,7 @@ struct ExistentialLayout { ExistentialLayout() { hasExplicitAnyObject = false; + hasExplicitReflectable = false; hasInverseCopyable = false; containsNonObjCProtocol = false; containsParameterized = false; @@ -47,6 +48,9 @@ struct ExistentialLayout { /// Whether the existential contains an explicit '& AnyObject' constraint. bool hasExplicitAnyObject : 1; + /// Whether the existential contains an explicit '& Reflectable' constraint. + bool hasExplicitReflectable : 1; + /// Whether the existential contains an explicit '& ~Copyable' constraint. bool hasInverseCopyable : 1; @@ -71,6 +75,8 @@ struct ExistentialLayout { bool isAnyObject() const; + bool isReflectable() const; + bool isObjC() const { // FIXME: Does the superclass have to be @objc? return ((explicitSuperclass || diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index fae1dc6cd273a..e8f6eb3e56112 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -89,7 +89,7 @@ enum class SwiftAsyncFramePointerKind : unsigned { }; enum class ReflectionMetadataMode : unsigned { - None, ///< Don't emit reflection metadata at all. + OptIn, ///< Reflection is emitted only for Reflectable nominal types. DebuggerOnly, ///< Emit reflection metadata for the debugger, don't link them /// into runtime metadata and don't force them to stay alive. Runtime, ///< Make reflection metadata fully available. diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 8ca7e73bf473d..922300fdf46f8 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -177,6 +177,7 @@ IDENTIFIER_WITH_NAME(RefCountedObjectLayout, "_RefCountedObject") IDENTIFIER_WITH_NAME(NativeRefCountedObjectLayout, "_NativeRefCountedObject") IDENTIFIER_WITH_NAME(ClassLayout, "_Class") IDENTIFIER_WITH_NAME(NativeClassLayout, "_NativeClass") +IDENTIFIER_WITH_NAME(Reflectable, "Reflectable") // Operators IDENTIFIER_WITH_NAME(MatchOperator, "~=") diff --git a/include/swift/AST/LayoutConstraint.h b/include/swift/AST/LayoutConstraint.h index 7df4730fdb8b6..d111f16cc80f9 100644 --- a/include/swift/AST/LayoutConstraint.h +++ b/include/swift/AST/LayoutConstraint.h @@ -100,6 +100,10 @@ class LayoutConstraintInfo return isClass(Kind); } + bool isReflectable() const { + return isReflectable(Kind); + } + bool isNativeClass() const { return isNativeClass(Kind); } @@ -194,6 +198,8 @@ class LayoutConstraintInfo static bool isClass(LayoutConstraintKind Kind); + static bool isReflectable(LayoutConstraintKind Kind); + static bool isNativeClass(LayoutConstraintKind Kind); static bool isRefCounted(LayoutConstraintKind Kind); @@ -217,6 +223,7 @@ class LayoutConstraintInfo static LayoutConstraintInfo ClassConstraintInfo; static LayoutConstraintInfo NativeClassConstraintInfo; static LayoutConstraintInfo TrivialConstraintInfo; + static LayoutConstraintInfo ReflectableConstraintInfo; }; /// A wrapper class containing a reference to the actual LayoutConstraintInfo diff --git a/include/swift/AST/LayoutConstraintKind.h b/include/swift/AST/LayoutConstraintKind.h index 63eae5418ceb1..5dc9f3550dd7f 100644 --- a/include/swift/AST/LayoutConstraintKind.h +++ b/include/swift/AST/LayoutConstraintKind.h @@ -39,7 +39,9 @@ enum class LayoutConstraintKind : uint8_t { RefCountedObject, // It is a layout constraint representing a native reference counted object. NativeRefCountedObject, - LastLayout = NativeRefCountedObject, + // It is a layout constraint representing type that has reflection metadata available at runtime. + Reflectable, + LastLayout = Reflectable, }; #endif diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 45f38444e686f..02f3f3f835ac7 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -599,7 +599,7 @@ struct InheritedNominalEntry : Located { void getDirectlyInheritedNominalTypeDecls( llvm::PointerUnion decl, unsigned i, llvm::SmallVectorImpl &result, - bool &anyObject); + bool &anyObject, bool &reflectable); /// Retrieve the set of nominal type declarations that are directly /// "inherited" by the given declaration, looking through typealiases @@ -608,7 +608,7 @@ void getDirectlyInheritedNominalTypeDecls( /// If we come across the AnyObject type, set \c anyObject true. SmallVector getDirectlyInheritedNominalTypeDecls( llvm::PointerUnion decl, - bool &anyObject); + bool &anyObject, bool &reflectable); /// Retrieve the set of nominal type declarations that appear as the /// constraint type of any "Self" constraints in the where clause of the diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index a6daff4e7a233..a93168bd4dc08 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -4644,6 +4644,24 @@ class UniqueUnderlyingTypeSubstitutionsRequest void cacheResult(llvm::Optional) const; }; +/// Determine if protocol inherits Reflectable. +class InheritsReflectableProtocolRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + +public: + // Separate caching. + bool isCached() const { return true; } +}; + #define SWIFT_TYPEID_ZONE TypeChecker #define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def" #include "swift/Basic/DefineTypeIDZone.h" diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index b46788190ea79..ea834888ad753 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -530,3 +530,5 @@ SWIFT_REQUEST(TypeChecker, SemanticDeclAttrsRequest, SWIFT_REQUEST(TypeChecker, UniqueUnderlyingTypeSubstitutionsRequest, llvm::Optional(const Decl *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, InheritsReflectableProtocolRequest, bool(ProtocolDecl *), + Cached, NoLocationInfo) \ No newline at end of file diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 26ba41b931159..cdf339e9a6a29 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -214,7 +214,7 @@ class RecursiveTypeProperties { /// Does a type with these properties structurally contain an /// archetype from an opaque type declaration? bool hasOpaqueArchetype() const { return Bits & HasOpaqueArchetype; } - + /// Does a type with these properties have a type parameter somewhere in it? bool hasTypeParameter() const { return Bits & HasTypeParameter; } @@ -313,7 +313,7 @@ class RecursiveTypeProperties { inline RecursiveTypeProperties operator~(RecursiveTypeProperties::Property P) { return RecursiveTypeProperties(~unsigned(P)); } - + /// The result of a type trait check. enum class TypeTraitResult { /// The type cannot have the trait. @@ -360,11 +360,11 @@ class ErrorType; /// See TypeNodes.def for a succinct description of the full class hierarchy. class alignas(1 << TypeAlignInBits) TypeBase : public ASTAllocated::type> { - + friend class ASTContext; TypeBase(const TypeBase&) = delete; void operator=(const TypeBase&) = delete; - + /// This union contains to the ASTContext for canonical types, and is /// otherwise lazily populated by ASTContext when the canonical form of a /// non-canonical type is requested. The disposition of the union is stored @@ -457,10 +457,12 @@ class alignas(1 << TypeAlignInBits) TypeBase Representation : 2 ); - SWIFT_INLINE_BITFIELD_FULL(ProtocolCompositionType, TypeBase, 1+32, + SWIFT_INLINE_BITFIELD_FULL(ProtocolCompositionType, TypeBase, 1+1+32, /// Whether we have an explicitly-stated class constraint not /// implied by any of our members. HasExplicitAnyObject : 1, + /// Whether we have an explicitly-stated Reflectable constraint. + HasExplicitReflectable : 1, : NumPadBits, @@ -545,7 +547,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// isCanonical - Return true if this is a canonical type. bool isCanonical() const { return Bits.TypeBase.IsCanonical; } - + /// hasCanonicalTypeComputed - Return true if we've already computed a /// canonical version of this type. bool hasCanonicalTypeComputed() const { return !CanonicalType.isNull(); } @@ -589,11 +591,11 @@ class alignas(1 << TypeAlignInBits) TypeBase /// To compare sugar, check for pointer equality of the underlying TypeBase * /// values, obtained by calling getPointer(). bool isEqual(Type Other) const; - + /// getDesugaredType - If this type is a sugared type, remove all levels of /// sugar until we get down to a non-sugar type. TypeBase *getDesugaredType(); - + /// If this type is a (potentially sugared) type of the specified kind, remove /// the minimal amount of sugar required to get a pointer to the type. template @@ -609,7 +611,7 @@ class alignas(1 << TypeAlignInBits) TypeBase static_assert(!isSugaredType(), "isa desugars types"); return isa(getDesugaredType()); } - + template T *castTo() { static_assert(!isSugaredType(), "castTo desugars types"); @@ -631,7 +633,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Is this an uninhabited type, such as 'Never' or '(Never, Int)'? bool isStructurallyUninhabited(); - + /// Is this the 'Any' type? bool isAny(); @@ -659,7 +661,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// - a class-bounded existential type /// - a dynamic Self type bool isAnyClassReferenceType(); - + /// allowsOwnership() - Are variables of this type permitted to have /// ownership attributes? bool allowsOwnership(const GenericSignatureImpl *sig = nullptr); @@ -687,7 +689,7 @@ class alignas(1 << TypeAlignInBits) TypeBase bool hasArchetype() const { return getRecursiveProperties().hasArchetype(); } - + /// Determine whether the type involves an opened existential archetype. bool hasOpenedExistential() const { return getRecursiveProperties().hasOpenedExistential(); @@ -834,7 +836,7 @@ class alignas(1 << TypeAlignInBits) TypeBase bool hasLValueType() { return getRecursiveProperties().isLValue(); } - + /// Is this a first-class value type, meaning it is not an LValueType or an /// InOutType. bool isMaterializable(); @@ -932,7 +934,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// \p kind must not be a raw pointer kind, since that would discard the /// current type. Type wrapInPointer(PointerTypeKind kind); - + /// Determines the element type of a known Unsafe[Mutable][Raw]BufferPointer /// variant, or returns null if the type is not a buffer pointer. Type getAnyBufferPointerElementType(BufferPointerTypeKind &BPTK); @@ -983,7 +985,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Check if this type is equal to Builtin.IntN. bool isBuiltinIntegerType(unsigned bitWidth); - + /// Check if this is a nominal type defined at the top level of the Swift module bool isStdlibType(); @@ -1002,7 +1004,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// If this is a struct type or a bound generic struct type, returns /// the (possibly generic) class. StructDecl *getStructOrBoundGenericStruct(); - + /// If this is an enum or a bound generic enum type, returns the /// (possibly generic) enum. EnumDecl *getEnumOrBoundGenericEnum(); @@ -1025,6 +1027,8 @@ class alignas(1 << TypeAlignInBits) TypeBase /// - classes bool satisfiesClassConstraint(); + bool satisfiesReflectableConstraint(); + /// Determine whether this type can be used as a base type for AST /// name lookup, which is the case for nominal types, existential types, /// archetypes, and tuples. @@ -1059,7 +1063,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Return true if the specified type or a super-class/super-protocol has the /// @dynamicMemberLookup attribute on it. bool hasDynamicMemberLookupAttribute(); - + /// Return true if the specified type or a super-class/super-protocol has the /// @dynamicCallable attribute on it. bool hasDynamicCallableAttribute(); @@ -1128,7 +1132,7 @@ class alignas(1 << TypeAlignInBits) TypeBase /// True if this type contains archetypes that could be substituted with /// concrete types to form the argument type. bool isBindableTo(Type ty); - + /// Visit this type and the argument type in parallel, invoking the callback /// function with each archetype-to-substituted-type binding. The callback /// may return a new type to substitute into the result type, or return @@ -1405,6 +1409,8 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Whether this is the AnyObject type. bool isAnyObject(); + bool isReflectable(); + /// Return true if this type is potentially an AnyObject existential after /// substitution. bool isPotentiallyAnyObject(); @@ -1460,7 +1466,7 @@ class alignas(1 << TypeAlignInBits) TypeBase TypeTraitResult canBeClass(); Type replaceSubstitutedSILFunctionTypesWithUnsubstituted(SILModule &M) const; // in SILType.cpp - + /// Return the tangent space of the given type, if it exists. Otherwise, /// return `None`. llvm::Optional @@ -1640,7 +1646,7 @@ class UnresolvedType : public TypeBase { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(UnresolvedType, Type) - + /// BuiltinType - An abstract class for all the builtin types. class BuiltinType : public TypeBase { protected: @@ -1869,24 +1875,24 @@ class BuiltinIntegerWidth { /// The size of a pointer on the target system. PointerWidth = ~3U, - + Least_SpecialValue = ~3U, }; - + unsigned RawValue; - + friend struct llvm::DenseMapInfo; - + /// Private constructor from a raw symbolic value. explicit BuiltinIntegerWidth(unsigned RawValue) : RawValue(RawValue) {} public: BuiltinIntegerWidth() : RawValue(0) {} - + static BuiltinIntegerWidth fixed(unsigned bitWidth) { assert(bitWidth < Least_SpecialValue && "invalid bit width"); return BuiltinIntegerWidth(bitWidth); } - + static BuiltinIntegerWidth pointer() { return BuiltinIntegerWidth(PointerWidth); } @@ -1894,7 +1900,7 @@ class BuiltinIntegerWidth { static BuiltinIntegerWidth arbitrary() { return BuiltinIntegerWidth(ArbitraryWidth); } - + /// Is this a fixed width? bool isFixedWidth() const { return RawValue < Least_SpecialValue; } @@ -1903,13 +1909,13 @@ class BuiltinIntegerWidth { assert(isFixedWidth() && "not fixed-width"); return RawValue; } - + /// Is this the abstract target pointer width? bool isPointerWidth() const { return RawValue == PointerWidth; } /// Is this the abstract arbitrary-width value? bool isArbitraryWidth() const { return RawValue == ArbitraryWidth; } - + /// Get the least supported value for the width. /// /// FIXME: This should be build-configuration-dependent. @@ -1922,7 +1928,7 @@ class BuiltinIntegerWidth { return 1; llvm_unreachable("impossible width value"); } - + /// Get the greatest supported value for the width. /// /// FIXME: This should be build-configuration-dependent. @@ -1941,7 +1947,7 @@ class BuiltinIntegerWidth { /// If the radix is 0, it is autosensed. APInt parse(StringRef text, unsigned radix, bool negate, bool *hadError = nullptr) const; - + friend bool operator==(BuiltinIntegerWidth a, BuiltinIntegerWidth b) { return a.RawValue == b.RawValue; } @@ -1975,50 +1981,50 @@ class BuiltinIntegerType : public AnyBuiltinIntegerType { BuiltinIntegerWidth Width; BuiltinIntegerType(BuiltinIntegerWidth BitWidth, const ASTContext &C) : AnyBuiltinIntegerType(TypeKind::BuiltinInteger, C), Width(BitWidth) {} - + public: /// Get a builtin integer type. static BuiltinIntegerType *get(BuiltinIntegerWidth BitWidth, const ASTContext &C); - + /// Get a builtin integer type of fixed width. static BuiltinIntegerType *get(unsigned BitWidth, const ASTContext &C) { return get(BuiltinIntegerWidth::fixed(BitWidth), C); } - + /// Get the target-pointer-width builtin integer type. static BuiltinIntegerType *getWordType(const ASTContext &C) { return get(BuiltinIntegerWidth::pointer(), C); } - + /// Return the bit width of the integer. Always returns a non-arbitrary /// width. BuiltinIntegerWidth getWidth() const { return Width; } - + /// Is the integer fixed-width? bool isFixedWidth() const { return Width.isFixedWidth(); } - + /// Is the integer fixed-width with the given width? bool isFixedWidth(unsigned width) const { return Width.isFixedWidth() && Width.getFixedWidth() == width; } - + /// Get the fixed integer width. Fails if the integer has abstract width. unsigned getFixedWidth() const { return Width.getFixedWidth(); } - + /// Return the least supported width of the integer. /// /// FIXME: This should be build-configuration-dependent. unsigned getLeastWidth() const { return Width.getLeastWidth(); } - + /// Return the greatest supported width of the integer. /// /// FIXME: This should be build-configuration-dependent. @@ -2064,12 +2070,12 @@ class BuiltinFloatType : public BuiltinType { }; private: FPKind Kind; - + BuiltinFloatType(FPKind Kind, const ASTContext &C) : BuiltinType(TypeKind::BuiltinFloat, C), Kind(Kind) {} public: - - /// getFPKind - Get the + + /// getFPKind - Get the FPKind getFPKind() const { return Kind; } @@ -2093,7 +2099,7 @@ class BuiltinFloatType : public BuiltinType { } }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinFloatType, BuiltinType) - + /// An abstract type for all sugared types to make getDesugaredType() fast by /// sharing field offsets and logic for the fast path. class SugarType : public TypeBase { @@ -2311,7 +2317,7 @@ class ParameterTypeFlags { return ParameterTypeFlags(isConst ? value | ParameterTypeFlags::CompileTimeConst : value - ParameterTypeFlags::CompileTimeConst); } - + ParameterTypeFlags withShared(bool isShared) const { return withOwnershipSpecifier(isShared ? ParamSpecifier::LegacyShared : ParamSpecifier::Default); @@ -2414,14 +2420,14 @@ class YieldTypeFlags { ParamSpecifier getOwnershipSpecifier() const { return ParamSpecifier((value.toRaw() & Specifier) >> SpecifierShift); } - + ValueOwnership getValueOwnership() const; YieldTypeFlags withInOut(bool isInout) const { return withOwnershipSpecifier(isInout ? ParamSpecifier::InOut : ParamSpecifier::Default); } - + YieldTypeFlags withShared(bool isShared) const { return withOwnershipSpecifier(isShared ? ParamSpecifier::LegacyShared : ParamSpecifier::Default); @@ -2481,7 +2487,7 @@ class TupleTypeElt { Type ElementType; friend class TupleType; - + public: TupleTypeElt() = default; TupleTypeElt(Type ty, Identifier name = Identifier()); @@ -2518,7 +2524,7 @@ typedef ArrayRefView class TupleType final : public TypeBase, public llvm::FoldingSetNode, private llvm::TrailingObjects { friend TrailingObjects; - + public: /// get - Return the uniqued tuple type with the specified elements. /// @@ -2555,7 +2561,7 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode, TupleEltTypeArrayRef getElementTypes() const { return TupleEltTypeArrayRef(getElements()); } - + /// getNamedElementId - If this tuple has an element with the specified name, /// return the element index, otherwise return -1. int getNamedElementId(Identifier I) const; @@ -2568,9 +2574,9 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode, void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElements()); } - static void Profile(llvm::FoldingSetNodeID &ID, + static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef Elements); - + bool containsPackExpansionType() const; private: @@ -2657,7 +2663,7 @@ typedef ArrayRefView CanTypeArrayRef; /// given type arguments. class BoundGenericType : public NominalOrBoundGenericNominalType, public llvm::FoldingSetNode { - + /// Retrieve the intrusive pointer storage from the subtype const Type *getTrailingObjectsPointer() const; Type *getTrailingObjectsPointer() { @@ -2778,7 +2784,7 @@ class BoundGenericStructType final : public BoundGenericType, BoundGenericStructType(StructDecl *theDecl, Type parent, ArrayRef genericArgs, const ASTContext *context, RecursiveTypeProperties properties) - : BoundGenericType(TypeKind::BoundGenericStruct, + : BoundGenericType(TypeKind::BoundGenericStruct, reinterpret_cast(theDecl), parent, genericArgs, context, properties) {} friend class BoundGenericType; @@ -2863,7 +2869,7 @@ class StructType : public NominalType { static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Struct; } - + private: StructType(StructDecl *TheDecl, Type Parent, const ASTContext &Ctx, RecursiveTypeProperties properties); @@ -2886,7 +2892,7 @@ class ClassType : public NominalType { static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Class; } - + private: ClassType(ClassDecl *TheDecl, Type Parent, const ASTContext &Ctx, RecursiveTypeProperties properties); @@ -2910,7 +2916,7 @@ enum class MetatypeRepresentation : char { /// struct and enum members is completely static. Thin, /// A thick metatype refers to a complete metatype representation - /// that allows introspection and dynamic dispatch. + /// that allows introspection and dynamic dispatch. /// /// Thick metatypes are used for class and existential metatypes, /// which permit dynamic behavior. @@ -2939,7 +2945,7 @@ class AnyMetatypeType : public TypeBase { bool hasRepresentation() const { return Bits.AnyMetatypeType.Representation > 0; } - + /// Retrieve the metatype representation. /// /// The metatype representation is a SIL-only property. Thin @@ -2998,7 +3004,7 @@ class MetatypeType : public AnyMetatypeType { static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Metatype; } - + private: MetatypeType(Type T, const ASTContext *C, RecursiveTypeProperties properties, llvm::Optional repr); @@ -3045,7 +3051,7 @@ class ExistentialMetatypeType : public AnyMetatypeType { } Type getExistentialInstanceType(); - + private: ExistentialMetatypeType(Type T, const ASTContext *C, RecursiveTypeProperties properties, @@ -3062,13 +3068,13 @@ BEGIN_CAN_TYPE_WRAPPER(ExistentialMetatypeType, AnyMetatypeType) } PROXY_CAN_TYPE_SIMPLE_GETTER(getExistentialInstanceType) END_CAN_TYPE_WRAPPER(ExistentialMetatypeType, AnyMetatypeType) - + /// ModuleType - This is the type given to a module value, e.g. the "Builtin" in /// "Builtin.int". This is typically given to a ModuleExpr, but can also exist /// on ParenExpr, for example. class ModuleType : public TypeBase { ModuleDecl *const TheModule; - + public: /// get - Return the ModuleType for the specified module. static ModuleType *get(ModuleDecl *M); @@ -3079,7 +3085,7 @@ class ModuleType : public TypeBase { static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Module; } - + private: ModuleType(ModuleDecl *M, const ASTContext &Ctx) : TypeBase(TypeKind::Module, &Ctx, // Always canonical @@ -3088,7 +3094,7 @@ class ModuleType : public TypeBase { } }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(ModuleType, Type) - + /// The type given to a dynamic \c Self return type. /// /// Example: @@ -3098,7 +3104,7 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(ModuleType, Type) /// }; /// \endcode /// -/// In this example, \c Self is represented by a +/// In this example, \c Self is represented by a /// \c DynamicSelfType node whose self type is \c X. class DynamicSelfType : public TypeBase { Type SelfType; @@ -3114,7 +3120,7 @@ class DynamicSelfType : public TypeBase { static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::DynamicSelf; } - + private: DynamicSelfType(Type selfType, const ASTContext &ctx, RecursiveTypeProperties properties) @@ -3143,7 +3149,7 @@ END_CAN_TYPE_WRAPPER(DynamicSelfType, Type) /// represented at the binary level as a single function pointer. class AnyFunctionType : public TypeBase { const Type Output; - + public: using Representation = FunctionTypeRepresentation; @@ -3162,7 +3168,7 @@ class AnyFunctionType : public TypeBase { /// The type of the parameter. For a variadic parameter, this is the /// element type. Type Ty; - + /// The label associated with the parameter, if any. Identifier Label; @@ -3175,10 +3181,10 @@ class AnyFunctionType : public TypeBase { /// - `_ name2: Int` has internal label `name2` /// - `name: Int` has no internal label Identifier InternalLabel; - + /// Parameter specific flags. ParameterTypeFlags Flags = {}; - + public: /// FIXME: Remove this. Return the formal type of the parameter in the /// function type, including the InOutType if there is one. @@ -3222,18 +3228,18 @@ class AnyFunctionType : public TypeBase { } Param getCanonical(CanGenericSignature genericSig) const; - + ParameterTypeFlags getParameterFlags() const { return Flags; } /// Whether the parameter is varargs bool isVariadic() const { return Flags.isVariadic(); } - + /// Whether the parameter is marked '@autoclosure' bool isAutoClosure() const { return Flags.isAutoClosure(); } - + /// Whether the parameter is marked 'inout' bool isInOut() const { return Flags.isInOut(); } - + /// Whether the parameter is marked 'shared' bool isShared() const { return Flags.isShared(); } @@ -3309,7 +3315,7 @@ class AnyFunctionType : public TypeBase { using ExtInfoBuilder = swift::ASTExtInfoBuilder; using CanParamArrayRef = ArrayRefView; - + class CanYield; class Yield { Type Ty; @@ -3426,7 +3432,7 @@ class AnyFunctionType : public TypeBase { unsigned getNumParams() const { return Bits.AnyFunctionType.NumParams; } GenericSignature getOptGenericSignature() const; - + bool hasClangTypeInfo() const { return Bits.AnyFunctionType.HasClangTypeInfo; } @@ -3749,7 +3755,7 @@ class FunctionType final return Type(); return getTrailingObjects()[hasGlobalActor()]; } - + void Profile(llvm::FoldingSetNodeID &ID) { llvm::Optional info = llvm::None; if (hasExtInfo()) @@ -3763,7 +3769,7 @@ class FunctionType final static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Function; } - + private: FunctionType(ArrayRef params, Type result, llvm::Optional info, const ASTContext *ctx, @@ -3846,13 +3852,13 @@ class GenericFunctionType final : public AnyFunctionType, private llvm::TrailingObjects { friend TrailingObjects; - + GenericSignature Signature; size_t numTrailingObjects(OverloadToken) const { return getNumParams(); } - + size_t numTrailingObjects(OverloadToken) const { return hasGlobalActor() + hasThrownError(); } @@ -3884,18 +3890,18 @@ class GenericFunctionType final : public AnyFunctionType, return Type(); return getTrailingObjects()[hasGlobalActor()]; } - + /// Retrieve the generic signature of this function type. GenericSignature getGenericSignature() const { return Signature; } - + /// Retrieve the generic parameters of this polymorphic function type. ArrayRef getGenericParams() const; /// Retrieve the requirements of this polymorphic function type. ArrayRef getRequirements() const; - + /// Substitute the given generic arguments into this generic /// function type and return the resulting non-generic type. FunctionType *substGenericArgs(SubstitutionMap subs, @@ -3935,7 +3941,7 @@ static CanGenericFunctionType get(CanGenericSignature sig, CanGenericSignature getGenericSignature() const { return CanGenericSignature(getPointer()->getGenericSignature()); } - + ArrayRef> getGenericParams() const { return getGenericSignature().getGenericParams(); } @@ -4153,7 +4159,7 @@ class SILParameterInfo { CanType getInterfaceType() const { return Type; } - + /// Return the type of a call argument matching this parameter. /// /// \c t must refer back to the function type this is a parameter for. @@ -4310,7 +4316,7 @@ enum class ResultConvention : uint8_t { /// The validity of the return value is dependent on the 'self' parameter, /// so it may be invalidated if that parameter is released. UnownedInnerPointer, - + /// This value has been (or may have been) returned autoreleased. /// The caller should make an effort to reclaim the autorelease. /// The type must be a class or class existential type, and this @@ -4369,7 +4375,7 @@ class SILResultInfo { CanType getInterfaceType() const { return Type; } - + /// The type of a return value corresponding to this result. /// /// \c t must refer back to the function type this is a parameter for. @@ -4536,7 +4542,7 @@ enum class SILCoroutineKind : uint8_t { /// It must not have normal results and may have arbitrary yield results. YieldMany, }; - + class SILFunctionConventions; @@ -5352,7 +5358,7 @@ class SILFunctionType final /// Return the unsubstituted function type equivalent to this type; that is, the type that has the same /// argument and result types as `this` type after substitutions, if any. CanSILFunctionType getUnsubstitutedType(SILModule &M) const; - + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), getCalleeConvention(), @@ -5402,18 +5408,18 @@ class SILBoxType final : public TypeBase, public llvm::FoldingSetNode // TODO: SILBoxTypes should be explicitly constructed in terms of specific // layouts. As a staging mechanism, we expose the old single-boxed-type // interface. - + static CanSILBoxType get(CanType BoxedType); static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::SILBox; } - + /// Produce a profile of this box, for use in a folding set. static void Profile(llvm::FoldingSetNodeID &id, SILLayout *Layout, SubstitutionMap Args); - + /// Produce a profile of this box, for use in a folding set. void Profile(llvm::FoldingSetNodeID &id) { Profile(id, getLayout(), getSubstitutions()); @@ -5453,7 +5459,7 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILMoveOnlyWrappedType, Type) class SILBlockStorageType; typedef CanTypeWrapper CanSILBlockStorageType; - + /// The SIL-only type @block_storage T, which represents the layout of an /// on-stack block that captures a value of type T. /// @@ -5461,20 +5467,20 @@ typedef CanTypeWrapper CanSILBlockStorageType; /// SILFunctionType, so it is only parsed and defined within the SIL library. class SILBlockStorageType : public TypeBase { CanType CaptureType; - + SILBlockStorageType(CanType CaptureType) : TypeBase(TypeKind::SILBlockStorage, &CaptureType->getASTContext(), CaptureType->getRecursiveProperties()), CaptureType(CaptureType) {} - + public: static CanSILBlockStorageType get(CanType CaptureType); - + CanType getCaptureType() const { return CaptureType; } // In SILType.h SILType getCaptureAddressType() const; - + static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::SILBlockStorage; } @@ -5641,7 +5647,7 @@ class UnarySyntaxSugarType : public SyntaxSugarType { T->getKind() <= TypeKind::Last_UnarySyntaxSugarType; } }; - + /// The type [T], which is always sugar for a library type. class ArraySliceType : public UnarySyntaxSugarType { ArraySliceType(const ASTContext &ctx, Type base, @@ -5687,7 +5693,7 @@ class DictionaryType : public SyntaxSugarType { // Syntax sugar types are never canonical. DictionaryType(const ASTContext &ctx, Type key, Type value, RecursiveTypeProperties properties) - : SyntaxSugarType(TypeKind::Dictionary, ctx, properties), + : SyntaxSugarType(TypeKind::Dictionary, ctx, properties), Key(key), Value(value) {} public: @@ -5788,7 +5794,7 @@ class ProtocolCompositionType final : public TypeBase, // TODO(kavon): this could probably be folded into the existing Bits field // or we could just store the InverseType's in the Members array. InvertibleProtocolSet Inverses; - + public: /// Retrieve an instance of a protocol composition type with the /// given set of members. A "hidden member" is an implicit constraint that @@ -5802,12 +5808,14 @@ class ProtocolCompositionType final : public TypeBase, /// treated as if \c AnyObject was a member. static Type get(const ASTContext &C, ArrayRef Members, InvertibleProtocolSet Inverses, - bool HasExplicitAnyObject); + bool HasExplicitAnyObject, + bool HasExplicitReflectable); /// Retrieve an instance of a protocol composition type with the /// given set of members. Assumes no inverses are present in \c Members. static Type get(const ASTContext &C, ArrayRef Members, - bool HasExplicitAnyObject); + bool HasExplicitAnyObject, + bool HasExplicitReflectable); /// Constructs a protocol composition corresponding to the `Any` type. static Type theAnyType(const ASTContext &C); @@ -5815,6 +5823,9 @@ class ProtocolCompositionType final : public TypeBase, /// Constructs a protocol composition corresponding to the `AnyObject` type. static Type theAnyObjectType(const ASTContext &C); + /// Constructs a protocol composition corresponding to the `Reflectable` type. + static Type theReflectableType(const ASTContext &C); + /// Canonical protocol composition types are minimized only to a certain /// degree to preserve ABI compatibility. This routine enables performing /// slower, but stricter minimization at need (e.g. redeclaration checking). @@ -5840,12 +5851,13 @@ class ProtocolCompositionType final : public TypeBase, InvertibleProtocolSet getInverses() const { return Inverses; } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getMembers(), getInverses(), hasExplicitAnyObject()); + Profile(ID, getMembers(), getInverses(), hasExplicitAnyObject(), hasExplicitReflectable()); } static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef Members, InvertibleProtocolSet Inverses, - bool HasExplicitAnyObject); + bool HasExplicitAnyObject, + bool HasExplicitReflectable); /// True if the composition requires the concrete conforming type to /// be a class, either via a directly-stated superclass constraint or @@ -5857,24 +5869,32 @@ class ProtocolCompositionType final : public TypeBase, return Bits.ProtocolCompositionType.HasExplicitAnyObject; } + /// True if the reflection requirement is stated directly via '& Reflectable'. + bool hasExplicitReflectable() const { + return Bits.ProtocolCompositionType.HasExplicitReflectable; + } + // Implement isa/cast/dyncast/etc. static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::ProtocolComposition; } - + private: static ProtocolCompositionType *build(const ASTContext &C, ArrayRef Members, InvertibleProtocolSet Inverses, - bool HasExplicitAnyObject); + bool HasExplicitAnyObject, + bool HasExplicitReflectable); ProtocolCompositionType(const ASTContext *ctx, ArrayRef members, InvertibleProtocolSet inverses, bool hasExplicitAnyObject, + bool hasExplicitReflectable, RecursiveTypeProperties properties) : TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx, properties), Inverses(inverses) { Bits.ProtocolCompositionType.HasExplicitAnyObject = hasExplicitAnyObject; + Bits.ProtocolCompositionType.HasExplicitReflectable = hasExplicitReflectable; Bits.ProtocolCompositionType.Count = members.size(); std::uninitialized_copy(members.begin(), members.end(), getTrailingObjects()); @@ -6111,7 +6131,7 @@ BEGIN_CAN_TYPE_WRAPPER(LValueType, Type) return CanLValueType(LValueType::get(type)); } END_CAN_TYPE_WRAPPER(LValueType, Type) - + /// InOutType - An inout qualified type is an argument to a function passed /// with an explicit "Address of" operator. It is read in and then written back /// to after the callee function is done. This also models the receiver of @@ -6119,17 +6139,17 @@ END_CAN_TYPE_WRAPPER(LValueType, Type) /// class InOutType : public TypeBase { Type ObjectTy; - + InOutType(Type objectTy, const ASTContext *canonicalContext, RecursiveTypeProperties properties) : TypeBase(TypeKind::InOut, canonicalContext, properties), ObjectTy(objectTy) {} - + public: static InOutType *get(Type type); - + Type getObjectType() const { return ObjectTy; } - + // Implement isa/cast/dyncast/etc. static bool classof(const TypeBase *type) { return type->getKind() == TypeKind::InOut; @@ -6168,7 +6188,7 @@ using ArchetypeTrailingObjects = llvm::TrailingObjects const Type *getSubclassTrailingObjects() const; - + template Type *getSubclassTrailingObjects() { const auto *constThis = this; @@ -6222,7 +6242,7 @@ class ArchetypeType : public SubstitutableType, return { getSubclassTrailingObjects(), static_cast(Bits.ArchetypeType.NumProtocols) }; } - + /// requiresClass - True if the type can only be substituted with class types. /// This is true if the type conforms to one or more class protocols or has /// a superclass constraint. @@ -6269,7 +6289,7 @@ class ArchetypeType : public SubstitutableType, /// Get the generic environment this archetype lives in. GenericEnvironment *getGenericEnvironment() const { return Environment; } - + /// Get the protocol/class existential type that most closely represents the /// set of constraints on this archetype. /// @@ -6294,7 +6314,7 @@ class ArchetypeType : public SubstitutableType, }; BEGIN_CAN_TYPE_WRAPPER(ArchetypeType, SubstitutableType) END_CAN_TYPE_WRAPPER(ArchetypeType, SubstitutableType) - + /// An archetype that represents a primary generic argument inside the generic /// context that binds it. class PrimaryArchetypeType final : public ArchetypeType, @@ -6302,7 +6322,7 @@ class PrimaryArchetypeType final : public ArchetypeType, { friend TrailingObjects; friend ArchetypeType; - + public: /// getNew - Create a new primary archetype with the given name. /// @@ -6555,7 +6575,7 @@ class OpenedArchetypeType final : public LocalArchetypeType, static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::OpenedArchetype; } - + private: OpenedArchetypeType(GenericEnvironment *environment, Type interfaceType, ArrayRef conformsTo, Type superclass, @@ -6640,7 +6660,7 @@ class ElementArchetypeType final : public LocalArchetypeType, static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::ElementArchetype; } - + private: ElementArchetypeType(const ASTContext &ctx, GenericEnvironment *environment, Type interfaceType, @@ -6672,7 +6692,7 @@ const Type *ArchetypeType::getSubclassTrailingObjects() const { } llvm_unreachable("unhandled ArchetypeType subclass?"); } - + /// Describes the type of a generic parameter. /// /// \sa GenericTypeParamDecl @@ -6697,7 +6717,7 @@ class GenericTypeParamType : public SubstitutableType { /// Get the name of the generic type parameter. Identifier getName() const; - + /// The depth of this generic type parameter, i.e., the number of outer /// levels of generic parameter lists that enclose this type parameter. /// @@ -6791,7 +6811,7 @@ class DependentMemberType : public TypeBase { AssociatedTypeDecl *getAssocType() const { return NameOrAssocType.dyn_cast(); } - + /// Substitute the base type, looking up our associated type in it if it is /// non-dependent. Returns null if the member could not be found in the new /// base. @@ -6918,15 +6938,15 @@ TypeVariableType : public TypeBase { } class Implementation; - + public: - + /// Create a new type variable whose implementation is constructed /// with the given arguments. template static TypeVariableType *getNew(const ASTContext &C, unsigned ID, Args &&...args); - + /// Retrieve the implementation data corresponding to this type /// variable. /// @@ -7375,7 +7395,7 @@ inline StructDecl *CanType::getStructOrBoundGenericStruct() const { if (auto boundTy = dyn_cast(*this)) return boundTy->getDecl(); - + return nullptr; } @@ -7389,7 +7409,7 @@ inline EnumDecl *CanType::getEnumOrBoundGenericEnum() const { if (auto boundTy = dyn_cast(*this)) return boundTy->getDecl(); - + return nullptr; } @@ -7573,19 +7593,19 @@ namespace llvm { template<> struct DenseMapInfo { using BuiltinIntegerWidth = swift::BuiltinIntegerWidth; - + static inline BuiltinIntegerWidth getEmptyKey() { return BuiltinIntegerWidth(BuiltinIntegerWidth::DenseMapEmpty); } - + static inline BuiltinIntegerWidth getTombstoneKey() { return BuiltinIntegerWidth(BuiltinIntegerWidth::DenseMapTombstone); } - + static unsigned getHashValue(BuiltinIntegerWidth w) { return DenseMapInfo::getHashValue(w.RawValue); } - + static bool isEqual(BuiltinIntegerWidth a, BuiltinIntegerWidth b) { return a == b; } diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 10145d0b5fd90..b1f6dd9656762 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -427,6 +427,7 @@ void decodeRequirement(NodePointer node, .Case("C", LayoutConstraintKind::Class) .Case("D", LayoutConstraintKind::NativeClass) .Case("T", LayoutConstraintKind::Trivial) + .Case("B", LayoutConstraintKind::Reflectable) .Cases("E", "e", LayoutConstraintKind::TrivialOfExactSize) .Cases("M", "m", LayoutConstraintKind::TrivialOfAtMostSize) .Default(llvm::None); diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 9f1573ddaa8f5..0b5c9274d7faa 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -560,6 +560,9 @@ def enable_anonymous_context_mangled_names : def disable_reflection_metadata : Flag<["-"], "disable-reflection-metadata">, HelpText<"Disable emission of reflection metadata for nominal types">; +def enable_opt_in_reflection_metadata : Flag<["-"], "enable-opt-in-reflection-metadata">, + HelpText<"Enable Opt-in emission of reflection metadata for nominal types">; + def reflection_metadata_for_debugger_only : Flag<["-"], "reflection-metadata-for-debugger-only">, HelpText<"Emit reflection metadata for debugger only, don't make them available at runtime">; diff --git a/include/swift/RemoteInspection/TypeRef.h b/include/swift/RemoteInspection/TypeRef.h index 28491c67719ce..be7a0601f6f46 100644 --- a/include/swift/RemoteInspection/TypeRef.h +++ b/include/swift/RemoteInspection/TypeRef.h @@ -421,7 +421,7 @@ class OpaqueArchetypeTypeRef final : public TypeRef { for (auto arg : argList) ID.addPointer(arg); } - + return ID; } @@ -432,7 +432,7 @@ class OpaqueArchetypeTypeRef final : public TypeRef { : TypeRef(TypeRefKind::OpaqueArchetype), ID(id), Description(description), Ordinal(ordinal) { std::vector argumentListLengths; - + for (auto argList : argumentLists) { argumentListLengths.push_back(argList.size()); AllArgumentsBuf.insert(AllArgumentsBuf.end(), @@ -461,17 +461,17 @@ class OpaqueArchetypeTypeRef final : public TypeRef { unsigned getOrdinal() const { return Ordinal; } - + /// A stable identifier for the opaque type. StringRef getID() const { return ID; } - + /// A human-digestible, but not necessarily stable, description of the opaque type. StringRef getDescription() const { return Description; } - + static bool classof(const TypeRef *T) { return T->getKind() == TypeRefKind::OpaqueArchetype; } @@ -548,7 +548,7 @@ class FunctionTypeRef final : public TypeRef { const TypeRef *getThrownError() const { return ThrownError; } - + static bool classof(const TypeRef *TR) { return TR->getKind() == TypeRefKind::Function; } @@ -558,12 +558,15 @@ class ProtocolCompositionTypeRef final : public TypeRef { std::vector Protocols; const TypeRef *Superclass; bool HasExplicitAnyObject; + bool HasExplicitReflectable; static TypeRefID Profile(std::vector Protocols, const TypeRef *Superclass, - bool HasExplicitAnyObject) { + bool HasExplicitAnyObject, + bool HasExplicitReflectable) { TypeRefID ID; ID.addInteger((uint32_t)HasExplicitAnyObject); + ID.addInteger((uint32_t)HasExplicitReflectable); for (auto Protocol : Protocols) { ID.addPointer(Protocol); } @@ -574,17 +577,20 @@ class ProtocolCompositionTypeRef final : public TypeRef { public: ProtocolCompositionTypeRef(std::vector Protocols, const TypeRef *Superclass, - bool HasExplicitAnyObject) + bool HasExplicitAnyObject, + bool HasExplicitReflectable) : TypeRef(TypeRefKind::ProtocolComposition), Protocols(Protocols), Superclass(Superclass), - HasExplicitAnyObject(HasExplicitAnyObject) {} + HasExplicitAnyObject(HasExplicitAnyObject), + HasExplicitReflectable(HasExplicitReflectable) {} template static const ProtocolCompositionTypeRef * create(Allocator &A, std::vector Protocols, - const TypeRef *Superclass, bool HasExplicitAnyObject) { + const TypeRef *Superclass, bool HasExplicitAnyObject, + bool HasExplicitReflectable) { FIND_OR_CREATE_TYPEREF(A, ProtocolCompositionTypeRef, Protocols, - Superclass, HasExplicitAnyObject); + Superclass, HasExplicitAnyObject, HasExplicitReflectable); } // These are either NominalTypeRef or ObjCProtocolTypeRef. @@ -598,6 +604,10 @@ class ProtocolCompositionTypeRef final : public TypeRef { return HasExplicitAnyObject; } + bool hasExplicitReflectable() const { + return HasExplicitReflectable; + } + static bool classof(const TypeRef *TR) { return TR->getKind() == TypeRefKind::ProtocolComposition; } diff --git a/include/swift/RemoteInspection/TypeRefBuilder.h b/include/swift/RemoteInspection/TypeRefBuilder.h index cd5b7d1c9c722..0a8382dbbc9fa 100644 --- a/include/swift/RemoteInspection/TypeRefBuilder.h +++ b/include/swift/RemoteInspection/TypeRefBuilder.h @@ -1211,7 +1211,7 @@ class TypeRefBuilder { } return ProtocolCompositionTypeRef::create(*this, protocolRefs, superclass, - isClassBound); + isClassBound, false); } const ConstrainedExistentialTypeRef *createConstrainedExistentialType( diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c8f69fbbf2a47..bd9bbe6931a00 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -224,6 +224,9 @@ struct ASTContext::Implementation { /// The AnyObject type. CanType AnyObjectType; + /// The Reflectable type. + CanType ReflectableType; + #define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \ /** The declaration of Swift.NAME. */ \ DECL_CLASS *NAME##Decl = nullptr; @@ -269,10 +272,10 @@ struct ASTContext::Implementation { /// The declaration of Swift.UnsafeMutablePointer.memory. VarDecl *UnsafeMutablePointerMemoryDecl = nullptr; - + /// The declaration of Swift.UnsafePointer.memory. VarDecl *UnsafePointerMemoryDecl = nullptr; - + /// The declaration of Swift.AutoreleasingUnsafeMutablePointer.memory. VarDecl *AutoreleasingUnsafeMutablePointerMemoryDecl = nullptr; @@ -289,10 +292,10 @@ struct ASTContext::Implementation { // Declare cached declarations for each of the known declarations. #define KNOWN_SDK_FUNC_DECL(Module, Name, Id) FuncDecl *Get##Name = nullptr; #include "swift/AST/KnownSDKDecls.def" - + /// func Bool FuncDecl *LessThanIntDecl = nullptr; - + /// func ==(Int, Int) -> Bool FuncDecl *EqualIntDecl = nullptr; @@ -578,7 +581,7 @@ struct ASTContext::Implementation { } llvm_unreachable("bad AllocationArena"); } - + llvm::FoldingSet SILLayouts; llvm::DenseMap overrideSigCache; @@ -1076,6 +1079,16 @@ CanType ASTContext::getAnyObjectConstraint() const { return getImpl().AnyObjectType; } +CanType ASTContext::getReflectableConstraint() const { + if (getImpl().ReflectableType) { + return getImpl().ReflectableType; + } + + getImpl().ReflectableType = CanType( + ProtocolCompositionType::theReflectableType(*this)); + return getImpl().ReflectableType; +} + CanType ASTContext::getAnyObjectType() const { return ExistentialType::get(getAnyObjectConstraint()) ->getCanonicalType(); @@ -1905,7 +1918,7 @@ void ASTContext::addModuleInterfaceChecker( void ASTContext::setModuleAliases(const llvm::StringMap &aliasMap) { // This setter should be called only once after ASTContext has been initialized assert(ModuleAliasMap.empty()); - + for (auto k: aliasMap.keys()) { auto v = aliasMap.lookup(k); if (!v.empty()) { @@ -2727,7 +2740,7 @@ bool ASTContext::hasDelayedConformanceErrors( return false; // unknown conformance, so no delayed diags either. } - + // check all conformances for any delayed errors for (const auto &entry : getImpl().DelayedConformanceDiags) { auto const& diagnostics = entry.getSecond(); @@ -2804,12 +2817,12 @@ size_t ASTContext::getTotalMemory() const { size_t ASTContext::getSolverMemory() const { size_t Size = 0; - + if (getImpl().CurrentConstraintSolverArena) { Size += getImpl().CurrentConstraintSolverArena->getTotalMemory(); Size += getImpl().CurrentConstraintSolverArena->Allocator.getBytesAllocated(); } - + return Size; } @@ -3345,7 +3358,7 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD, bool wantDynamicSelf) { auto *dc = AFD->getDeclContext(); auto &Ctx = dc->getASTContext(); - + // Determine the type of the container. auto containerTy = dc->getDeclaredInterfaceType(); if (!containerTy || containerTy->hasError()) @@ -3651,13 +3664,14 @@ ClassType *ClassType::get(ClassDecl *D, Type Parent, const ASTContext &C) { ProtocolCompositionType * ProtocolCompositionType::build(const ASTContext &C, ArrayRef Members, InvertibleProtocolSet Inverses, - bool HasExplicitAnyObject) { - assert(Members.size() != 1 || HasExplicitAnyObject || !Inverses.empty()); + bool HasExplicitAnyObject, + bool HasExplicitReflectable) { + assert(Members.size() != 1 || HasExplicitAnyObject || HasExplicitReflectable || !Inverses.empty()); // Check to see if we've already seen this protocol composition before. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - ProtocolCompositionType::Profile(ID, Members, Inverses, HasExplicitAnyObject); + ProtocolCompositionType::Profile(ID, Members, Inverses, HasExplicitAnyObject, HasExplicitReflectable); bool isCanonical = true; RecursiveTypeProperties properties; @@ -3682,6 +3696,7 @@ ProtocolCompositionType::build(const ASTContext &C, ArrayRef Members, Members, Inverses, HasExplicitAnyObject, + HasExplicitReflectable, properties); C.getImpl().getArena(arena).ProtocolCompositionTypes.InsertNode( compTy, InsertPos); @@ -3875,7 +3890,7 @@ ModuleType *ModuleType::get(ModuleDecl *M) { DynamicSelfType *DynamicSelfType::get(Type selfType, const ASTContext &ctx) { assert(selfType->isMaterializable() && "non-materializable dynamic self?"); - + auto properties = selfType->getRecursiveProperties(); auto arena = getArena(properties); @@ -4421,13 +4436,13 @@ SILFunctionType::SILFunctionType( // Make sure the type follows invariants. assert((!invocationSubs || genericSig) && "can only have substitutions with a generic signature"); - + if (invocationSubs) { assert(invocationSubs.getGenericSignature().getCanonicalSignature() == genericSig.getCanonicalSignature() && "substitutions must match generic signature"); } - + if (genericSig) { assert(!genericSig->areAllParamsConcrete() && "If all generic parameters are concrete, SILFunctionType should " @@ -4538,10 +4553,10 @@ CanSILBlockStorageType SILBlockStorageType::get(CanType captureType) { auto found = ctx.getImpl().SILBlockStorageTypes.find(captureType); if (found != ctx.getImpl().SILBlockStorageTypes.end()) return CanSILBlockStorageType(found->second); - + void *mem = ctx.Allocate(sizeof(SILBlockStorageType), alignof(SILBlockStorageType)); - + SILBlockStorageType *storageTy = new (mem) SILBlockStorageType(captureType); ctx.getImpl().SILBlockStorageTypes.insert({captureType, storageTy}); return CanSILBlockStorageType(storageTy); @@ -4580,7 +4595,7 @@ CanSILFunctionType SILFunctionType::get( // with generic parameters) if (isThinRepresentation(ext.getRepresentation())) ext = ext.intoBuilder().withNoEscape(false); - + llvm::FoldingSetNodeID id; SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params, yields, normalResults, errorResult, @@ -4616,7 +4631,7 @@ CanSILFunctionType SILFunctionType::get( properties |= result.getInterfaceType()->getRecursiveProperties(); if (errorResult) properties |= errorResult->getInterfaceType()->getRecursiveProperties(); - + // FIXME: If we ever have first-class polymorphic values, we'll need to // revisit this. if (genericSig || patternSubs) { @@ -4665,7 +4680,7 @@ VariadicSequenceType *VariadicSequenceType::get(Type base) { } DictionaryType *DictionaryType::get(Type keyType, Type valueType) { - auto properties = keyType->getRecursiveProperties() + auto properties = keyType->getRecursiveProperties() | valueType->getRecursiveProperties(); auto arena = getArena(properties); @@ -4675,7 +4690,7 @@ DictionaryType *DictionaryType::get(Type keyType, Type valueType) { = C.getImpl().getArena(arena).DictionaryTypes[{keyType, valueType}]; if (entry) return entry; - return entry = new (C, arena) DictionaryType(C, keyType, valueType, + return entry = new (C, arena) DictionaryType(C, keyType, valueType, properties); } @@ -5214,14 +5229,14 @@ void DeclName::initialize(ASTContext &C, DeclBaseName baseName, DeclName::DeclName(ASTContext &C, DeclBaseName baseName, ParameterList *paramList) { SmallVector names; - + for (auto P : *paramList) names.push_back(P->getArgumentName()); initialize(C, baseName, names); } /// Find the implementation of the named type in the given module. -static NominalTypeDecl *findUnderlyingTypeInModule(ASTContext &ctx, +static NominalTypeDecl *findUnderlyingTypeInModule(ASTContext &ctx, Identifier name, ModuleDecl *module) { // Find all of the declarations with this name in the Swift module. @@ -5345,7 +5360,7 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal, addTrivial(getIdentifier(name), simd); \ } \ } -#include "swift/ClangImporter/SIMDMappedTypes.def" +#include "swift/ClangImporter/SIMDMappedTypes.def" } } @@ -5422,12 +5437,12 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal, // If we didn't find anything, mark the result as "None". if (!result) result = ForeignRepresentationInfo::forNone(CurrentGeneration); - + // Cache the result. known = getImpl().ForeignRepresentableCache.insert({ nominal, *result }).first; } - // Map a cache entry to a result for this specific + // Map a cache entry to a result for this specific auto entry = known->second; if (entry.getKind() == ForeignRepresentableKind::None) return entry; @@ -5506,14 +5521,14 @@ bool ASTContext::isObjCClassWithMultipleSwiftBridgedTypes(Type t) { auto clazz = t->getClassOrBoundGenericClass(); if (!clazz) return false; - + if (clazz == getNSErrorDecl()) return true; if (clazz == getNSNumberDecl()) return true; if (clazz == getNSValueDecl()) return true; - + return false; } @@ -5838,7 +5853,7 @@ ASTContext::getOpenedElementSignature(CanGenericSignature baseGenericSig, return elementSig; } -GenericSignature +GenericSignature ASTContext::getOverrideGenericSignature(const ValueDecl *base, const ValueDecl *derived) { assert(isa(base) || isa(base)); @@ -5971,22 +5986,22 @@ SILLayout *SILLayout::get(ASTContext &C, if (!Generics || Generics->areAllParamsConcrete()) { CapturesGenericEnvironment = false; } - + // Profile the layout parameters. llvm::FoldingSetNodeID id; Profile(id, Generics, Fields, CapturesGenericEnvironment); - + // Return an existing layout if there is one. void *insertPos; auto &Layouts = C.getImpl().SILLayouts; - + if (auto existing = Layouts.FindNodeOrInsertPos(id, insertPos)) return existing; - + // Allocate a new layout. void *memory = C.Allocate(totalSizeToAlloc(Fields.size()), alignof(SILLayout)); - + auto newLayout = ::new (memory) SILLayout(Generics, Fields, CapturesGenericEnvironment); Layouts.InsertNode(newLayout, insertPos); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 1a89a1b2adde1..dc543f2b741ed 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -112,7 +112,7 @@ ASTBuilder::createBuiltinType(StringRef builtinName, Ctx.TheBuiltinModule->lookupValue(Ctx.getIdentifier(strippedName), NLKind::QualifiedLookup, decls); - + if (decls.size() == 1 && isa(decls[0])) return cast(decls[0])->getDeclaredInterfaceType(); } @@ -209,7 +209,7 @@ createSubstitutionMapFromGenericArgs(GenericSignature genericSig, LookupConformanceFn lookupConformance) { if (!genericSig) return SubstitutionMap(); - + if (genericSig.getGenericParams().size() != args.size()) return SubstitutionMap(); @@ -281,7 +281,7 @@ Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor, Type interfaceType = opaqueDecl->getOpaqueGenericParams()[ordinal]; return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs); } - + // TODO: named opaque types return Type(); } @@ -648,7 +648,7 @@ Type ASTBuilder::createProtocolCompositionType( if (superclass && superclass->getClassOrBoundGenericClass()) members.push_back(superclass); - Type composition = ProtocolCompositionType::get(Ctx, members, isClassBound); + Type composition = ProtocolCompositionType::get(Ctx, members, isClassBound, false); if (forRequirement) return composition; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 783f62f3dfa4d..fcd05374efe29 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -282,7 +282,7 @@ static StringRef getDumpString(ImportKind value) { case ImportKind::Var: return "var"; case ImportKind::Func: return "func"; } - + llvm_unreachable("Unhandled ImportKind in switch."); } @@ -386,7 +386,7 @@ static StringRef getDumpString(LifetimeAnnotation lifetime) { case LifetimeAnnotation::None: return ""; } - + llvm_unreachable("Unhandled LifetimeAnnotation in switch."); } static StringRef getDumpString(AccessorKind kind) { @@ -1305,7 +1305,7 @@ namespace { "known_to_be_local", DeclModifierColor); printAccessors(VD); - + printFoot(); } @@ -1369,7 +1369,7 @@ namespace { PD->getDefaultArgumentCaptureInfo().print(OS); }, "", CapturesColor); } - + printFlag(PD->getAttrs().hasAttribute(), "known_to_be_local", DeclModifierColor); @@ -2009,7 +2009,7 @@ class PrintStmt : public StmtVisitor, printRecArbitrary([&](StringRef label) { printHead("case_label_item", StmtColor, label); printFlag(LabelItem.isDefault(), "default"); - + if (auto *CasePattern = LabelItem.getPattern()) { printRec(CasePattern); } @@ -2099,12 +2099,12 @@ class PrintExpr : public ExprVisitor, printFlag(E->TrailingSemiLoc.isValid(), "trailing_semi"); } - + void printSemanticExpr(Expr * semanticExpr) { if (semanticExpr == nullptr) { return; } - + printRec(semanticExpr, "semantic_expr"); } @@ -2134,7 +2134,7 @@ class PrintExpr : public ExprVisitor, void visitIntegerLiteralExpr(IntegerLiteralExpr *E, StringRef label) { printCommon(E, "integer_literal_expr", label); - + printFlag(E->isNegative(), "negative", LiteralValueColor); Type T = GetTypeOfExpr(E); if (T.isNull() || !T->is()) @@ -2148,7 +2148,7 @@ class PrintExpr : public ExprVisitor, } void visitFloatLiteralExpr(FloatLiteralExpr *E, StringRef label) { printCommon(E, "float_literal_expr", label); - + printFlag(E->isNegative(), "negative", LiteralValueColor); printFieldQuoted(E->getDigitsText(), "value", LiteralValueColor); printInitializerField(E->getBuiltinInitializer(), "builtin_initializer"); @@ -2156,13 +2156,13 @@ class PrintExpr : public ExprVisitor, if (!E->getBuiltinType().isNull()) { printFieldQuoted(E->getBuiltinType(), "builtin_type", ExprModifierColor); } - + printFoot(); } void visitBooleanLiteralExpr(BooleanLiteralExpr *E, StringRef label) { printCommon(E, "boolean_literal_expr", label); - + printField(E->getValue(), "value", LiteralValueColor); printInitializerField(E->getBuiltinInitializer(), "builtin_initializer"); printInitializerField(E->getInitializer(), "initializer"); @@ -2172,7 +2172,7 @@ class PrintExpr : public ExprVisitor, void visitStringLiteralExpr(StringLiteralExpr *E, StringRef label) { printCommon(E, "string_literal_expr", label); - + printField(E->getEncoding(), "encoding", ExprModifierColor); printFieldQuoted(E->getValue(), "value", LiteralValueColor); printInitializerField(E->getBuiltinInitializer(), "builtin_initializer"); @@ -2200,7 +2200,7 @@ class PrintExpr : public ExprVisitor, } void visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, StringRef label) { printCommon(E, "magic_identifier_literal_expr", label); - + printField(E->getKind(), "kind", ExprModifierColor); if (E->isString()) { @@ -2213,7 +2213,7 @@ class PrintExpr : public ExprVisitor, } void visitRegexLiteralExpr(RegexLiteralExpr *E, StringRef label) { printCommon(E, "regex_literal_expr", label); - + printFieldQuoted(E->getRegexText(), "text", LiteralValueColor); printInitializerField(E->getInitializer(), "initializer"); @@ -2227,7 +2227,7 @@ class PrintExpr : public ExprVisitor, printInitializerField(E->getInitializer(), "initializer"); printRec(E->getArgs()); - + printFoot(); } @@ -2767,7 +2767,7 @@ class PrintExpr : public ExprVisitor, E->getCaptureInfo().print(OS); }, "", CapturesColor); } - // Printing a function type doesn't indicate whether it's escaping because it doesn't + // Printing a function type doesn't indicate whether it's escaping because it doesn't // matter in 99% of contexts. AbstractClosureExpr nodes are one of the only exceptions. if (auto Ty = GetTypeOfExpr(E)) { if (auto fType = Ty->getAs()) { @@ -3372,7 +3372,7 @@ class PrintTypeRepr : public TypeReprVisitor, printRec(T->getBase()); printFoot(); } - + void visitIsolatedTypeRepr(IsolatedTypeRepr *T, StringRef label) { printCommon("isolated", label); printRec(T->getBase()); @@ -4091,7 +4091,7 @@ namespace { printRec(T->getSelfType()); printFoot(); } - + void printArchetypeCommon(ArchetypeType *T, StringRef className, StringRef label) { @@ -4340,6 +4340,8 @@ namespace { printFlag(T->hasExplicitAnyObject(), "any_object"); + printFlag(T->hasExplicitReflectable(), "reflectable"); + for (auto proto : T->getMembers()) { printRec(proto); } diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 3c0ab1d8b0d97..b6021f6f3c5fa 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -3790,6 +3790,9 @@ void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) { case LayoutConstraintKind::Trivial: appendOperatorParam("T"); break; + case LayoutConstraintKind::Reflectable: + appendOperatorParam("B"); + break; case LayoutConstraintKind::TrivialOfExactSize: if (!layout->getAlignmentInBits()) appendOperatorParam("e", Index(layout->getTrivialSizeInBits())); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 7cc9e049c06a8..c88a86f754b48 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3048,7 +3048,7 @@ static bool usesFeatureRetroactiveAttribute(Decl *decl) { return false; ArrayRef entries = ext->getInherited().getEntries(); - return std::find_if(entries.begin(), entries.end(), + return std::find_if(entries.begin(), entries.end(), [](const InheritedEntry &entry) { return entry.isRetroactive; }) != entries.end(); @@ -3503,19 +3503,19 @@ static bool usesFeatureStructLetDestructuring(Decl *decl) { auto sd = dyn_cast(decl); if (!sd) return false; - + for (auto member : sd->getStoredProperties()) { if (!member->isLet()) continue; - + auto init = member->getParentPattern(); if (!init) continue; - + if (!init->getSingleVar()) return true; } - + return false; } @@ -4258,7 +4258,7 @@ static void printParameterFlags(ASTPrinter &printer, printer.printKeyword("__owned", options, " "); break; } - + if (flags.isIsolated()) printer.printKeyword("isolated", options, " "); @@ -7055,7 +7055,7 @@ class TypePrinter : public TypeVisitor { if (T->getLayout()->capturesGenericEnvironment()) { Printer << "@captures_generics "; } - + { // A box layout has its own independent generic environment. Don't try // to print it with the environment's generic params. @@ -7164,6 +7164,8 @@ class TypePrinter : public TypeVisitor { [&] { Printer << " & "; }); if (T->hasExplicitAnyObject()) Printer << " & AnyObject"; + if (T->hasExplicitReflectable()) + Printer << " & Reflectable"; } } @@ -7556,6 +7558,7 @@ void LayoutConstraintInfo::print(ASTPrinter &Printer, case LayoutConstraintKind::RefCountedObject: case LayoutConstraintKind::NativeRefCountedObject: case LayoutConstraintKind::Class: + case LayoutConstraintKind::Reflectable: case LayoutConstraintKind::NativeClass: case LayoutConstraintKind::Trivial: return; diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 173a5f9293318..5cd881b1ac2a6 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -99,7 +99,7 @@ Type swift::getBuiltinType(ASTContext &Context, StringRef Name) { return Context.TheUnsafeValueBufferType; if (Name == "PackIndex") return Context.ThePackIndexType; - + if (Name == "FPIEEE32") return Context.TheIEEE32Type; if (Name == "FPIEEE64") @@ -118,7 +118,7 @@ Type swift::getBuiltinType(ASTContext &Context, StringRef Name) { BitWidth <= 2048 && BitWidth != 0) // Cap to prevent insane things. return BuiltinIntegerType::get(BitWidth, Context); } - + // Target specific FP types. if (Name == "FPIEEE16") return Context.TheIEEE16Type; @@ -134,6 +134,10 @@ Type swift::getBuiltinType(ASTContext &Context, StringRef Name) { return CanType( ProtocolCompositionType::theAnyObjectType(Context)); + if (Name == "Reflectable") + return CanType( + ProtocolCompositionType::theReflectableType(Context)); + return Type(); } @@ -144,17 +148,17 @@ StringRef swift::getBuiltinBaseName(ASTContext &C, StringRef Name, // builtin-id ::= operation-id ('_' type-id)* for (StringRef::size_type Underscore = Name.find_last_of('_'); Underscore != StringRef::npos; Underscore = Name.find_last_of('_')) { - + // Check that the type parameter is well-formed and set it up for returning. // This allows operations with underscores in them, like "icmp_eq". Type Ty = getBuiltinType(C, Name.substr(Underscore + 1)); if (Ty.isNull()) break; - + Types.push_back(Ty); - + Name = Name.substr(0, Underscore); } - + std::reverse(Types.begin(), Types.end()); return Name; } @@ -323,7 +327,7 @@ synthesizeGenericSignature(SynthesisContext &SC, static FuncDecl * getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType) { auto &Context = ResType->getASTContext(); - + ModuleDecl *M = Context.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); @@ -338,7 +342,7 @@ getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType) { } auto *paramList = ParameterList::create(Context, params); - + DeclName Name(Context, Id, paramList); auto *const FD = FuncDecl::createImplicit( Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), @@ -554,7 +558,7 @@ static ValueDecl *getCastOperation(ASTContext &Context, Identifier Id, CheckOutput->castTo()->getGreatestWidth()) return nullptr; break; - + case BuiltinValueKind::ZExt: case BuiltinValueKind::SExt: { if (CheckOutput.isNull() || @@ -634,7 +638,7 @@ static ValueDecl *getCastOperation(ASTContext &Context, Identifier Id, if (auto *BIT = CheckOutput->getAs()) if (BIT->isFixedWidth() && BIT->getFixedWidth() == BFT->getBitWidth()) break; - + // Support VecNxInt1 -> IntN bitcast for SIMD comparison results. if (auto *Vec = CheckInput->getAs()) if (auto *BIT = CheckOutput->getAs()) @@ -1631,7 +1635,7 @@ static ValueDecl *getBuildComplexEqualitySerialExecutorRef(ASTContext &ctx, static ValueDecl *getAutoDiffCreateLinearMapContext(ASTContext &ctx, Identifier id) { return getBuiltinFunction( - ctx, id, _thin, _generics(_unrestricted), + ctx, id, _thin, _generics(_unrestricted), _parameters(_metatype(_typeparam(0))), _nativeObject); } @@ -1815,7 +1819,7 @@ static ValueDecl *getStaticReportOperation(ASTContext &Context, Identifier Id) { Type ArgElts[] = { BoolTy, BoolTy, MessageTy }; Type ResultTy = TupleType::getEmpty(Context); - + return getBuiltinFunction(Id, ArgElts, ResultTy); } @@ -1892,7 +1896,7 @@ static ValueDecl *getOnceOperation(ASTContext &Context, Identifier Id, bool withContext) { // (RawPointer, @convention(c) (Context) -> ()[, Context]) -> () - + auto HandleTy = Context.TheRawPointerType; auto VoidTy = Context.TheEmptyTupleType; SmallVector CFuncParams; @@ -2006,7 +2010,7 @@ static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { inline bool isBuiltinTypeOverloaded(Type T, OverloadedBuiltinKind OK) { switch (OK) { case OverloadedBuiltinKind::None: - return false; // always fail. + return false; // always fail. case OverloadedBuiltinKind::Integer: return T->is(); case OverloadedBuiltinKind::IntegerOrVector: @@ -2060,7 +2064,7 @@ llvm::Intrinsic::ID swift::getLLVMIntrinsicID(StringRef InName) { if (!InName.startswith("int_")) return llvm::Intrinsic::not_intrinsic; InName = InName.drop_front(strlen("int_")); - + // Prepend "llvm." and change _ to . in name. SmallString<128> NameS; NameS.append("llvm."); @@ -2189,7 +2193,7 @@ Type IntrinsicTypeDecoder::decodeImmediate() { if (!eltType) return Type(); return makeVector(eltType, D.Vector_Width.getKnownMinValue()); } - + // The element type of a vector type. case IITDescriptor::VecElementArgument: { Type argType = getTypeArgument(D.getArgumentNumber()); @@ -2226,7 +2230,7 @@ Type IntrinsicTypeDecoder::decodeImmediate() { for (unsigned i = 0; i != D.Struct_NumElements; ++i) { Type T = decodeImmediate(); if (!T) return Type(); - + Elts.push_back(T); } return TupleType::get(Elts, Context); @@ -2326,7 +2330,7 @@ static bool isUnknownOrUnordered(llvm::AtomicOrdering ordering) { llvm_unreachable("Unhandled AtomicOrdering in switch."); } -static bool isValidCmpXChgOrdering(StringRef SuccessString, +static bool isValidCmpXChgOrdering(StringRef SuccessString, StringRef FailureString) { using namespace llvm; AtomicOrdering SuccessOrdering = decodeLLVMAtomicOrdering(SuccessString); @@ -2371,20 +2375,20 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { if (OperationName.empty()) return nullptr; return getIfdefOperation(Context, Id); } - + // If this starts with fence, we have special suffixes to handle. if (OperationName.startswith("fence_")) { OperationName = OperationName.drop_front(strlen("fence_")); - + // Verify we have a single integer, floating point, or pointer type. if (!Types.empty()) return nullptr; - + // Get and validate the ordering argument, which is required. auto Underscore = OperationName.find('_'); if (!isValidFenceOrdering(OperationName.substr(0, Underscore))) return nullptr; OperationName = OperationName.substr(Underscore); - + // Accept singlethread if present. if (OperationName.startswith("_singlethread")) OperationName = OperationName.drop_front(strlen("_singlethread")); @@ -2393,11 +2397,11 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { return nullptr; return getFenceOperation(Context, Id); } - + // If this starts with cmpxchg, we have special suffixes to handle. if (OperationName.startswith("cmpxchg_")) { OperationName = OperationName.drop_front(strlen("cmpxchg_")); - + // Verify we have a single integer, floating point, or pointer type. if (Types.size() != 1) return nullptr; Type T = Types[0]; @@ -2430,13 +2434,13 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { // If this starts with atomicrmw, we have special suffixes to handle. if (OperationName.startswith("atomicrmw_")) { OperationName = OperationName.drop_front(strlen("atomicrmw_")); - + // Verify we have a single integer or pointer type. if (Types.size() != 1) return nullptr; Type Ty = Types[0]; if (!Ty->is() && !Ty->is()) return nullptr; - + // Get and validate the suboperation name, which is required. auto Underscore = OperationName.find('_'); if (Underscore == StringRef::npos) return nullptr; @@ -2446,13 +2450,13 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { SubOp != "min" && SubOp != "umax" && SubOp != "umin") return nullptr; OperationName = OperationName.drop_front(Underscore+1); - + // Get and validate the ordering argument, which is required. Underscore = OperationName.find('_'); if (!isValidRMWOrdering(OperationName.substr(0, Underscore))) return nullptr; OperationName = OperationName.substr(Underscore); - + // Accept volatile and singlethread if present. if (OperationName.startswith("_volatile")) OperationName = OperationName.drop_front(strlen("_volatile")); @@ -2643,7 +2647,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; return getUnaryOperation(Context, Id, Types[0]); - + #define BUILTIN(id, name, Attrs) #define BUILTIN_CAST_OPERATION(id, name, attrs) case BuiltinValueKind::id: #define BUILTIN_CAST_OR_BITCAST_OPERATION(id, name, attrs) case BuiltinValueKind::id: @@ -2655,14 +2659,14 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::Autorelease: if (!Types.empty()) return nullptr; return getRefCountingOperation(Context, Id); - + case BuiltinValueKind::Load: case BuiltinValueKind::LoadRaw: case BuiltinValueKind::LoadInvariant: case BuiltinValueKind::Take: if (!Types.empty()) return nullptr; return getLoadOperation(Context, Id); - + case BuiltinValueKind::Destroy: if (!Types.empty()) return nullptr; return getDestroyOperation(Context, Id); @@ -2675,7 +2679,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::DestroyArray: if (!Types.empty()) return nullptr; return getDestroyArrayOperation(Context, Id); - + case BuiltinValueKind::CopyArray: case BuiltinValueKind::TakeArrayNoAlias: case BuiltinValueKind::TakeArrayFrontToBack: @@ -2758,7 +2762,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::CastBitPatternFromBridgeObject: if (!Types.empty()) return nullptr; return getCastFromBridgeObjectOperation(Context, Id, BV); - + case BuiltinValueKind::CastReference: if (!Types.empty()) return nullptr; return getCastReferenceOperation(Context, Id); @@ -2766,7 +2770,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::ReinterpretCast: if (!Types.empty()) return nullptr; return getReinterpretCastOperation(Context, Id); - + case BuiltinValueKind::AddressOf: case BuiltinValueKind::UnprotectedAddressOf: if (!Types.empty()) return nullptr; @@ -2787,20 +2791,20 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::AssertConf: return getAssertConfOperation(Context, Id); - + case BuiltinValueKind::FixLifetime: return getFixLifetimeOperation(Context, Id); - + case BuiltinValueKind::CanBeObjCClass: return getCanBeObjCClassOperation(Context, Id); - + case BuiltinValueKind::CondUnreachable: case BuiltinValueKind::Unreachable: return getUnreachableOperation(Context, Id); - + case BuiltinValueKind::ZeroInitializer: return getZeroInitializerOperation(Context, Id); - + case BuiltinValueKind::Once: case BuiltinValueKind::OnceWithContext: return getOnceOperation(Context, Id, BV == BuiltinValueKind::OnceWithContext); @@ -2819,7 +2823,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::InsertElement: if (Types.size() != 3) return nullptr; return getInsertElementOperation(Context, Id, Types[0], Types[1], Types[2]); - + case BuiltinValueKind::ShuffleVector: if (Types.size() != 2) return nullptr; return getShuffleVectorOperation(Context, Id, Types[0], Types[1]); @@ -2932,7 +2936,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::TypePtrAuthDiscriminator: return getTypePtrAuthDiscriminator(Context, Id); - + case BuiltinValueKind::TypeJoin: return getTypeJoinOperation(Context, Id); diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index dd2303435754f..f559db140be1e 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -205,8 +205,9 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage, } else if (next->getParentSourceFile() || next->getParentModule()->isBuiltinModule()) { bool anyObject = false; + bool reflectable = false; for (const auto &found : - getDirectlyInheritedNominalTypeDecls(next, anyObject)) { + getDirectlyInheritedNominalTypeDecls(next, anyObject, reflectable)) { if (auto proto = dyn_cast(found.Item)) protocols.push_back({proto, found.Loc, found.uncheckedLoc}); } @@ -492,8 +493,9 @@ void ConformanceLookupTable::addInheritedProtocols( ConformanceSource source) { // Find all of the protocols in the inheritance list. bool anyObject = false; + bool reflectable = false; for (const auto &found : - getDirectlyInheritedNominalTypeDecls(decl, anyObject)) { + getDirectlyInheritedNominalTypeDecls(decl, anyObject, reflectable)) { if (auto proto = dyn_cast(found.Item)) { addProtocol( proto, found.Loc, source.withUncheckedLoc(found.uncheckedLoc)); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 253da996fd3be..7125451b50773 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6535,6 +6535,11 @@ bool ProtocolDecl::requiresClass() const { ProtocolRequiresClassRequest{const_cast(this)}, false); } +bool ProtocolDecl::inheritsReflectable() const { + return evaluateOrDefault(getASTContext().evaluator, + InheritsReflectableProtocolRequest{const_cast(this)}, false); +} + bool ProtocolDecl::requiresSelfConformanceWitnessTable() const { return isSpecificProtocol(KnownProtocolKind::Error); } diff --git a/lib/AST/ExistentialGeneralization.cpp b/lib/AST/ExistentialGeneralization.cpp index 3a22d6dd5f334..3e494bedf30f3 100644 --- a/lib/AST/ExistentialGeneralization.cpp +++ b/lib/AST/ExistentialGeneralization.cpp @@ -107,7 +107,8 @@ class Generalizer : public CanTypeVisitor { newMembers.push_back(generalizeStructure(origMember)); } return ProtocolCompositionType::get(ctx, newMembers, - origType->hasExplicitAnyObject()); + origType->hasExplicitAnyObject(), + origType->hasExplicitReflectable()); } Type visitInverseType(CanInverseType type) { diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 1fa30884d5c25..6c639814c949f 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -729,7 +729,7 @@ Type GenericSignatureImpl::getUpperBound(Type type, } auto constraint = ProtocolCompositionType::get(getASTContext(), types, - hasExplicitAnyObject); + hasExplicitAnyObject, true); // FIXME if (!constraint->isConstraintType()) { assert(constraint->getClassOrBoundGenericClass()); diff --git a/lib/AST/LayoutConstraint.cpp b/lib/AST/LayoutConstraint.cpp index 1c00b790a9a73..650986aaa3ab5 100644 --- a/lib/AST/LayoutConstraint.cpp +++ b/lib/AST/LayoutConstraint.cpp @@ -43,6 +43,10 @@ LayoutConstraint getLayoutConstraint(Identifier ID, ASTContext &Ctx) { return LayoutConstraint::getLayoutConstraint( LayoutConstraintKind::Class, Ctx); + if (ID == Ctx.Id_Reflectable) + return LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Reflectable, Ctx); + if (ID == Ctx.Id_NativeClassLayout) return LayoutConstraint::getLayoutConstraint( LayoutConstraintKind::NativeClass, Ctx); @@ -73,6 +77,8 @@ StringRef LayoutConstraintInfo::getName(LayoutConstraintKind Kind, bool useClass return "_TrivialAtMost"; case LayoutConstraintKind::TrivialOfExactSize: return "_Trivial"; + case LayoutConstraintKind::Reflectable: + return "Reflectable"; } llvm_unreachable("Unhandled LayoutConstraintKind in switch."); @@ -127,6 +133,10 @@ bool LayoutConstraintInfo::isClass(LayoutConstraintKind Kind) { Kind == LayoutConstraintKind::NativeClass; } +bool LayoutConstraintInfo::isReflectable(LayoutConstraintKind Kind) { + return Kind == LayoutConstraintKind::Reflectable; +} + bool LayoutConstraintInfo::isNativeClass(LayoutConstraintKind Kind) { return Kind == LayoutConstraintKind::NativeClass; } @@ -324,6 +334,8 @@ LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind) { &LayoutConstraintInfo::RefCountedObjectConstraintInfo); case LayoutConstraintKind::UnknownLayout: return LayoutConstraint(&LayoutConstraintInfo::UnknownLayoutConstraintInfo); + case LayoutConstraintKind::Reflectable: + return LayoutConstraint(&LayoutConstraintInfo::ReflectableConstraintInfo); case LayoutConstraintKind::TrivialOfAtMostSize: case LayoutConstraintKind::TrivialOfExactSize: llvm_unreachable("Wrong layout constraint kind"); @@ -352,6 +364,9 @@ LayoutConstraintInfo LayoutConstraintInfo::NativeClassConstraintInfo( LayoutConstraintInfo LayoutConstraintInfo::TrivialConstraintInfo( LayoutConstraintKind::Trivial); +LayoutConstraintInfo LayoutConstraintInfo::ReflectableConstraintInfo( + LayoutConstraintKind::Reflectable); + int LayoutConstraint::compare(LayoutConstraint rhs) const { if (Ptr->getKind() != rhs->getKind()) return int(rhs->getKind()) - int(Ptr->getKind()); diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 9f561346b75d8..6b24ff3b58c9c 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1085,7 +1085,8 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, ArrayRef typeDecls, ResolveToNominalOptions options, SmallVectorImpl &modulesFound, - bool &anyObject); + bool &anyObject, + bool &reflectable); SelfBounds SelfBoundsFromWhereClauseRequest::evaluate( Evaluator &evaluator, @@ -1136,10 +1137,12 @@ SelfBounds SelfBoundsFromWhereClauseRequest::evaluate( } SmallVector modulesFound; + bool reflectable = false; auto rhsNominals = resolveTypeDeclsToNominal(evaluator, ctx, rhsDecls, ResolveToNominalOptions(), modulesFound, - result.anyObject); + result.anyObject, + reflectable); result.decls.insert(result.decls.end(), rhsNominals.begin(), rhsNominals.end()); @@ -1175,9 +1178,10 @@ SelfBounds SelfBoundsFromGenericSignatureRequest::evaluate( auto rhsDecls = directReferencesForType(req.getSecondType()); SmallVector modulesFound; + bool reflectable = false; auto rhsNominals = resolveTypeDeclsToNominal( evaluator, ctx, rhsDecls, ResolveToNominalOptions(), - modulesFound, result.anyObject); + modulesFound, result.anyObject, reflectable); result.decls.insert(result.decls.end(), rhsNominals.begin(), rhsNominals.end()); } @@ -2663,6 +2667,7 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, ResolveToNominalOptions options, SmallVectorImpl &modulesFound, bool &anyObject, + bool &reflectable, llvm::SmallPtrSetImpl &typealiases) { SmallPtrSet knownNominalDecls; TinyPtrVector nominalDecls; @@ -2698,7 +2703,7 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, auto underlyingNominalReferences = resolveTypeDeclsToNominal(evaluator, ctx, underlyingTypeReferences, - options, modulesFound, anyObject, typealiases); + options, modulesFound, anyObject, reflectable, typealiases); std::for_each(underlyingNominalReferences.begin(), underlyingNominalReferences.end(), addNominalDecl); @@ -2728,6 +2733,33 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, } } + if (typealias->getName().is("Reflectable")) { + // TypeRepr version: Builtin.AnyObject + if (auto typeRepr = typealias->getUnderlyingTypeRepr()) { + if (auto memberTR = dyn_cast(typeRepr)) { + if (auto identBase = + dyn_cast(memberTR->getBaseComponent())) { + auto memberComps = memberTR->getMemberComponents(); + if (memberComps.size() == 1 && + identBase->getNameRef().isSimpleName("Builtin") && + memberComps.front()->getNameRef().isSimpleName("Reflectable")) { + reflectable = true; + } + } + } + } + + // Type version: an empty class-bound existential. + if (typealias->hasInterfaceType()) { + if (auto type = typealias->getUnderlyingType()) { + if (type->isAnyObject()) + anyObject = true; + if (type->isReflectable()) + reflectable = true; + } + } + } + continue; } @@ -2751,10 +2783,11 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, ArrayRef typeDecls, ResolveToNominalOptions options, SmallVectorImpl &modulesFound, - bool &anyObject) { + bool &anyObject, + bool &reflectable) { llvm::SmallPtrSet typealiases; return resolveTypeDeclsToNominal(evaluator, ctx, typeDecls, options, - modulesFound, anyObject, typealiases); + modulesFound, anyObject, reflectable, typealiases); } /// Perform unqualified name lookup for types at the given location. @@ -2857,10 +2890,11 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator, // to nominal type declarations, module declarations, and SmallVector moduleDecls; bool anyObject = false; + bool reflectable = false; auto nominalTypeDecls = resolveTypeDeclsToNominal(ctx.evaluator, ctx, baseTypes, ResolveToNominalOptions(), - moduleDecls, anyObject); + moduleDecls, anyObject, reflectable); dc->lookupQualified(nominalTypeDecls, name, loc, options, members); @@ -3146,10 +3180,11 @@ SuperclassDeclRequest::evaluate(Evaluator &evaluator, // Resolve those type declarations to nominal type declarations. SmallVector modulesFound; bool anyObject = false; + bool reflectable = false; auto inheritedNominalTypes = resolveTypeDeclsToNominal(evaluator, Ctx, inheritedTypes, ResolveToNominalOptions(), - modulesFound, anyObject); + modulesFound, anyObject, reflectable); // Look for a class declaration. ClassDecl *superclass = nullptr; @@ -3190,7 +3225,8 @@ InheritedProtocolsRequest::evaluate(Evaluator &evaluator, SmallPtrSet known; known.insert(PD); bool anyObject = false; - for (const auto &found : getDirectlyInheritedNominalTypeDecls(PD, anyObject)) { + bool reflectable = false; + for (const auto &found : getDirectlyInheritedNominalTypeDecls(PD, anyObject, reflectable)) { if (auto proto = dyn_cast(found.Item)) { if (known.insert(proto).second) result.push_back(proto); @@ -3231,10 +3267,11 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator, // Resolve those type declarations to nominal type declarations. SmallVector modulesFound; bool anyObject = false; + bool reflectable = false; auto nominalTypes = resolveTypeDeclsToNominal(evaluator, ctx, referenced, ResolveToNominalFlags::AllowTupleType, - modulesFound, anyObject); + modulesFound, anyObject, reflectable); // If there is more than 1 element, we will emit a warning or an error // elsewhere, so don't handle that case here. @@ -3583,9 +3620,10 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, // Dig out the nominal type declarations. SmallVector modulesFound; bool anyObject = false; + bool reflectable = false; auto nominals = resolveTypeDeclsToNominal(evaluator, ctx, decls, ResolveToNominalOptions(), - modulesFound, anyObject); + modulesFound, anyObject, reflectable); if (nominals.size() == 1 && !isa(nominals.front())) return nominals.front(); @@ -3603,7 +3641,7 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, LookupOuterResults::Included); nominals = resolveTypeDeclsToNominal(evaluator, ctx, decls, ResolveToNominalOptions(), - modulesFound, anyObject); + modulesFound, anyObject, reflectable); if (nominals.size() == 1 && !isa(nominals.front())) { auto nominal = nominals.front(); if (nominal->getDeclContext()->isModuleScopeContext()) { @@ -3638,7 +3676,7 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, void swift::getDirectlyInheritedNominalTypeDecls( llvm::PointerUnion decl, unsigned i, llvm::SmallVectorImpl &result, - bool &anyObject) { + bool &anyObject, bool &reflectable) { auto typeDecl = decl.dyn_cast(); auto extDecl = decl.dyn_cast(); @@ -3654,7 +3692,7 @@ void swift::getDirectlyInheritedNominalTypeDecls( auto nominalTypes = resolveTypeDeclsToNominal(ctx.evaluator, ctx, referenced, ResolveToNominalOptions(), - modulesFound, anyObject); + modulesFound, anyObject, reflectable); // Dig out the source location // FIXME: This is a hack. We need cooperation from @@ -3676,13 +3714,14 @@ void swift::getDirectlyInheritedNominalTypeDecls( SmallVector swift::getDirectlyInheritedNominalTypeDecls( llvm::PointerUnion decl, - bool &anyObject) { + bool &anyObject, + bool &reflectable) { auto inheritedTypes = InheritedTypes(decl); // Gather results from all of the inherited types. SmallVector result; for (unsigned i : inheritedTypes.getIndices()) { - getDirectlyInheritedNominalTypeDecls(decl, i, result, anyObject); + getDirectlyInheritedNominalTypeDecls(decl, i, result, anyObject, reflectable); } auto *typeDecl = decl.dyn_cast(); @@ -3838,10 +3877,11 @@ ProtocolDecl *ImplementsAttrProtocolRequest::evaluate( // Resolve those type declarations to nominal type declarations. SmallVector modulesFound; bool anyObject = false; + bool reflectable = false; auto nominalTypes = resolveTypeDeclsToNominal(evaluator, ctx, referenced, ResolveToNominalOptions(), - modulesFound, anyObject); + modulesFound, anyObject, reflectable); if (nominalTypes.empty()) return nullptr; diff --git a/lib/AST/RequirementMachine/RequirementLowering.cpp b/lib/AST/RequirementMachine/RequirementLowering.cpp index 8b0b62d9a5b1a..bc4f9e5cb2dc6 100644 --- a/lib/AST/RequirementMachine/RequirementLowering.cpp +++ b/lib/AST/RequirementMachine/RequirementLowering.cpp @@ -371,6 +371,12 @@ static void desugarConformanceRequirement(Requirement req, LayoutConstraintKind::Class)); } + if (compositionType->hasExplicitReflectable()) { + subReqs.emplace_back(RequirementKind::Layout, req.getFirstType(), + LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Reflectable)); + } + for (auto memberType : compositionType->getMembers()) { subReqs.emplace_back( memberType->isConstraintType() diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f033ca00b7238..bc94607db7800 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -119,7 +119,7 @@ bool TypeBase::isUninhabited() { bool TypeBase::isStructurallyUninhabited() { if (isUninhabited()) return true; - + // Tuples of uninhabited types are uninhabited if (auto *TTy = getAs()) for (auto eltTy : TTy->getElementTypes()) @@ -341,6 +341,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) { auto *protoDecl = type->getDecl(); hasExplicitAnyObject = false; + hasExplicitReflectable = protoDecl->inheritsReflectable(); hasInverseCopyable = false; containsNonObjCProtocol = !isObjCProtocol(protoDecl); containsParameterized = false; @@ -350,6 +351,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) { ExistentialLayout::ExistentialLayout(CanInverseType type) { hasExplicitAnyObject = false; + hasExplicitReflectable = false; hasInverseCopyable = false; containsNonObjCProtocol = false; containsParameterized = false; @@ -363,6 +365,7 @@ ExistentialLayout::ExistentialLayout(CanInverseType type) { ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) { hasExplicitAnyObject = type->hasExplicitAnyObject(); + hasExplicitReflectable = type->hasExplicitReflectable(); hasInverseCopyable = false; containsNonObjCProtocol = false; containsParameterized = false; @@ -472,6 +475,10 @@ bool ExistentialLayout::isAnyObject() const { return (hasExplicitAnyObject && !explicitSuperclass && getProtocols().empty()); } +bool ExistentialLayout::isReflectable() const { + return (hasExplicitReflectable && getProtocols().empty()); +} + bool TypeBase::isObjCExistentialType() { return getCanonicalType().isObjCExistentialType(); } @@ -1153,7 +1160,8 @@ Type TypeBase::stripConcurrency(bool recurse, bool dropGlobalActor) { if (!newMembers.empty()) { return ProtocolCompositionType::get( getASTContext(), newMembers, - protocolCompositionType->hasExplicitAnyObject()); + protocolCompositionType->hasExplicitAnyObject(), + protocolCompositionType->hasExplicitReflectable()); } return Type(this); @@ -1186,6 +1194,15 @@ bool TypeBase::isAnyObject() { return canTy.getExistentialLayout().isAnyObject(); } +bool TypeBase::isReflectable() { + auto canTy = getCanonicalType(); + + if (!canTy.isExistentialType() || canTy.isForeignReferenceType()) + return false; + + return canTy.getExistentialLayout().isReflectable(); +} + // Distinguish between class-bound types that might be AnyObject vs other // class-bound types. Only types that are potentially AnyObject might have a // transparent runtime type wrapper like __SwiftValue. This must look through @@ -1226,6 +1243,11 @@ LayoutConstraint ExistentialLayout::getLayoutConstraint() const { LayoutConstraintKind::Class); } + if (hasExplicitReflectable) { + return LayoutConstraint::getLayoutConstraint( + LayoutConstraintKind::Reflectable); + } + return LayoutConstraint(); } @@ -1348,7 +1370,7 @@ Type TypeBase::replaceCovariantResultType(Type newResultType, inputType, resultType, fnType->getExtInfo()); } - + return FunctionType::get(inputType, resultType, fnType->getExtInfo()); } @@ -1563,7 +1585,8 @@ static void addProtocols(Type T, SmallVectorImpl &Protocols, ParameterizedProtocolMap &Parameterized, Type &Superclass, - bool &HasExplicitAnyObject) { + bool &HasExplicitAnyObject, + bool &HasExplicitReflectable) { if (auto Proto = T->getAs()) { Protocols.push_back(Proto->getDecl()); return; @@ -1572,9 +1595,11 @@ static void addProtocols(Type T, if (auto PC = T->getAs()) { if (PC->hasExplicitAnyObject()) HasExplicitAnyObject = true; + if (PC->hasExplicitReflectable()) + HasExplicitReflectable = true; for (auto P : PC->getMembers()) addProtocols(P, Protocols, Parameterized, Superclass, - HasExplicitAnyObject); + HasExplicitAnyObject, HasExplicitReflectable); return; } @@ -1640,7 +1665,7 @@ static void canonicalizeProtocols(SmallVectorImpl &protocols, protocols[i] = nullptr; zappedAny = true; } - + // Walk the inheritance hierarchies of all of the protocols. If we run into // one of the known protocols, zap it from the original list. for (unsigned i : indices(protocols)) { @@ -1666,7 +1691,7 @@ static void canonicalizeProtocols(SmallVectorImpl &protocols, return TypeWalker::Action::Continue; }); } - + if (zappedAny) { protocols.erase(std::remove(protocols.begin(), protocols.end(), nullptr), protocols.end()); @@ -1875,7 +1900,8 @@ CanType TypeBase::computeCanonicalType() { assert(!CanProtos.empty() && "Non-canonical empty composition?"); const ASTContext &C = CanProtos[0]->getASTContext(); Type Composition = ProtocolCompositionType::get(C, CanProtos, - PCT->hasExplicitAnyObject()); + PCT->hasExplicitAnyObject(), + PCT->hasExplicitReflectable()); Result = Composition.getPointer(); break; } @@ -2123,7 +2149,7 @@ Identifier GenericTypeParamType::getName() const { // Use the declaration name if we still have that sugar. if (auto decl = getDecl()) return decl->getName(); - + // Otherwise, we're canonical. Produce an anonymous '_n_n' name. assert(isCanonical()); // getASTContext() doesn't actually mutate an already-canonical type. @@ -2133,7 +2159,7 @@ Identifier GenericTypeParamType::getName() const { auto cached = names.find(depthIndex); if (cached != names.end()) return cached->second; - + llvm::SmallString<10> nameBuf; llvm::raw_svector_ostream os(nameBuf); @@ -2191,6 +2217,44 @@ bool TypeBase::satisfiesClassConstraint() { return mayHaveSuperclass() || isObjCExistentialType(); } +bool TypeBase::satisfiesReflectableConstraint() { + + const TypeDecl * decl = getAnyNominal(); + auto inheritedTypes = InheritedTypes(decl); + auto inheritedClause = inheritedTypes.getEntries(); + + ASTContext &ctx = decl->getASTContext(); + + // Check all of the types listed in the inheritance clause. + bool inheritedReflectable = false; + for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) { + // Validate the type. + InheritedTypeRequest request{decl, i, TypeResolutionStage::Interface}; + Type inheritedTy = evaluateOrDefault(ctx.evaluator, request, Type()); + + if (!inheritedTy || inheritedTy->hasError()) + continue; + + if (inheritedTy->isConstraintType()) { + + if (auto PC = inheritedTy->getAs()) { + inheritedReflectable |= PC->hasExplicitReflectable(); + } + + auto layout = inheritedTy->getExistentialLayout(); + + if (isa(decl)) + continue; + + if (layout.hasExplicitReflectable) { + inheritedReflectable = true; + } + } + } + + return inheritedReflectable; +} + Type TypeBase::getSuperclass(bool useArchetypes) { auto *nominalDecl = getAnyNominal(); auto *classDecl = dyn_cast_or_null(nominalDecl); @@ -2275,9 +2339,9 @@ class IsBindableVisitor using VisitBindingCallback = llvm::function_ref)>; - + VisitBindingCallback VisitBinding; - + IsBindableVisitor(VisitBindingCallback visit) : VisitBinding(visit) {} @@ -2301,25 +2365,25 @@ class IsBindableVisitor // TODO: If the archetype has a superclass constraint, check that the // substitution is a subclass. - + // TODO: For private types or protocols, we might be able to definitively // deny bindings. - + // Otherwise, there may be an external retroactive conformance that // allows the binding. } // Let the binding succeed. return VisitBinding(orig, subst, upperBound, substConformances); } - + CanType visitType(TypeBase *orig, CanType subst, ArchetypeType*, ArrayRef) { if (CanType(orig) == subst) return subst; - + return CanType(); } - + CanType visitDynamicSelfType(DynamicSelfType *orig, CanType subst, ArchetypeType *upperBound, ArrayRef substConformances) { @@ -2333,14 +2397,14 @@ class IsBindableVisitor } return CanType(); } - + if (auto newNonDynBase = visit(orig->getSelfType(), subst, upperBound, substConformances)) { return newNonDynBase; } return CanType(); } - + /// Handle a nominal type with generic parameters anywhere in its context. /// \c origType and \c substType must already have been established to be /// instantiations of the same \c NominalTypeDecl. @@ -2351,7 +2415,7 @@ class IsBindableVisitor ArrayRef substConformances) { assert(origType->getAnyNominal() == decl && substType->getAnyNominal() == decl); - + LLVM_DEBUG(llvm::dbgs() << "\n---\nTesting bindability of:\n"; origType->print(llvm::dbgs()); llvm::dbgs() << "\nto subst type:\n"; @@ -2360,7 +2424,7 @@ class IsBindableVisitor llvm::dbgs() << "\nwith upper bound archetype:\n"; upperBound->print(llvm::dbgs()); }); - + auto *moduleDecl = decl->getParentModule(); auto origSubMap = origType->getContextSubstitutionMap( moduleDecl, decl, decl->getGenericEnvironment()); @@ -2368,11 +2432,11 @@ class IsBindableVisitor moduleDecl, decl, decl->getGenericEnvironment()); auto genericSig = decl->getGenericSignature(); - + SmallVector newParams; llvm::DenseMap newParamsMap; bool didChange = false; - + // The upper bounds for the nominal type's arguments may depend on the // upper bounds imposed on the nominal type itself, if conditional // conformances are involved. For instance, if we're looking at: @@ -2390,17 +2454,17 @@ class IsBindableVisitor // upper bound. auto upperBoundGenericSig = genericSig; auto upperBoundSubstMap = substSubMap; - + LLVM_DEBUG(llvm::dbgs() << "\nNominal type generic signature:\n"; upperBoundGenericSig.print(llvm::dbgs()); upperBoundSubstMap.dump(llvm::dbgs())); - + if (upperBound && !upperBound->getConformsTo().empty()) { // Start with the set of requirements from the nominal type. SmallVector addedRequirements; - + llvm::DenseMap, ProtocolConformanceRef> addedConformances; - + for (auto proto : upperBound->getConformsTo()) { // Find the DeclContext providing the conformance for the type. auto nomConformance = moduleDecl->lookupConformance( @@ -2410,27 +2474,27 @@ class IsBindableVisitor if (nomConformance.isAbstract()) continue; auto conformanceContext = nomConformance.getConcrete()->getDeclContext(); - + LLVM_DEBUG(llvm::dbgs() << "\nFound extension conformance for " << proto->getName() << " in context:\n"; conformanceContext->printContext(llvm::dbgs())); - + auto conformanceSig = conformanceContext->getGenericSignatureOfContext(); // TODO: Conformance on generalized generic extensions could conceivably // have totally different generic signatures. assert(conformanceSig.getGenericParams().size() == genericSig.getGenericParams().size() && "generalized generic extension not handled properly"); - + // Collect requirements from the conformance not satisfied by the // original declaration. for (auto reqt : conformanceSig.requirementsNotSatisfiedBy(genericSig)) { LLVM_DEBUG(llvm::dbgs() << "\n- adds requirement\n"; reqt.dump(llvm::dbgs())); - + addedRequirements.push_back(reqt); - + // Collect the matching conformance for the substituted type. // TODO: Look this up using the upperBoundSubstConformances if (reqt.getKind() == RequirementKind::Conformance) { @@ -2443,19 +2507,19 @@ class IsBindableVisitor substConformance = moduleDecl->lookupConformance( substTy, proto, /*allowMissing=*/true); } - + LLVM_DEBUG(llvm::dbgs() << "\n` adds conformance for subst type\n"; substTy->print(llvm::dbgs()); substConformance.dump(llvm::dbgs())); - + auto key = std::make_pair(reqt.getFirstType()->getCanonicalType(), proto); - + addedConformances.insert({key, substConformance}); } } } - + // Build the generic signature with the additional collected requirements. if (!addedRequirements.empty()) { upperBoundGenericSig = buildGenericSignature(decl->getASTContext(), @@ -2479,24 +2543,24 @@ class IsBindableVisitor return added->second; } // Otherwise, use the conformance from the original map. - + return substSubMap.lookupConformance(dependentType, conformedProtocol); }); - + LLVM_DEBUG(llvm::dbgs() << "\nGeneric signature with conditional reqts:\n"; upperBoundGenericSig.print(llvm::dbgs()); upperBoundSubstMap.dump(llvm::dbgs())); } } - + auto upperBoundGenericEnv = upperBoundGenericSig.getGenericEnvironment(); - + for (auto gpTy : upperBoundGenericSig.getGenericParams()) { auto gp = gpTy->getCanonicalType(); - + auto orig = gp.subst(origSubMap)->getCanonicalType(); auto subst = gp.subst(substSubMap)->getCanonicalType(); - + // The new type is upper-bounded by the constraints the nominal type // requires. The substitution operation may be interested in transforming // the substituted type's conformances to these protocols. @@ -2517,17 +2581,17 @@ class IsBindableVisitor paramSubstConformances.push_back(conformance); } } - + auto newParam = visit(orig, subst, paramUpperBound, paramSubstConformances); if (!newParam) return CanType(); - + newParams.push_back(newParam); newParamsMap.insert({gp->castTo(), newParam}); didChange |= (newParam != subst); } - + SmallVector newConformances; // Collect conformances for the new substitutions, and verify that they don't @@ -2536,7 +2600,7 @@ class IsBindableVisitor if (req.getKind() != RequirementKind::Conformance) continue; auto canTy = req.getFirstType()->getCanonicalType(); - + // Verify the generic requirements, if the subst type is bound to // concrete type. auto *proto = req.getProtocolDecl(); @@ -2552,13 +2616,13 @@ class IsBindableVisitor return CanType(); } } - + // Gather the conformances for the new binding type, if the type changed. if (didChange) { auto newSubstTy = req.getFirstType().subst( QueryTypeSubstitutionMap{newParamsMap}, LookUpConformanceInModule(moduleDecl)); - + if (newSubstTy->isTypeParameter()) { newConformances.push_back(ProtocolConformanceRef(proto)); } else { @@ -2574,7 +2638,7 @@ class IsBindableVisitor if (!didChange) return substType; - + // Build the new substituted generic type. auto newSubMap = SubstitutionMap::get(genericSig, newParams, @@ -2582,7 +2646,7 @@ class IsBindableVisitor return decl->getDeclaredInterfaceType().subst(newSubMap) ->getCanonicalType(); } - + CanType visitNominalType(NominalType *nom, CanType subst, ArchetypeType* upperBound, ArrayRef substConformances) { @@ -2590,7 +2654,7 @@ class IsBindableVisitor auto nomDecl = nom->getDecl(); if (nom->getDecl() != substNom->getDecl()) return CanType(); - + // If the type is generic (because it's a nested type in a generic context), // process the generic type bindings. if (!isa(nomDecl) && nomDecl->isGenericContext()) { @@ -2602,29 +2666,29 @@ class IsBindableVisitor } return CanType(); } - + CanType visitAnyMetatypeType(AnyMetatypeType *meta, CanType subst, ArchetypeType*, ArrayRef) { if (auto substMeta = dyn_cast(subst)) { if (substMeta->getKind() != meta->getKind()) return CanType(); - + auto substInstance = visit(meta->getInstanceType()->getCanonicalType(), substMeta->getInstanceType()->getCanonicalType(), nullptr, {}); if (!substInstance) return CanType(); - + if (substInstance == substMeta.getInstanceType()) return subst; - + return isa(substMeta) ? CanType(CanExistentialMetatypeType::get(substInstance)) : CanType(CanMetatypeType::get(substInstance)); } return CanType(); } - + CanType visitTupleType(TupleType *tuple, CanType subst, ArchetypeType*, ArrayRef) { if (auto substTuple = dyn_cast(subst)) { @@ -2654,7 +2718,7 @@ class IsBindableVisitor } return CanType(); } - + CanType visitDependentMemberType(DependentMemberType *dt, CanType subst, ArchetypeType*, ArrayRef) { return subst; @@ -2663,13 +2727,13 @@ class IsBindableVisitor ArchetypeType*, ArrayRef) { return subst; } - + CanType visitFunctionType(FunctionType *func, CanType subst, ArchetypeType*, ArrayRef) { if (auto substFunc = dyn_cast(subst)) { if (!func->hasSameExtInfoAs(substFunc)) return CanType(); - + if (func->getParams().size() != substFunc->getParams().size()) return CanType(); @@ -2680,16 +2744,16 @@ class IsBindableVisitor auto substParam = substFunc.getParams()[i]; if (param.getParameterFlags() != substParam.getParameterFlags()) return CanType(); - + auto newParamTy = visit(param.getPlainType(), substParam.getPlainType(), nullptr, {}); if (!newParamTy) return CanType(); - + newParams.push_back(substParam.withType(newParamTy)); didChange = didChange | (newParamTy != substParam.getPlainType()); } - + auto newReturn = visit(func->getResult()->getCanonicalType(), substFunc->getResult()->getCanonicalType(), nullptr, {}); @@ -2702,7 +2766,7 @@ class IsBindableVisitor } return CanType(); } - + CanType visitSILFunctionType(SILFunctionType *func, CanType subst, ArchetypeType*, ArrayRef) { if (auto substFunc = dyn_cast(subst)) { @@ -2745,48 +2809,48 @@ class IsBindableVisitor if (func->getPatternGenericSignature() != substFunc->getPatternGenericSignature()) return CanType(); - + auto sig = func->getPatternGenericSignature(); - + auto origSubs = func->getPatternSubstitutions(); auto substSubs = substFunc->getPatternSubstitutions(); - + for (unsigned i : indices(origSubs.getReplacementTypes())) { auto origType = origSubs.getReplacementTypes()[i]->getReducedType(sig); auto substType = substSubs.getReplacementTypes()[i]->getReducedType(sig); - + auto newType = visit(origType, substType, nullptr, {}); - + if (!newType) return CanType(); - + // We can test SILFunctionTypes for bindability, but we can't // transform them. assert(newType == substType && "cannot transform SILFunctionTypes"); } - + return subst; } - + if (func->getParameters().size() != substFunc->getParameters().size()) return CanType(); if (func->getResults().size() != substFunc->getResults().size()) return CanType(); - + for (unsigned i : indices(func->getParameters())) { if (func->getParameters()[i].getConvention() != substFunc->getParameters()[i].getConvention()) return CanType(); - + auto origParam = func->getParameters()[i].getInterfaceType(); auto substParam = substFunc->getParameters()[i].getInterfaceType(); auto newParam = visit(origParam, substParam, nullptr, {}); if (!newParam) return CanType(); - + // We can test SILFunctionTypes for bindability, but we can't // transform them. assert(newParam == substParam @@ -2809,20 +2873,20 @@ class IsBindableVisitor assert(newResult == substResult && "cannot transform SILFunctionTypes"); } - + return subst; } - + return CanType(); } - + CanType visitBoundGenericType(BoundGenericType *bgt, CanType subst, ArchetypeType *upperBound, ArrayRef substConformances) { auto substBGT = dyn_cast(subst); if (!substBGT) return CanType(); - + if (bgt->getDecl() != substBGT->getDecl()) return CanType(); @@ -2845,7 +2909,7 @@ bool TypeBase::isBindableTo(Type ty) { // different types to the same type parameter, e.g. // `Foo`.isBindableTo(`Foo`). llvm::DenseMap Bindings; - + return !substituteBindingsTo(ty, [&](ArchetypeType *archetype, CanType binding, ArchetypeType*, ArrayRef) -> CanType { @@ -2867,7 +2931,7 @@ bool TypeBase::isBindableToSuperclassOf(Type ty) { // Do an exact match if no archetypes are involved. if (!hasArchetype()) return isExactSuperclassOf(ty); - + // For there to be a superclass relationship, // the potential subtype must be a class or superclass-bounded archetype. if (!ty->mayHaveSuperclass()) @@ -3047,7 +3111,7 @@ getForeignRepresentable(Type type, ForeignLanguage language, ProtocolConformance *> { return { ForeignRepresentableKind::None, nullptr }; }; - + // If type has an error let's fail early. if (type->hasError()) return failure(); @@ -3168,7 +3232,7 @@ getForeignRepresentable(Type type, ForeignLanguage language, // Note: works around a broken Unmanaged<> definition. if (!boundGenericType || boundGenericType->getGenericArgs().size() != 1) return failure(); - + auto typeArgument = boundGenericType->getGenericArgs()[0]; if (typeArgument->isTriviallyRepresentableIn(language, dc)) return { ForeignRepresentableKind::Trivial, nullptr }; @@ -3263,7 +3327,7 @@ getForeignRepresentable(Type type, ForeignLanguage language, if (wasOptional && !result.isRepresentableAsOptional()) return failure(); - + // If our nominal type has type arguments, make sure they are // representable as well. Because type arguments are not actually // translated separately, whether they are trivially representable @@ -3299,16 +3363,16 @@ getForeignRepresentable(Type type, ForeignLanguage language, break; } } - + return failure(); - + case ForeignRepresentableKind::Object: case ForeignRepresentableKind::Bridged: case ForeignRepresentableKind::BridgedError: break; } } - + // Specialize the conformance we were given for the type we're testing. if (result.getKind() == ForeignRepresentableKind::Bridged && !result.getConformance()->getType()->isEqual(type)) { @@ -3907,8 +3971,10 @@ CanExistentialType CanExistentialType::get(CanType constraint) { void ProtocolCompositionType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef Members, InvertibleProtocolSet Inverses, - bool HasExplicitAnyObject) { + bool HasExplicitAnyObject, + bool HasExplicitReflectable) { ID.AddBoolean(HasExplicitAnyObject); + ID.AddBoolean(HasExplicitReflectable); for (auto T : Members) ID.AddPointer(T.getPointer()); for (auto IP : Inverses) @@ -3963,28 +4029,36 @@ bool ProtocolCompositionType::requiresClass() { /// Constructs a protocol composition corresponding to the `Any` type. Type ProtocolCompositionType::theAnyType(const ASTContext &C) { - return ProtocolCompositionType::get(C, {}, /*HasExplicitAnyObject=*/false); + return ProtocolCompositionType::get(C, {}, /*HasExplicitAnyObject=*/false, false); } /// Constructs a protocol composition containing the `AnyObject` constraint. Type ProtocolCompositionType::theAnyObjectType(const ASTContext &C) { - return ProtocolCompositionType::get(C, {}, /*HasExplicitAnyObject=*/true); + return ProtocolCompositionType::get(C, {}, /*HasExplicitAnyObject=*/true, false); +} + +/// Constructs a protocol composition containing the `Reflectable` constraint. +Type ProtocolCompositionType::theReflectableType(const ASTContext &C) { + return ProtocolCompositionType::get(C, {}, /*HasExplicitAnyObject=*/false, true); } Type ProtocolCompositionType::get(const ASTContext &C, ArrayRef Members, - bool HasExplicitAnyObject) { + bool HasExplicitAnyObject, + bool HasExplicitReflectable) { return ProtocolCompositionType::get(C, Members, /*Inverses=*/{}, - HasExplicitAnyObject); + HasExplicitAnyObject, + HasExplicitReflectable); } Type ProtocolCompositionType::get(const ASTContext &C, ArrayRef Members, InvertibleProtocolSet Inverses, - bool HasExplicitAnyObject) { - // Fast path for 'AnyObject' and 'Any'. + bool HasExplicitAnyObject, + bool HasExplicitReflectable) { + // Fast path for 'AnyObject', 'Any' and 'Reflectable'. if (Members.empty()) { - return build(C, Members, Inverses, HasExplicitAnyObject); + return build(C, Members, Inverses, HasExplicitAnyObject, HasExplicitReflectable); } assert(llvm::none_of(Members, [](Type t){return t->is();})); @@ -3992,7 +4066,7 @@ Type ProtocolCompositionType::get(const ASTContext &C, // Whether this composition has an `AnyObject` or protocol-inverse member // that is not reflected in the Members array. auto haveExtraMember = [&]{ - return HasExplicitAnyObject || !Inverses.empty(); + return HasExplicitReflectable || HasExplicitAnyObject || !Inverses.empty(); }; // If there's a single member and no layout constraint or inverses, @@ -4003,14 +4077,14 @@ Type ProtocolCompositionType::get(const ASTContext &C, for (Type t : Members) { if (!t->isCanonical()) - return build(C, Members, Inverses, HasExplicitAnyObject); + return build(C, Members, Inverses, HasExplicitAnyObject, HasExplicitReflectable); } - + Type Superclass; SmallVector Protocols; ParameterizedProtocolMap Parameterized; for (Type t : Members) { - addProtocols(t, Protocols, Parameterized, Superclass, HasExplicitAnyObject); + addProtocols(t, Protocols, Parameterized, Superclass, HasExplicitAnyObject, HasExplicitReflectable); } // The presence of a superclass constraint makes AnyObject redundant. @@ -4046,7 +4120,7 @@ Type ProtocolCompositionType::get(const ASTContext &C, if (CanTypes.size() == 1 && !haveExtraMember()) return CanTypes.front(); - return build(C, CanTypes, Inverses, HasExplicitAnyObject); + return build(C, CanTypes, Inverses, HasExplicitAnyObject, HasExplicitReflectable); } CanType ProtocolCompositionType::getMinimalCanonicalType( @@ -4124,7 +4198,7 @@ CanType ProtocolCompositionType::getMinimalCanonicalType( // The resulting composition is necessarily canonical. return CanType(build(Ctx, MinimalMembers, MinimalInverses, - MinimalHasExplicitAnyObject)); + MinimalHasExplicitAnyObject, false)); } ClangTypeInfo AnyFunctionType::getClangTypeInfo() const { @@ -4422,7 +4496,7 @@ case TypeKind::Id: return *this; } - + case TypeKind::SILBlockStorage: { auto storageTy = cast(base); Type transCap = storageTy->getCaptureType().transformWithPosition( @@ -4479,7 +4553,7 @@ case TypeKind::Id: boxTy->getSubstitutions()); return boxTy; } - + case TypeKind::SILFunction: { auto fnTy = cast(base); bool changed = false; @@ -4652,12 +4726,12 @@ case TypeKind::Id: return BoundGenericType::get(bound->getDecl(), substParentTy, substArgs); } - + case TypeKind::OpaqueTypeArchetype: { auto opaque = cast(base); if (opaque->getSubstitutions().empty()) return *this; - + SmallVector newSubs; bool anyChanged = false; for (auto replacement : opaque->getSubstitutions().getReplacementTypes()) { @@ -4669,10 +4743,10 @@ case TypeKind::Id: if (replacement.getPointer() != newReplacement.getPointer()) anyChanged = true; } - + if (!anyChanged) return *this; - + // FIXME: This re-looks-up conformances instead of transforming them in // a systematic way. auto sig = opaque->getDecl()->getGenericSignature(); @@ -5052,7 +5126,7 @@ case TypeKind::Id: if (thrownError.getPointer() != origThrownError.getPointer()) isUnchanged = false; } - + // Transform the global actor. Type globalActorType; if (Type origGlobalActorType = function->getGlobalActor()) { @@ -5182,7 +5256,7 @@ case TypeKind::Id: TypePosition::Invariant, fn); if (!objectTy || objectTy->hasError()) return objectTy; - + return objectTy.getPointer() == inout->getObjectType().getPointer() ? *this : InOutType::get(objectTy); } @@ -5230,13 +5304,14 @@ case TypeKind::Id: if (substMember.getPointer() != member.getPointer()) anyChanged = true; } - + if (!anyChanged) return *this; - + return ProtocolCompositionType::get(Ptr->getASTContext(), substMembers, - pc->hasExplicitAnyObject()); + pc->hasExplicitAnyObject(), + pc->hasExplicitReflectable()); } case TypeKind::ParameterizedProtocol: { @@ -5273,7 +5348,7 @@ case TypeKind::Id: substArgs); } } - + llvm_unreachable("Unhandled type in transformation"); } @@ -5316,7 +5391,7 @@ TypeTraitResult TypeBase::canBeClass() { return TypeTraitResult::CanBe; if (isa(self)) return TypeTraitResult::CanBe; - + return TypeTraitResult::IsNot; } @@ -5703,7 +5778,7 @@ bool TypeBase::hasSimpleTypeRepr() const { // 'Any', 'AnyObject' and single protocol compositions are simple auto composition = cast(this); auto memberCount = composition->getMembers().size(); - if (composition->hasExplicitAnyObject()) + if (composition->hasExplicitAnyObject() || composition->hasExplicitReflectable()) return memberCount == 0; return memberCount <= 1; } diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp index 0820d3715d1f3..fdfe706e400ae 100644 --- a/lib/AST/TypeJoinMeet.cpp +++ b/lib/AST/TypeJoinMeet.cpp @@ -404,7 +404,7 @@ CanType TypeJoin::computeProtocolCompositionJoin(ArrayRef firstMembers, return TheAnyType; auto &ctx = result[0]->getASTContext(); - return ProtocolCompositionType::get(ctx, result, false)->getCanonicalType(); + return ProtocolCompositionType::get(ctx, result, false, false)->getCanonicalType(); } CanType TypeJoin::visitProtocolCompositionType(CanType second) { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b41c29e22a7d2..3cfe3b5455066 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -5703,8 +5703,9 @@ namespace { template bool inheritanceListContainsProtocol(D decl, const ProtocolDecl *proto) { bool anyObject = false; + bool reflectable = false; for (const auto &found : - getDirectlyInheritedNominalTypeDecls(decl, anyObject)) { + getDirectlyInheritedNominalTypeDecls(decl, anyObject, reflectable)) { if (auto protoDecl = dyn_cast(found.Item)) if (protoDecl == proto || protoDecl->inheritsFrom(proto)) return true; @@ -8752,6 +8753,13 @@ GenericSignature ClangImporter::Implementation::buildGenericSignature( LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class))); continue; } + if (inheritedType->isReflectable()) { + requirements.push_back( + Requirement( + RequirementKind::Layout, paramType, + LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Reflectable))); + continue; + } if (inheritedType->getClassOrBoundGenericClass()) { requirements.push_back( Requirement(RequirementKind::Superclass, paramType, inheritedType)); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index c57624c615de1..db27d9fb8be72 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -629,7 +629,7 @@ namespace { // we don't want to break arrays of size PATH_MAX. if (size > 4096) return Type(); - + if (size == 1) return ParenType::get(elementType->getASTContext(), elementType); @@ -1241,7 +1241,7 @@ namespace { importedType = ExistentialType::get( ProtocolCompositionType::get(Impl.SwiftContext, members, - /*HasExplicitAnyObject=*/false)); + /*HasExplicitAnyObject=*/false, false)); } // Class or Class

maps to an existential metatype. @@ -1677,7 +1677,7 @@ ImportedType ClangImporter::Implementation::importType( if (auto nullability = type->getNullability()) { bool stripNonResultOptionality = importKind == ImportTypeKind::CompletionHandlerResultParameter; - + optionality = translateNullability(*nullability, stripNonResultOptionality); } @@ -1852,7 +1852,7 @@ class GetSendableType : members.push_back(proto->getDeclaredInterfaceType()); return { - ProtocolCompositionType::get(ctx, members, explicitAnyObject), true }; + ProtocolCompositionType::get(ctx, members, explicitAnyObject, false), true }; } /// Visitor action: Recurse into the children of this type and try to add @@ -2560,13 +2560,13 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( return typePart->isEqual(genericParam->getDeclaredInterfaceType()); }); }; - + // Make sure all generic parameters are accounted for in the function signature. for (auto genericParam : genericParams) { bool shouldCheckResultType = resultType && resultType->hasTypeParameter(); if (genericParamTypeUsedInSignature(genericParam, shouldCheckResultType)) continue; - + // If this generic parameter is not used in the function signature, // add a new parameter that accepts a metatype corresponding to that // generic parameter. diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 6b89321c92a4e..9a04748322e2b 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -4028,6 +4028,8 @@ NodePointer Demangler::demangleGenericRequirement() { name = "D"; } else if (c == 'T') { name = "T"; + } else if (c == 'B') { + name = "B"; } else if (c == 'E') { size = demangleIndexAsNode(); if (!size) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f95ea0311fb99..e7981558461a3 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2732,8 +2732,8 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.SanitizeCoverage.CoverageType = llvm::SanitizerCoverageOptions::SCK_Edge; } - if (Args.hasArg(OPT_disable_reflection_metadata)) { - Opts.ReflectionMetadata = ReflectionMetadataMode::None; + if (Args.hasArg(OPT_disable_reflection_metadata) || Args.hasArg(OPT_enable_opt_in_reflection_metadata)) { + Opts.ReflectionMetadata = ReflectionMetadataMode::OptIn; Opts.EnableReflectionNames = false; } diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index 82edff684f246..59ea624f621d2 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -556,7 +556,7 @@ Type CompletionLookup::eraseArchetypes(Type type, GenericSignature genericSig) { for (auto proto : protos) types.push_back(proto->getDeclaredInterfaceType()); return ProtocolCompositionType::get(Ctx, types, - /*HasExplicitAnyObject=*/false); + /*HasExplicitAnyObject=*/false, false); }; if (auto *genericFuncType = type->getAs()) { diff --git a/lib/IDE/CompletionOverrideLookup.cpp b/lib/IDE/CompletionOverrideLookup.cpp index b422a045c19f2..7c7552cdf2d56 100644 --- a/lib/IDE/CompletionOverrideLookup.cpp +++ b/lib/IDE/CompletionOverrideLookup.cpp @@ -132,7 +132,7 @@ Type CompletionOverrideLookup::getOpaqueResultType( return opaqueTypes.front(); } return ProtocolCompositionType::get(VD->getASTContext(), opaqueTypes, - hasExplicitAnyObject); + hasExplicitAnyObject, false); } void CompletionOverrideLookup::addValueOverride( diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 45987a560d280..0c96203aca95b 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -6780,6 +6780,9 @@ GenericArgumentMetadata irgen::addGenericRequirements( [&]{ B.addInt32((uint32_t)GenericRequirementLayoutKind::Class); }); break; } + case LayoutConstraintKind::Reflectable: { + break; + } default: // No other layout constraints are supported in source-level Swift // today. diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index a8f35c548f39c..aa503ee66bec6 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -348,9 +348,15 @@ class MissingConformanceFailure final : public RequirementFailure { bool diagnoseAsAmbiguousOperatorRef(); DiagOnDecl getDiagnosticOnDecl() const override { - return (getRequirement().getKind() == RequirementKind::Layout ? - diag::type_does_not_conform_anyobject_decl_owner : - diag::type_does_not_conform_decl_owner); + if (getRequirement().getKind() == RequirementKind::Layout) { + if (getRequirement().getLayoutConstraint()->isReflectable()) + return diag::type_does_not_conform_reflectable_decl_owner; + return diag::type_does_not_conform_anyobject_decl_owner; + } + + // if (auto layoutConstraint = layout.getLayoutConstraint()) { + // if (layoutConstraint->isReflectable()) { + return diag::type_does_not_conform_decl_owner; } DiagInReference getDiagnosticInRereference() const override { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 423754a5245db..613cdcf7e165f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3944,6 +3944,39 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2, auto layout = type2->getExistentialLayout(); if (auto layoutConstraint = layout.getLayoutConstraint()) { + if (layoutConstraint->isReflectable()) { + if (kind == ConstraintKind::ConformsTo) { + if (!type1->satisfiesReflectableConstraint()) { + if (shouldAttemptFixes()) { + if (auto last = locator.last()) { + // If solver is in diagnostic mode and type1 is a hole, or if this + // is a superclass requirement, let's consider `AnyObject` + // conformance solved. The actual superclass requirement + // will also fail (because type can't satisfy it), and it's + // more interesting for diagnostics. + auto req = last->getAs(); + if (!req) + return getTypeMatchFailure(locator); + + // Superclass constraints are never satisfied by existentials, + // even those that contain the superclass a la `any C & P`. + // if (!type1->isExistentialType() && + // (type1->isPlaceholder() || + // req->getRequirementKind() == RequirementKind::Superclass)) + // return getTypeMatchSuccess(); + + auto *fix = fixRequirementFailure(*this, type1, type2, locator); + if (fix && !recordFix(fix)) { + recordFixedRequirement(getConstraintLocator(locator), type2); + return getTypeMatchSuccess(); + } + } + } + + return getTypeMatchFailure(locator); + } + } + } if (layoutConstraint->isClass()) { if (kind == ConstraintKind::ConformsTo) { if (!type1->satisfiesClassConstraint()) { @@ -15559,6 +15592,12 @@ void ConstraintSystem::addConstraint(Requirement req, kind = ConstraintKind::Bind; break; case RequirementKind::Layout: + if (req.getLayoutConstraint()->isReflectable()) { + auto firstType = req.getFirstType(); + auto reflectable = getASTContext().getReflectableConstraint(); + addConstraint(ConstraintKind::ConformsTo, firstType, reflectable, locator); + } + // Only a class constraint can be modeled as a constraint, and only that can // appear outside of a @_specialize at the moment anyway. if (req.getLayoutConstraint()->isClass()) { diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 61654833f9176..96e0f39ae8443 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -152,10 +152,10 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, // Verify warn_unqualified_access uses. checkUnqualifiedAccessUse(DRE); - + // Verify that special decls are eliminated. checkForDeclWithSpecialTypeCheckingSemantics(DRE); - + // Verify that `unsafeBitCast` isn't misused. checkForSuspiciousBitCasts(DRE, nullptr); } @@ -176,7 +176,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, if (auto *Call = dyn_cast(E)) { // Warn about surprising implicit optional promotions. checkOptionalPromotions(Call); - + // Check the callee, looking through implicit conversions. auto base = Call->getFn(); unsigned uncurryLevel = 0; @@ -248,7 +248,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } } } - + // If we have an assignment expression, scout ahead for acceptable _'s. if (auto *AE = dyn_cast(E)) { auto destExpr = AE->getDest(); @@ -323,7 +323,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, // Diagnose tuple expressions with duplicate element label. diagnoseDuplicateLabels(tupleExpr->getLoc(), tupleExpr->getElementNames()); - + // Diagnose attempts to form a tuple with any noncopyable elements. if (E->getType()->isNoncopyable(DC) && !Ctx.LangOpts.hasFeature(Feature::MoveOnlyTuples)) { @@ -830,7 +830,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, .fixItInsert(DRE->getStartLoc(), namePlusDot); } } - + void checkForDeclWithSpecialTypeCheckingSemantics(const DeclRefExpr *DRE) { // Referencing type(of:) and other decls with special type-checking // behavior as functions is not implemented. Maybe we could wrap up the @@ -841,7 +841,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, DRE->getDecl()->getBaseIdentifier()); } } - + enum BitcastableNumberKind { BNK_None = 0, BNK_Int8, @@ -875,23 +875,23 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, MATCH_DECL(Float) MATCH_DECL(Double) #undef MATCH_DECL - + return BNK_None; } - + static constexpr unsigned BNKPair(BitcastableNumberKind a, BitcastableNumberKind b) { return (a << 8) | b; } - + void checkForSuspiciousBitCasts(DeclRefExpr *DRE, Expr *Parent = nullptr) { if (DRE->getDecl() != Ctx.getUnsafeBitCast()) return; - + if (DRE->getDeclRef().getSubstitutions().empty()) return; - + // Don't check the same use of unsafeBitCast twice. if (!AlreadyDiagnosedBitCasts.insert(DRE).second) return; @@ -902,7 +902,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, // Warn about `unsafeBitCast` formulations that are undefined behavior // or have better-defined alternative APIs that can be used instead. - + // If we have a parent ApplyExpr that calls bitcast, extract the argument // for fixits. Expr *subExpr = nullptr; @@ -921,7 +921,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, Lexer::getLocForEndOfToken(Ctx.SourceMgr, apply->getEndLoc())); } - + // Casting to the same type or a superclass is a no-op. if (toTy->isEqual(fromTy) || toTy->isExactSuperclassOf(fromTy)) { @@ -935,7 +935,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } return; } - + if (auto fromFnTy = fromTy->getAs()) { if (auto toFnTy = toTy->getAs()) { // Casting a nonescaping function to escaping is UB. @@ -954,7 +954,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, return; } } - + // Unchecked casting to a subclass is better done by unsafeDowncast. if (fromTy->isBindableToSuperclassOf(toTy)) { Ctx.Diags.diagnose(DRE->getLoc(), diag::bitcasting_to_downcast, @@ -991,13 +991,13 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, before = "UnsafeMutablePointer(mutating: "; after = ")"; break; - + case PTK_UnsafeRawPointer: // UnsafeRawPointer(pointer) before = "UnsafeRawPointer("; after = ")"; break; - + case PTK_UnsafeMutableRawPointer: // UnsafeMutableRawPointer(mutating: rawPointer) before = fromPTK == PTK_UnsafeMutablePointer @@ -1015,7 +1015,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } return; } - + // Casting to a different typed pointer type should use // withMemoryRebound. if (!isRawPointerKind(fromPTK) && !isRawPointerKind(toPTK)) { @@ -1024,7 +1024,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, fromTy, toTy); return; } - + // Casting a raw pointer to a typed pointer should bind the memory // (or assume it's already bound). assert(isRawPointerKind(fromPTK) && !isRawPointerKind(toPTK) @@ -1066,7 +1066,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } return; } - + StringRef replaceBefore, replaceAfter; llvm::Optional> diagID; SmallString<64> replaceBeforeBuf; @@ -1098,7 +1098,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ")"; break; - + // Combos that can be bitPattern-ed with a constructor and sign flip case BNKPair(BNK_Int32, BNK_Float): case BNKPair(BNK_Int64, BNK_Double): @@ -1115,14 +1115,14 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = "))"; break; - + // Combos that can be bitPattern-ed with a property case BNKPair(BNK_Float, BNK_UInt32): case BNKPair(BNK_Double, BNK_UInt64): diagID = diag::bitcasting_for_number_bit_pattern_property; replaceAfter = ".bitPattern"; break; - + // Combos that can be bitPattern-ed with a property and sign flip case BNKPair(BNK_Float, BNK_Int32): case BNKPair(BNK_Double, BNK_Int64): @@ -1149,12 +1149,12 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, llvm::raw_svector_ostream os(replaceBeforeBuf); toTy->print(os); os << "(bitPattern: "; - + if (fromBNK == BNK_Int) os << "Int"; else os << "UInt"; - + if (toBNK == BNK_Float || toBNK == BNK_Int32 || toBNK == BNK_UInt32) @@ -1173,7 +1173,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, llvm::raw_svector_ostream os(replaceBeforeBuf); toTy->print(os); os << "(bitPattern: UInt"; - + if (toBNK == BNK_Float || toBNK == BNK_Int32 || toBNK == BNK_UInt32) @@ -1184,7 +1184,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ")))"; break; - + // Combos that can be bitPattern-ed then converted from a sized type // to (U)Int. case BNKPair(BNK_Int32, BNK_UInt): @@ -1208,7 +1208,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = "))"; break; - + case BNKPair(BNK_Float, BNK_UInt): case BNKPair(BNK_Double, BNK_UInt): diagID = diag::bitcasting_for_number_bit_pattern_property; @@ -1220,7 +1220,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ".bitPattern)"; break; - + case BNKPair(BNK_Float, BNK_Int): case BNKPair(BNK_Double, BNK_Int): diagID = diag::bitcasting_for_number_bit_pattern_property; @@ -1232,7 +1232,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ".bitPattern))"; break; - + // Combos that should be done with a value-preserving initializer. case BNKPair(BNK_Int, BNK_Int32): case BNKPair(BNK_Int, BNK_Int64): @@ -1251,13 +1251,13 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ")"; break; - + default: // Leave other combos alone. break; } } - + // Casting a pointer to an int or back should also use bitPattern // initializers. if (fromPointee && toBNK) { @@ -1273,7 +1273,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ")"; break; - + case BNK_UInt64: case BNK_UInt32: case BNK_Int64: @@ -1291,7 +1291,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = "))"; break; - + default: break; } @@ -1309,7 +1309,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, replaceBefore = replaceBeforeBuf; replaceAfter = ")"; break; - + case BNK_UInt64: case BNK_UInt32: case BNK_Int64: @@ -1332,7 +1332,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, break; } } - + if (diagID) { auto d = Ctx.Diags.diagnose(DRE->getLoc(), *diagID, fromTy, toTy); if (subExpr) { @@ -1346,7 +1346,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } } - + /// Return true if this is a 'nil' literal. This looks /// like this if the type is Optional: /// @@ -1393,7 +1393,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, auto DRE = dyn_cast(fnExpr); if (!DRE || !DRE->getDecl()->isOperator()) return; - + auto lhs = BE->getLHS(); auto rhs = BE->getRHS(); auto calleeName = DRE->getDecl()->getBaseName(); @@ -1411,7 +1411,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, Lexer::getLocForEndOfToken(Ctx.SourceMgr, rhs->getEndLoc())); return; } - + if (calleeName == "==" || calleeName == "!=" || calleeName == "===" || calleeName == "!==") { if (((subExpr = isImplicitPromotionToOptional(lhs)) && @@ -1420,7 +1420,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, (subExpr = isImplicitPromotionToOptional(rhs)))) { bool isTrue = calleeName == "!=" || calleeName == "!=="; bool isNilLiteral = isa(lhs) || isa(rhs); - + Ctx.Diags.diagnose(DRE->getLoc(), diag::nonoptional_compare_to_nil, subExpr->getType(), isNilLiteral, isTrue) .highlight(lhs->getSourceRange()) @@ -1488,7 +1488,7 @@ static void diagRecursivePropertyAccess(const Expr *E, const DeclContext *DC) { if (auto *AE = dyn_cast(E)) { subExpr = AE->getDest(); - + // If we couldn't flatten this expression, don't explode. if (!subExpr) return Action::Continue(E); @@ -1527,7 +1527,7 @@ static void diagRecursivePropertyAccess(const Expr *E, const DeclContext *DC) { Var->getName(), Accessor->isSetter()); } } - + // If this is a direct store in a "willSet", we reject this because // it is about to get overwritten. if (isStore && @@ -1545,7 +1545,7 @@ static void diagRecursivePropertyAccess(const Expr *E, const DeclContext *DC) { if (MRE->getMember().getDecl() == Var && isa(MRE->getBase()) && isImplicitSelfUse(MRE->getBase())) { - + if (MRE->getAccessSemantics() == AccessSemantics::Ordinary) { bool shouldDiagnose = false; // Warn about any property access in the getter. @@ -1843,7 +1843,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, emitFixIts(Diags, memberLoc, ACE); return Action::SkipChildren(E); } - + if (isImplicitSelfParamUseLikelyToCauseCycle(E, ACE)) Diags.diagnose(E->getLoc(), diag::implicit_use_of_self_in_closure) .warnUntilSwiftVersionIf(shouldOnlyWarn(E), 6); @@ -1922,7 +1922,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, .fixItInsert(memberLoc, "self."); } } - + /// Diagnose any captures which might have been an attempt to capture /// \c self strongly, but do not actually enable implicit \c self. Returns /// whether there were any such captures to diagnose. @@ -1935,7 +1935,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, if (!VD->getInterfaceType()->is()) { Diags.diagnose(VD->getLoc(), diag::note_other_self_capture); } - + return true; } return false; @@ -2024,7 +2024,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, DC = DC->getParent(); } } - + const_cast(E)->walk(DiagnoseWalker(ctx, ACE)); } @@ -2063,7 +2063,7 @@ bool TypeChecker::getDefaultGenericArgumentsString( members.push_back(typeDecl->getASTContext().getAnyObjectConstraint()); auto type = ProtocolCompositionType::get(typeDecl->getASTContext(), - members, hasExplicitAnyObject); + members, hasExplicitAnyObject, false); if (type->isObjCExistentialType() || type->isAny()) { genericParamText << type; @@ -2081,7 +2081,7 @@ bool TypeChecker::getDefaultGenericArgumentsString( llvm::interleave(typeDecl->getInnermostGenericParamTypes(), printGenericParamSummary, [&] { genericParamText << ", "; }); - + genericParamText << ">"; return true; } @@ -2633,10 +2633,10 @@ class VarDeclUsageChecker : public ASTWalker { RK_Defined = 1, ///< Whether it was ever defined in this scope. RK_Read = 2, ///< Whether it was ever read. RK_Written = 4, ///< Whether it was ever written or passed inout. - + RK_CaptureList = 8 ///< Var is an entry in a capture list. }; - + /// These are all of the variables that we are tracking. VarDecls get added /// to this when the declaration is seen. We use a MapVector to keep the /// diagnostics emission in deterministic order. @@ -2656,9 +2656,9 @@ class VarDeclUsageChecker : public ASTWalker { #ifndef NDEBUG llvm::SmallPtrSet AllExprsSeen; #endif - + bool sawError = false; - + VarDeclUsageChecker(const VarDeclUsageChecker &) = delete; void operator=(const VarDeclUsageChecker &) = delete; @@ -2693,18 +2693,18 @@ class VarDeclUsageChecker : public ASTWalker { // If the variable is implicit, ignore it. if (VD->isImplicit() || VD->getLoc().isInvalid()) return false; - + // If the variable is computed, ignore it. if (!VD->hasStorage()) return false; - + // If the variable was invalid, ignore it and notice that the code is // malformed. if (VD->isInvalid()) { sawError = true; return false; } - + // If the variable is already unnamed, ignore it. if (!VD->hasName() || VD->getName().str() == "_") return false; @@ -2721,7 +2721,7 @@ class VarDeclUsageChecker : public ASTWalker { void markBaseOfStorageUse(Expr *E, ConcreteDeclRef decl, unsigned flags); void markBaseOfStorageUse(Expr *E, bool isMutating); - + void markStoredOrInOutExpr(Expr *E, unsigned Flags); MacroWalking getMacroWalkingBehavior() const override { @@ -2738,7 +2738,7 @@ class VarDeclUsageChecker : public ASTWalker { // for them. if (auto *ICD = dyn_cast(D)) handleIfConfig(ICD); - + // If this is a VarDecl, then add it to our list of things to track. if (auto *vd = dyn_cast(D)) { if (shouldTrackVarDecl(vd)) { @@ -2838,7 +2838,7 @@ class VarDeclUsageChecker : public ASTWalker { } } } - + // A fallthrough dest case's bound variable means the source case's // var of the same name is read. if (auto *fallthroughStmt = dyn_cast(S)) { @@ -2846,7 +2846,7 @@ class VarDeclUsageChecker : public ASTWalker { SmallVector sourceVars; auto sourcePattern = sourceCase->getCaseLabelItems()[0].getPattern(); sourcePattern->collectVariables(sourceVars); - + auto destCase = fallthroughStmt->getFallthroughDest(); auto destPattern = destCase->getCaseLabelItems()[0].getPattern(); destPattern->forEachVariable([&](VarDecl *V) { @@ -2872,7 +2872,7 @@ class VarDeclUsageChecker : public ASTWalker { return Action::Continue(S); } }; - + /// An AST walker that determines the underlying type of an opaque return decl /// from its associated function body. class OpaqueUnderlyingTypeChecker : public ASTWalker { @@ -3373,12 +3373,12 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { isWrittenLet = (access & RK_Written) != 0; access &= ~RK_Written; } - + // If this variable has WeakStorageType, then it can be mutated in ways we // don't know. if (var->getInterfaceType()->is()) access |= RK_Written; - + // Diagnose variables that were never used (other than their // initialization). // @@ -3391,7 +3391,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { var->getName()); continue; } - + // If the source of the VarDecl is a trivial PatternBinding with only a // single binding, rewrite the whole thing into an assignment. // let x = foo() @@ -3505,7 +3505,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { continue; } } - + // Otherwise, this is something more complex, perhaps // let (a,b) = foo() if (isWrittenLet) { @@ -3521,7 +3521,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { } continue; } - + // If this is a mutable 'var', and it was never written to, suggest // upgrading to 'let'. if (var->getIntroducer() == VarDecl::Introducer::Var @@ -3573,7 +3573,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { continue; } } - + // If this is a variable that was only written to, emit a warning. if ((access & RK_Read) == 0) { Diags.diagnose(var->getLoc(), diag::variable_never_read, var->getName()); @@ -3645,22 +3645,22 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) { sawError = true; return; } - + // Ignore parens and other easy cases. E = E->getSemanticsProvidingExpr(); - + // If we found a decl that is being assigned to, then mark it. if (auto *DRE = dyn_cast(E)) { addMark(DRE->getDecl(), Flags); return; } - + if (auto *TE = dyn_cast(E)) { for (auto &elt : TE->getElements()) markStoredOrInOutExpr(elt, Flags); return; } - + // If this is an assignment into a mutating subscript lvalue expr, then we // are mutating the base expression. We also need to visit the index // expressions as loads though. @@ -3670,7 +3670,7 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) { markBaseOfStorageUse(SE->getBase(), SE->getDecl(), Flags); return; } - + // Likewise for key path applications. An application of a WritableKeyPath // reads and writes its base; an application of a ReferenceWritableKeyPath // only reads its base; the other KeyPath types cannot be written at all. @@ -3683,10 +3683,10 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) { markBaseOfStorageUse(KPA->getBase(), isMutating); return; } - + if (auto *ioe = dyn_cast(E)) return markStoredOrInOutExpr(ioe->getSubExpr(), RK_Written|RK_Read); - + if (auto *MRE = dyn_cast(E)) { markBaseOfStorageUse(MRE->getBase(), MRE->getMember(), Flags); return; @@ -3694,7 +3694,7 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) { if (auto *TEE = dyn_cast(E)) return markStoredOrInOutExpr(TEE->getBase(), Flags); - + if (auto *FVE = dyn_cast(E)) return markStoredOrInOutExpr(FVE->getSubExpr(), Flags); @@ -3762,19 +3762,19 @@ ASTWalker::PreWalkResult VarDeclUsageChecker::walkToExprPre(Expr *E) { // about. if (auto *assign = dyn_cast(E)) { markStoredOrInOutExpr(assign->getDest(), RK_Written); - + // Don't walk into the LHS of the assignment, only the RHS. assign->getSrc()->walk(*this); return Action::SkipChildren(E); } - + // '&x' is a read and write of 'x'. if (auto *io = dyn_cast(E)) { markStoredOrInOutExpr(io->getSubExpr(), RK_Read|RK_Written); // Don't bother walking into this. return Action::SkipChildren(E); } - + // If we see an OpenExistentialExpr, remember the mapping for its OpaqueValue // and only walk the subexpr. if (auto *oee = dyn_cast(E)) { @@ -3789,7 +3789,7 @@ ASTWalker::PreWalkResult VarDeclUsageChecker::walkToExprPre(Expr *E) { mapping->walk(*this); return Action::SkipChildren(E); } - + // If we saw an ErrorExpr, take note of this. if (isa(E)) sawError = true; @@ -4093,7 +4093,7 @@ diagnoseMoveOnlyPatternMatchSubject(ASTContext &C, // pattern matched. Pattern matching is only implemented as a consuming // operation today, but we don't want to be stuck with that as the default // in the fullness of time when we get borrowing pattern matching later. - + // Don't bother if the subject wasn't given a valid type, or is a copyable // type. auto subjectType = subjectExpr->getType(); @@ -4119,7 +4119,7 @@ diagnoseMoveOnlyPatternMatchSubject(ASTContext &C, static void checkSwitch(ASTContext &ctx, const SwitchStmt *stmt, DeclContext *DC) { diagnoseMoveOnlyPatternMatchSubject(ctx, DC, stmt->getSubjectExpr()); - + // We want to warn about "case .Foo, .Bar where 1 != 100:" since the where // clause only applies to the second case, and this is surprising. for (auto cs : stmt->getCases()) { @@ -4129,27 +4129,27 @@ static void checkSwitch(ASTContext &ctx, const SwitchStmt *stmt, // If we find a "where", and there is a preceding item without a where, and // if they are on the same source line, then warn. auto items = cs->getCaseLabelItems(); - + // Don't do any work for the vastly most common case. if (items.size() == 1) continue; - + // Ignore the first item, since it can't have preceding ones. for (unsigned i = 1, e = items.size(); i != e; ++i) { // Must have a where clause. auto where = items[i].getGuardExpr(); if (!where) continue; - + // Preceding item must not. if (items[i-1].getGuardExpr()) continue; - + // Must be on the same source line. auto prevLoc = items[i-1].getStartLoc(); auto thisLoc = items[i].getStartLoc(); if (prevLoc.isInvalid() || thisLoc.isInvalid()) continue; - + auto &SM = ctx.SourceMgr; auto prevLineCol = SM.getLineAndColumnInBuffer(prevLoc); if (SM.getLineAndColumnInBuffer(thisLoc).first != prevLineCol.first) @@ -4158,7 +4158,7 @@ static void checkSwitch(ASTContext &ctx, const SwitchStmt *stmt, ctx.Diags.diagnose(items[i].getWhereLoc(), diag::where_on_one_item) .highlight(items[i].getPattern()->getSourceRange()) .highlight(where->getSourceRange()); - + // Whitespace it out to the same column as the previous item. std::string whitespace(prevLineCol.second-1, ' '); ctx.Diags.diagnose(thisLoc, diag::add_where_newline) @@ -4725,7 +4725,7 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond, ASTContext &ctx) { auto *p = cond.getPatternOrNull(); if (!p) return; - + if (auto *subExpr = isImplicitPromotionToOptional(cond.getInitializer())) { // If the subexpression was actually optional, then the pattern must be // checking for a type, which forced it to be promoted to a double optional @@ -5057,7 +5057,7 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E, size_t optionalityDifference = 0; if (!isOptionalToAnyCoercion(srcType, destType, optionalityDifference)) return; - + // If we're implicitly unwrapping from IUO to Any then emit a custom // diagnostic if (hasImplicitlyUnwrappedResult(subExpr)) { @@ -5078,7 +5078,7 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E, /* from */ srcType, /* to */ destType) .highlight(subExpr->getSourceRange()); } - + if (optionalityDifference == 1) { Ctx.Diags.diagnose(subExpr->getLoc(), diag::default_optional_to_any) .highlight(subExpr->getSourceRange()) @@ -5179,12 +5179,12 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E, auto uncurriedType = fnDecl->getInterfaceType()->getAs(); auto curriedType = uncurriedType->getResult()->getAs(); - // I don't know why you'd use a zero-arg interpolator, but it obviously + // I don't know why you'd use a zero-arg interpolator, but it obviously // doesn't interpolate an optional. if (curriedType->getNumParams() == 0) return false; - // If the first parameter explicitly accepts the type, this method + // If the first parameter explicitly accepts the type, this method // presumably doesn't want us to warn about optional use. auto firstParamType = curriedType->getParams().front().getPlainType()->getRValueType(); @@ -5202,7 +5202,7 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E, Expr * getFirstArgIfUnintendedInterpolation(ArgumentList *args, UnintendedInterpolationKind kind) { - // Just check the first argument, which is usually the value + // Just check the first argument, which is usually the value // being interpolated. if (args->empty()) return nullptr; @@ -5753,7 +5753,7 @@ diagnoseDictionaryLiteralDuplicateKeyEntries(const Expr *E, } return "'" + out + "'"; } - + bool shouldDiagnoseLiteral(const LiteralExpr *LE) { switch (LE->getKind()) { case ExprKind::IntegerLiteral: @@ -5822,7 +5822,7 @@ diagnoseDictionaryLiteralDuplicateKeyEntries(const Expr *E, auto *LE = dyn_cast(keyExpr); if (!LE) continue; - + if (!shouldDiagnoseLiteral(LE)) continue; @@ -6138,7 +6138,7 @@ TypeChecker::omitNeedlessWords(AbstractFunctionDecl *afd) { paramTypes.push_back(getTypeNameForOmission(param->getInterfaceType()) .withDefaultArgument(param->isDefaultArgument())); } - + // Handle contextual type, result type, and returnsSelf. Type contextType = afd->getDeclContext()->getDeclaredInterfaceType(); Type resultType; @@ -6338,7 +6338,7 @@ void swift::diagnoseCopyableTypeContainingMoveOnlyType( enumEltDecl->getBaseName()); } } - } + } // We have finished processing this enum... so return. return; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index f8ed99afc398a..b7ce0475090ed 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -236,7 +236,8 @@ HasCircularInheritedProtocolsRequest::evaluate(Evaluator &evaluator, return false; bool anyObject = false; - auto inherited = getDirectlyInheritedNominalTypeDecls(decl, anyObject); + bool reflectable = false; + auto inherited = getDirectlyInheritedNominalTypeDecls(decl, anyObject, reflectable); for (auto &found : inherited) { auto *protoDecl = dyn_cast(found.Item); if (!protoDecl) @@ -659,8 +660,9 @@ ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator, // Determine the set of nominal types that this protocol inherits. bool anyObject = false; + bool reflectable = false; auto allInheritedNominals = - getDirectlyInheritedNominalTypeDecls(decl, anyObject); + getDirectlyInheritedNominalTypeDecls(decl, anyObject, reflectable); // Quick check: do we inherit AnyObject? if (anyObject) @@ -3265,3 +3267,31 @@ ImplicitKnownProtocolConformanceRequest::evaluate(Evaluator &evaluator, llvm_unreachable("non-implicitly derived KnownProtocol"); } } + +//----------------------------------------------------------------------------// +// InheritsReflectableProtocolRequest +//----------------------------------------------------------------------------// +bool +InheritsReflectableProtocolRequest::evaluate(Evaluator &evaluator, + ProtocolDecl *decl) const { + + // Determine the set of nominal types that this protocol inherits. + bool anyObject = false; + bool reflectable = false; + auto allInheritedNominals = + getDirectlyInheritedNominalTypeDecls(decl, anyObject, reflectable); + + // Quick check: do we inherit Reflectable? + if (reflectable) + return true; + + // Look through all of the inherited nominals for Reflectable. + for (const auto &found : allInheritedNominals) { + if (auto proto = dyn_cast(found.Item)) { + if (proto->inheritsReflectable()) + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index d4c6dc7f2ec31..c2daf4add602e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1425,7 +1425,7 @@ static Type diagnoseUnknownType(TypeResolution resolution, return I->second; } - + // type-casting operators such as 'is' and 'as'. if (resolution.getOptions().is(TypeResolverContext::ExplicitCastExpr)) { auto lookupResult = TypeChecker::lookupUnqualified( @@ -2086,9 +2086,9 @@ namespace { bool diagnoseMoveOnlyGeneric(TypeRepr *repr, Type unboundTy, Type genericArgTy); - + bool diagnoseDisallowedExistential(TypeRepr *repr); - + bool diagnoseInvalidPlaceHolder(OpaqueReturnTypeRepr *repr); NeverNullType resolveOpenedExistentialArchetype( @@ -2525,10 +2525,10 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, // evaluation of an `OpaqueResultTypeRequest`. auto opaqueRepr = cast(repr); auto *DC = getDeclContext(); - + bool isInExistential = diagnoseDisallowedExistential(opaqueRepr); bool hasInvalidPlaceholder = diagnoseInvalidPlaceHolder(opaqueRepr); - + if (auto opaqueDecl = dyn_cast(DC)) { if (auto ordinal = opaqueDecl->getAnonymousOpaqueParamOrdinal(opaqueRepr)){ return !isInExistential ? getOpaqueArchetypeIdentity(opaqueDecl, *ordinal) @@ -2829,7 +2829,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, if (auto box = dyn_cast(repr)) { return resolveSILBoxType(box, attrs.has(TAK_captures_generics), options); } - + // Resolve global actor. CustomAttr *globalActorAttr = nullptr; Type globalActor; @@ -2890,16 +2890,16 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, // The type we're working with, in case we want to build it differently // based on the attributes we see. Type ty; - + // If this is a reference to an opaque return type, resolve it. if (auto &opaque = attrs.OpaqueReturnTypeOf) { return resolveOpaqueReturnType(repr, opaque->mangledName, opaque->index, options); } - + // In SIL *only*, allow @thin, @thick, or @objc_metatype to apply to // a metatype. - if (attrs.has(TAK_thin) || attrs.has(TAK_thick) || + if (attrs.has(TAK_thin) || attrs.has(TAK_thick) || attrs.has(TAK_objc_metatype)) { if (auto SF = getDeclContext()->getParentSourceFile()) { if (SF->Kind == SourceFileKind::SIL) { @@ -2988,7 +2988,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, attrs.clearAttribute(attr); } }; - + // Some function representation attributes are not supported at source level; // only SIL knows how to handle them. Reject them unless this is a SIL input. if (!(options & TypeResolutionFlags::SILType)) { @@ -3001,7 +3001,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, TAK_yield_many}) { checkUnsupportedAttr(silOnlyAttr); } - } + } // Other function representation attributes are not normally supported at // source level, but we want to support them there in SIL files. @@ -3258,7 +3258,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, .fixItRemove(getTypeAttrRangeWithAt(getASTContext(), loc)); ty = ErrorType::get(getASTContext()); } - + attrs.clearAttribute(TAK_retroactive); } @@ -3411,13 +3411,13 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, } } } - + // In SIL *only*, allow @block_storage to specify a block storage type. if ((options & TypeResolutionFlags::SILType) && attrs.has(TAK_block_storage)) { ty = SILBlockStorageType::get(ty->getCanonicalType()); attrs.clearAttribute(TAK_block_storage); } - + // In SIL *only*, allow @box to specify a box type. if ((options & TypeResolutionFlags::SILType) && attrs.has(TAK_box)) { ty = SILBoxType::get(ty->getCanonicalType()); @@ -3599,7 +3599,7 @@ TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName, TypeArgsBuf.push_back(argTy); } } - + // Use type reconstruction to summon the opaque type decl. Demangler demangle; auto definingDeclNode = demangle.demangleSymbol(mangledName); @@ -3613,7 +3613,7 @@ TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName, auto opaqueNode = builder.getNodeFactory().createNode(Node::Kind::OpaqueReturnTypeOf); opaqueNode->addChild(definingDeclNode, builder.getNodeFactory()); - + auto TypeArgs = ArrayRef(TypeArgsBuf); auto ty = builder.resolveOpaqueType(opaqueNode, TypeArgs, ordinal); if (!ty || ty->hasError()) { @@ -3738,7 +3738,7 @@ NeverNullType TypeResolver::resolveASTFunctionType( } auto fnTy = FunctionType::get(params, outputTy, extInfo); - + if (fnTy->hasError()) return fnTy; @@ -3784,7 +3784,7 @@ NeverNullType TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, // Substitute out parsed context types into interface types. auto genericSig = repr->getGenericSignature().getCanonicalSignature(); - + // Resolve the generic arguments. // Start by building a TypeSubstitutionMap. SubstitutionMap subMap; @@ -3797,7 +3797,7 @@ NeverNullType TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, diagnose(repr->getLoc(), diag::sil_box_arg_mismatch); return ErrorType::get(getASTContext()); } - + for (unsigned i : indices(params)) { auto argTy = resolveType(repr->getGenericArguments()[i], options); genericArgMap.insert({params[i], argTy->getCanonicalType()}); @@ -4920,7 +4920,7 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr, !elements[0].getType()->is()) return ParenType::get(ctx, elements[0].getType()); } - + if (moveOnlyElementIndex.has_value() && !options.contains(TypeResolutionFlags::SILType) && !ctx.LangOpts.hasFeature(Feature::MoveOnlyTuples)) { @@ -5034,7 +5034,7 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, // AnyObject type in the standard library. auto composition = ProtocolCompositionType::get(getASTContext(), Members, Inverses, - /*HasExplicitAnyObject=*/false); + /*HasExplicitAnyObject=*/false, false); if (options.isConstraintImplicitExistential()) { return ExistentialType::get(composition); } @@ -5068,7 +5068,7 @@ TypeResolver::resolveExistentialType(ExistentialTypeRepr *repr, .fixItReplace(repr->getSourceRange(), fix); return constraintType; } - + // Diagnose redundant `any` on an already existential type e.g. any (any P) // with a fix-it to remove first any. if (constraintType->is()) { @@ -5291,7 +5291,7 @@ class ExistentialTypeVisitor unsigned exprCount = 0; llvm::SmallVector reprStack; - + public: ExistentialTypeVisitor(ASTContext &ctx, bool checkStatements) : Ctx(ctx), checkStatements(checkStatements), hitTopStmt(false) { } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 7c45fd9ef7222..502893f509d61 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -681,7 +681,7 @@ SILLayout *ModuleFile::readSILLayout(llvm::BitstreamCursor &Cursor) { decls_block::SILLayoutLayout::readRecord(scratch, rawGenericSig, capturesGenerics, numFields, types); - + SmallVector fields; for (auto fieldInfo : types.slice(0, numFields)) { bool isMutable = fieldInfo & 0x80000000U; @@ -690,7 +690,7 @@ SILLayout *ModuleFile::readSILLayout(llvm::BitstreamCursor &Cursor) { SILField(getType(typeId)->getCanonicalType(), isMutable)); } - + CanGenericSignature canSig; if (auto sig = getGenericSignature(rawGenericSig)) canSig = sig.getCanonicalSignature(); @@ -1937,15 +1937,15 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { importedFromClang, isStatic, llvm::None, values); break; } - + case XREF_OPAQUE_RETURN_TYPE_PATH_PIECE: { IdentifierID DefiningDeclNameID; - + XRefOpaqueReturnTypePathPieceLayout::readRecord(scratch, DefiningDeclNameID); - + auto name = getIdentifier(DefiningDeclNameID); pathTrace.addOpaqueReturnType(name); - + if (auto opaque = baseModule->lookupOpaqueResultType(name.str())) { values.push_back(opaque); } @@ -2036,7 +2036,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { IdentifierID IID; XRefOpaqueReturnTypePathPieceLayout::readRecord(scratch, IID); auto mangledName = getIdentifier(IID); - + SmallString<64> buf; { llvm::raw_svector_ostream os(buf); @@ -2044,7 +2044,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { os << mangledName.str(); os << ">>"; } - + result = getContext().getIdentifier(buf); break; } @@ -2287,7 +2287,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { ctorInit = getActualCtorInitializerKind(kind); break; } - + default: fatal(llvm::make_error(recordID, "Unhandled path piece")); @@ -2480,16 +2480,16 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { break; } - + case XREF_OPAQUE_RETURN_TYPE_PATH_PIECE: { values.clear(); IdentifierID DefiningDeclNameID; - + XRefOpaqueReturnTypePathPieceLayout::readRecord(scratch, DefiningDeclNameID); - + auto name = getIdentifier(DefiningDeclNameID); pathTrace.addOpaqueReturnType(name); - + auto lookupModule = M ? M : baseModule; if (auto opaqueTy = lookupModule->lookupOpaqueResultType(name.str())) { values.push_back(opaqueTy); @@ -4230,7 +4230,7 @@ class DeclDeserializer { underlyingTypeSubsID, rawAccessLevel, exportUnderlyingType); - + auto declContext = MF.getDeclContext(contextID); auto interfaceSigOrErr = MF.getGenericSignatureChecked(interfaceSigID); if (!interfaceSigOrErr) @@ -4510,7 +4510,7 @@ class DeclDeserializer { ctx.evaluator.cacheOutput( OperatorPrecedenceGroupRequest{result}, std::move(cast_or_null(precedenceGroup.get()))); - + declOrOffset = result; return result; } @@ -4715,7 +4715,7 @@ class DeclDeserializer { if (isObjC) { theEnum->setHasFixedRawValues(); } - + if (isImplicit) theEnum->setImplicit(); theEnum->setIsObjC(isObjC); @@ -4887,7 +4887,7 @@ class DeclDeserializer { auto *genericParams = MF.maybeReadGenericParams(parent); if (declOrOffset.isComplete()) return declOrOffset; - + auto staticSpelling = getActualStaticSpellingKind(rawStaticSpelling); if (!staticSpelling.has_value()) return MF.diagnoseFatal(); @@ -4929,13 +4929,13 @@ class DeclDeserializer { subscript->setOverriddenDecl(cast_or_null(overridden.get())); if (subscript->getOverriddenDecl()) AddAttribute(new (ctx) OverrideAttr(SourceLoc())); - + if (opaqueReturnTypeID) { ctx.evaluator.cacheOutput( OpaqueResultTypeRequest{subscript}, cast(MF.getDecl(opaqueReturnTypeID))); } - + return subscript; } @@ -6017,7 +6017,7 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { uint8_t rawAlign; serialization::decls_block::RawLayoutDeclAttrLayout:: readRecord(scratch, isImplicit, typeID, rawSize, rawAlign); - + if (typeID) { auto type = MF.getTypeChecked(typeID); if (!type) { @@ -6036,7 +6036,7 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { break; } } - + Attr = new (ctx) RawLayoutAttr(rawSize, rawAlign, SourceLoc(), SourceRange()); break; @@ -6193,7 +6193,7 @@ DeclDeserializer::getDeclCheckedImpl( declOrOffset = resolved.get(); break; } - + default: // We don't know how to deserialize this kind of decl. MF.fatal(llvm::make_error(recordID)); @@ -6929,10 +6929,11 @@ DESERIALIZE_TYPE(GENERIC_TYPE_PARAM_TYPE)( Expected DESERIALIZE_TYPE(PROTOCOL_COMPOSITION_TYPE)( ModuleFile &MF, SmallVectorImpl &scratch, StringRef blobData) { bool hasExplicitAnyObject; + bool hasExplicitReflectable; ArrayRef rawProtocolIDs; decls_block::ProtocolCompositionTypeLayout::readRecord( - scratch, hasExplicitAnyObject, rawProtocolIDs); + scratch, hasExplicitAnyObject, hasExplicitReflectable, rawProtocolIDs); SmallVector protocols; for (TypeID protoID : rawProtocolIDs) { auto protoTy = MF.getTypeChecked(protoID); @@ -6942,7 +6943,8 @@ Expected DESERIALIZE_TYPE(PROTOCOL_COMPOSITION_TYPE)( } return ProtocolCompositionType::get(MF.getContext(), protocols, - hasExplicitAnyObject); + hasExplicitAnyObject, + hasExplicitReflectable); } Expected DESERIALIZE_TYPE(PARAMETERIZED_PROTOCOL_TYPE)( @@ -7866,7 +7868,7 @@ class LazyConformanceLoaderInfo final size_t align = alignof(LazyConformanceLoaderInfo); // TODO: maybe don't permanently allocate this? - void *memory = mf.getContext().Allocate(size, align); + void *memory = mf.getContext().Allocate(size, align); return new (memory) LazyConformanceLoaderInfo(ids); } @@ -8111,12 +8113,12 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, bool needToFillInOpaqueValueWitnesses = false; while (valueCount--) { ValueDecl *req; - + auto trySetWitness = [&](Witness w) { if (req) conformance->setWitness(req, w); }; - + auto deserializedReq = getDeclChecked(*rawIDIter++); if (deserializedReq) { req = cast_or_null(*deserializedReq); @@ -8127,7 +8129,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, } else { fatal(deserializedReq.takeError()); } - + bool isOpaque = false; ValueDecl *witness; auto deserializedWitness = getDeclChecked(*rawIDIter++); @@ -8196,7 +8198,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, witness, witnessSubstitutions.get(), enterIsolation)); } assert(rawIDIter <= rawIDs.end() && "read too much"); - + // Fill in opaque value witnesses if we need to. if (needToFillInOpaqueValueWitnesses) { for (auto member : proto->getMembers()) { @@ -8205,7 +8207,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, if (!valueMember || !valueMember->isProtocolRequirement() || isa(valueMember)) continue; - + if (!conformance->hasWitness(valueMember)) conformance->setWitness(valueMember, Witness::forOpaque(valueMember)); } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 860b57e31a0a6..6a095c8413a05 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 819; // _resultDependsOnSelf +const uint16_t SWIFTMODULE_VERSION_MINOR = 820; // Reflectable /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1277,6 +1277,7 @@ namespace decls_block { TYPE_LAYOUT(ProtocolCompositionTypeLayout, PROTOCOL_COMPOSITION_TYPE, BCFixed<1>, // has AnyObject constraint + BCFixed<1>, // has Reflectable constraint BCArray // protocols ); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index d0f09ec3c9a3b..fb12724223cde 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1501,6 +1501,8 @@ void Serializer::serializeGenericRequirements( case LayoutConstraintKind::Class: rawKind = LayoutRequirementKind::Class; break; + case LayoutConstraintKind::Reflectable: + break; case LayoutConstraintKind::NativeClass: rawKind = LayoutRequirementKind::NativeClass; break; @@ -5579,6 +5581,7 @@ class Serializer::TypeSerializer : public TypeVisitor { ProtocolCompositionTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, composition->hasExplicitAnyObject(), + composition->hasExplicitReflectable(), protocols); } diff --git a/stdlib/public/core/Policy.swift b/stdlib/public/core/Policy.swift index fbd44c273d3b7..e3d6758f15bdf 100644 --- a/stdlib/public/core/Policy.swift +++ b/stdlib/public/core/Policy.swift @@ -316,6 +316,8 @@ public typealias AnyObject = Builtin.AnyObject public typealias AnyObject = Builtin.AnyObject #endif +public typealias Reflectable = Builtin.Reflectable + /// The protocol to which all class types implicitly conform. /// /// You can use the `AnyClass` protocol as the concrete type for an instance of diff --git a/test/IRGen/opt_in_reflection_metadata.swift b/test/IRGen/opt_in_reflection_metadata.swift new file mode 100644 index 0000000000000..2d1fef94fbe4c --- /dev/null +++ b/test/IRGen/opt_in_reflection_metadata.swift @@ -0,0 +1,110 @@ +// RUN: %target-swift-frontend -enable-upcoming-feature OptInReflection -emit-ir %s | %FileCheck %s --check-prefix=CHECK-REL +// RUN: %target-swift-frontend -g -enable-upcoming-feature OptInReflection -emit-ir %s | %FileCheck %s --check-prefix=CHECK-DEB +// RUN: %target-swift-frontend -enable-full-reflection-metadata -emit-ir %s | %FileCheck %s --check-prefix=CHECK-FULL + +// reflection metadata field descriptor opt_in_reflection_metadata.RefProtocol +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata11RefProtocol_pMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-DEB-DAG: @"$s26opt_in_reflection_metadata11RefProtocol_pMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public protocol RefProtocol: Reflectable { + associatedtype RefInner + var inner: RefInner { get } +} + +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata12RefProtocol2_pMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public protocol RefProtocol2: RefProtocol {} + +// reflection metadata field descriptor opt_in_reflection_metadata.Conformance +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata11ConformanceVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-DEB-DAG: @"$s26opt_in_reflection_metadata11ConformanceVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public struct Conformance: RefProtocol { + public var inner: Int = 0 +} + +// reflection metadata field descriptor opt_in_reflection_metadata.RefStruct +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata9RefStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-DEB-DAG: @"$s26opt_in_reflection_metadata9RefStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public struct RefStruct: Reflectable { + let i: Int + let rc: RefClass + let re: RefEnum +} + +// reflection metadata field descriptor opt_in_reflection_metadata.RefEnum +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata7RefEnumOMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public enum RefEnum: Reflectable { + case C(RefClass) + indirect case S(RefStruct) + indirect case E(RefEnum) + case I(Int) +} + +// reflection metadata field descriptor opt_in_reflection_metadata.RefClass +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata8RefClassCMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public class RefClass: Reflectable { + let i: Int + + public init(i: Int) { + self.i = i + } +} + +// reflection metadata field descriptor opt_in_reflection_metadata.RefClassChild +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata13RefClassChildCMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public class RefClassChild: RefClass { + let y: Int + + public init(y: Int) { + self.y = y + super.init(i: y) + } +} + +// reflection metadata field descriptor opt_in_reflection_metadata.RefGenericClass +// CHECK-REL-DAG: @"$s26opt_in_reflection_metadata15RefGenericClassCMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public class RefGenericClass: RefProtocol2 { + public let inner: T + + public init(inner: T) { + self.inner = inner + } +} + +// reflection metadata field descriptor opt_in_reflection_metadata.NonRefProtocol +// CHECK-REL-NOT: @"$s26opt_in_reflection_metadata14NonRefProtocol_pMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-FULL-DAG: @"$s26opt_in_reflection_metadata14NonRefProtocol_pMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-DEB-DAG: @"$s26opt_in_reflection_metadata14NonRefProtocol_pMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public protocol NonRefProtocol { + associatedtype NonRefInner + var inner: NonRefInner { get } +} + +public protocol RefProtocol3: Reflectable {} + +// reflection metadata field descriptor opt_in_reflection_metadata.NonRefStruct +// CHECK-REL-NOT: @"$s26opt_in_reflection_metadata12NonRefStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-FULL-DAG: @"$s26opt_in_reflection_metadata12NonRefStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-DEB-DAG: @"$s26opt_in_reflection_metadata12NonRefStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public struct NonRefStruct { + let i: Int + let y: RefProtocol3 +} + +// CHECK-FULL-DAG: @"$s26opt_in_reflection_metadata11NonRefClassCMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public class NonRefClass { + public let a = 123 +} + +// reflection metadata field descriptor opt_in_reflection_metadata.NonRefGenericStruct +// CHECK-REL-NOT: @"$s26opt_in_reflection_metadata19NonRefGenericStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +// CHECK-DEB-DAG: @"$s26opt_in_reflection_metadata19NonRefGenericStructVMF" = internal constant {{.*}} section "{{[^"]*swift5_fieldmd|.sw5flmd\$B}} +public struct NonRefGenericStruct { + let inner: T + let i: RefProtocol3 +} + +// CHECK-REL-DAG: @__swift_reflection_version = linkonce_odr hidden constant i16 {{[0-9]+}} + +// associated type descriptor for opt_in_reflection_metadata.RefProtocol.RefInner +// CHECK-REL-DAG: @"$s8RefInner26opt_in_reflection_metadata0A8ProtocolPTl" = +// associated type descriptor for opt_in_reflection_metadata.NonRefProtocol.NonRefInner +// CHECK-REL-DAG: @"$s11NonRefInner26opt_in_reflection_metadata0aB8ProtocolPTl" = \ No newline at end of file diff --git a/test/Reflection/reflectable_implicit_conversion.swift b/test/Reflection/reflectable_implicit_conversion.swift new file mode 100644 index 0000000000000..7f82ff6622d93 --- /dev/null +++ b/test/Reflection/reflectable_implicit_conversion.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-frontend -typecheck %s -verify + +func cast(_ x: U) -> T { + return x as! T +} + +func castOptional(_ x: U) -> T? { + return x as? T +} + +public func wrap( + _ testFunction: @escaping () -> Void +) { testFunction() } + +public func consume(_ t: Reflectable) {} + +let a: Reflectable? = cast(1) // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} +let a1: Reflectable = cast(1) // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} + +let b: Reflectable? = castOptional(1) // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} +let b1: Reflectable = castOptional(1)! // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} + +let c = cast(1) as Reflectable // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} +let c1 = cast(1) as Reflectable? // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} + +let d = castOptional(1) as Reflectable? // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} +let d1 = castOptional(1)! as Reflectable // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} + +wrap() { + let e: Reflectable? = castOptional(1) // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} +} + +consume(cast(1)) // expected-error {{expression can't be implicitly converted to Reflectable; use 'as? Reflectable' or 'as! Reflectable' instead}} \ No newline at end of file diff --git a/test/Reflection/reflectable_metadata_conformance_in_extension.swift b/test/Reflection/reflectable_metadata_conformance_in_extension.swift new file mode 100644 index 0000000000000..d9fc920fbf2ab --- /dev/null +++ b/test/Reflection/reflectable_metadata_conformance_in_extension.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-frontend -enable-upcoming-feature OptInReflection -typecheck %s -verify + +// MARK: - Errors +struct Foo {} + +extension Foo: Reflectable {} // expected-error {{extensions cannot declare protocol conformance to Reflectable}} \ No newline at end of file