diff --git a/CMakeLists.txt b/CMakeLists.txt index 978a162f72596..c7b9997160d99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,6 @@ set_property(GLOBAL PROPERTY JOB_POOL_LINK local_jobs) # First include general CMake utilities. include(SwiftUtils) -include(CheckSymbolExists) # # User-configurable options that control the inclusion and default build @@ -806,8 +805,6 @@ if(LIBXML2_FOUND) set(SWIFT_HAVE_LIBXML 1) endif() -check_symbol_exists(el_wgets "histedit.h" HAVE_UNICODE_LIBEDIT) - if (LLVM_ENABLE_DOXYGEN) message(STATUS "Doxygen: enabled") endif() diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 30014c3269a56..bfb8faaa213f7 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -341,8 +341,6 @@ function(_add_variant_link_flags) list(APPEND library_search_directories "${SWIFT_ANDROID_PREBUILT_PATH}/lib/gcc/arm-linux-androideabi/${SWIFT_ANDROID_NDK_GCC_VERSION}.x") else() - list(APPEND result "-lobjc") - # If lto is enabled, we need to add the object path flag so that the LTO code # generator leaves the intermediate object file in a place where it will not # be touched. The reason why this must be done is that on OS X, debug info is @@ -1588,7 +1586,7 @@ function(add_swift_library name) else() if("${sdk}" STREQUAL "WINDOWS") set(UNIVERSAL_LIBRARY_NAME - "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/lib${name}.lib") + "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${name}.lib") else() set(UNIVERSAL_LIBRARY_NAME "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") diff --git a/docs/ABI.rst b/docs/ABI.rst index 082f507ec4663..efb07219ad354 100644 --- a/docs/ABI.rst +++ b/docs/ABI.rst @@ -792,6 +792,9 @@ Globals global ::= type 'WV' // value witness table global ::= entity 'Wv' DIRECTNESS // field offset + global ::= type 'Wy' // Outlined Copy Function Type + global ::= type 'We' // Outlined Consume Function Type + DIRECTNESS ::= 'd' // direct DIRECTNESS ::= 'i' // indirect diff --git a/docs/ARCOptimization.rst b/docs/ARCOptimization.rst index ed4ecf69a5ceb..d692b378db984 100644 --- a/docs/ARCOptimization.rst +++ b/docs/ARCOptimization.rst @@ -886,7 +886,7 @@ Consider the following pseudo-Swift example:: var GLOBAL_D : D = D1() - class C { deinit { GLOBAL_D = D2 } } + class C { deinit { GLOBAL_D = D2() } } func main() { let c = C() diff --git a/include/swift/AST/ASTNode.h b/include/swift/AST/ASTNode.h index 69487eaa7b75f..3bef23cbb6bac 100644 --- a/include/swift/AST/ASTNode.h +++ b/include/swift/AST/ASTNode.h @@ -18,6 +18,7 @@ #define SWIFT_AST_AST_NODE_H #include "llvm/ADT/PointerUnion.h" +#include "swift/AST/SourceEntityWalker.h" #include "swift/AST/TypeAlignments.h" namespace swift { @@ -44,6 +45,9 @@ namespace swift { void walk(ASTWalker &Walker); void walk(ASTWalker &&walker) { walk(walker); } + void walk(SourceEntityWalker &Walker); + void walk(SourceEntityWalker &&walker) { walk(walker); } + /// \brief get the underlying entity as a decl context if it is one, /// otherwise, return nullptr; DeclContext *getAsDeclContext() const; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7157c363facd3..6930219a2b1ce 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5070,13 +5070,6 @@ class FuncDecl final : public AbstractFunctionDecl, FuncDeclBits.HasDynamicSelf = hasDynamicSelf; } - /// Determine whether this method has an archetype \c Self return - /// type. This is when a method defined in a protocol extension - /// returns Self. In this case, the type is not quite as constrained - /// as a dynamic Self, because it is bound to the conforming type, - /// not the dynamic type of the value. - bool hasArchetypeSelf() const; - void getLocalCaptures(SmallVectorImpl &Result) const { return getCaptureInfo().getLocalCaptures(Result); } diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index b8b00451986e8..0543046824fb6 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -390,11 +390,6 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// any of its parents have generic parameters. bool isGenericContext() const; - /// Determine whether this declaration context is a generic context that has - /// been fully type checked, meaning it has a valid GenericSignature and - /// GenericEnvironment. - bool isValidGenericContext() const; - /// Determine whether the innermost context is generic. bool isInnermostContextGeneric() const; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 403f1aaaa07e6..e5ed60b6989fc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2432,6 +2432,9 @@ NOTE(fix_unqualified_access_top_level_multi,none, "use '%0' to reference the %1 in module %2", (StringRef, DescriptiveDeclKind, Identifier)) +ERROR(unsupported_special_decl_ref, none, + "referencing %0 as a function value is not implemented", (Identifier)) + WARNING(use_of_qq_on_non_optional_value,none, "left side of nil coalescing operator '?""?' has non-optional type %0, " "so the right side is never used", (Type)) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 4b762589ac185..170aa5cc70428 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2522,6 +2522,69 @@ class ForceValueExpr : public Expr { } }; +/// \brief An expression that grants temporary escapability to a nonescaping +/// closure value. +/// +/// This expression is formed by the type checker when a call to the +/// `withoutActuallyEscaping` declaration is made. +class MakeTemporarilyEscapableExpr : public Expr { + Expr *NonescapingClosureValue; + OpaqueValueExpr *EscapingClosureValue; + Expr *SubExpr; + SourceLoc NameLoc, LParenLoc, RParenLoc; + +public: + MakeTemporarilyEscapableExpr(SourceLoc NameLoc, + SourceLoc LParenLoc, + Expr *NonescapingClosureValue, + Expr *SubExpr, + SourceLoc RParenLoc, + OpaqueValueExpr *OpaqueValueForEscapingClosure, + bool implicit = false) + : Expr(ExprKind::MakeTemporarilyEscapable, implicit, Type()), + NonescapingClosureValue(NonescapingClosureValue), + EscapingClosureValue(OpaqueValueForEscapingClosure), + SubExpr(SubExpr), + NameLoc(NameLoc), LParenLoc(LParenLoc), RParenLoc(RParenLoc) + {} + + SourceLoc getStartLoc() const { + return NameLoc; + } + SourceLoc getEndLoc() const { + return RParenLoc; + } + + SourceLoc getLoc() const { + return NameLoc; + } + + /// Retrieve the opaque value representing the escapable copy of the + /// closure. + OpaqueValueExpr *getOpaqueValue() const { return EscapingClosureValue; } + + /// Retrieve the nonescaping closure expression. + Expr *getNonescapingClosureValue() const { + return NonescapingClosureValue; + } + void setNonescapingClosureValue(Expr *e) { + NonescapingClosureValue = e; + } + + /// Retrieve the subexpression that has access to the escapable copy of the + /// closure. + Expr *getSubExpr() const { + return SubExpr; + } + void setSubExpr(Expr *e) { + SubExpr = e; + } + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::MakeTemporarilyEscapable; + } +}; + /// \brief An expression that opens up a value of protocol or protocol /// composition type and gives a name to its dynamic type. /// diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index fd647108a04f8..3dcd6bc441933 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -107,6 +107,7 @@ EXPR(BindOptional, Expr) EXPR(OptionalEvaluation, Expr) EXPR(ForceValue, Expr) EXPR(OpenExistential, Expr) +EXPR(MakeTemporarilyEscapable, Expr) ABSTRACT_EXPR(Apply, Expr) EXPR(Call, ApplyExpr) EXPR(PrefixUnary, ApplyExpr) diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h index 7c7533b2f78c4..b6af7ebaa67fc 100644 --- a/include/swift/AST/Pattern.h +++ b/include/swift/AST/Pattern.h @@ -535,7 +535,10 @@ class EnumElementPattern : public Pattern { : NameLoc; } SourceLoc getEndLoc() const { - return SubPattern ? SubPattern->getSourceRange().End : NameLoc; + if (SubPattern && SubPattern->getSourceRange().isValid()) { + return SubPattern->getSourceRange().End; + } + return NameLoc; } SourceRange getSourceRange() const { return {getStartLoc(), getEndLoc()}; } diff --git a/include/swift/AST/SourceEntityWalker.h b/include/swift/AST/SourceEntityWalker.h index 773ee2b44a766..684158b691bb5 100644 --- a/include/swift/AST/SourceEntityWalker.h +++ b/include/swift/AST/SourceEntityWalker.h @@ -53,6 +53,12 @@ class SourceEntityWalker { /// Walks the provided DeclContext. /// \returns true if traversal was aborted, false otherwise. bool walk(DeclContext *DC); + /// Walks the provided Stmt. + /// \returns true if traversal was aborted, false otherwise. + bool walk(Stmt *S); + /// Walks the provided Expr. + /// \returns true if traversal was aborted, false otherwise. + bool walk(Expr *E); /// This method is called when first visiting a decl, before walking into its /// children. If it returns false, the subtree is skipped. diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h index 8870d2833934e..90f381d6c99bb 100644 --- a/include/swift/AST/Type.h +++ b/include/swift/AST/Type.h @@ -280,9 +280,6 @@ class Type { /// Return the name of the type as a string, for use in diagnostics only. std::string getString(const PrintOptions &PO = PrintOptions()) const; - /// Get the canonical type, or return null if the type is null. - CanType getCanonicalTypeOrNull() const; // in Types.h - /// Computes the join between two types. /// /// The join of two types is the most specific type that is a supertype of diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index 3ae0d0fbd4367..cfec2794b1fbc 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -107,7 +107,7 @@ ABSTRACT_TYPE(Nominal, Type) TYPE(Enum, NominalType) TYPE(Struct, NominalType) TYPE(Class, NominalType) - ALWAYS_CANONICAL_TYPE(Protocol, NominalType) + TYPE(Protocol, NominalType) TYPE_RANGE(Nominal, Enum, Protocol) ABSTRACT_TYPE(AnyMetatype, Type) TYPE(Metatype, AnyMetatypeType) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 2b51d81caf8ec..e02e4197ad2d0 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -309,6 +309,10 @@ class GenericIdentTypeRepr : public ComponentIdentTypeRepr { : ComponentIdentTypeRepr(TypeReprKind::GenericIdent, Loc, Id), GenericArgs(GenericArgs), AngleBrackets(AngleBrackets) { assert(!GenericArgs.empty()); +#ifndef NDEBUG + for (auto arg : GenericArgs) + assert(arg != nullptr); +#endif } ArrayRef getGenericArgs() const { return GenericArgs; } diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 8e7955ad57654..2ccda2c3f31d4 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -64,6 +64,7 @@ namespace swift { class TypeVariableType; class ValueDecl; class ModuleDecl; + class ModuleType; class ProtocolConformance; struct SILArgumentConvention; enum OptionalTypeKind : unsigned; @@ -489,7 +490,11 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// Erase the given opened existential type by replacing it with its /// existential type throughout the given type. - Type eraseOpenedExistential(ModuleDecl *module, ArchetypeType *opened); + Type eraseOpenedExistential(ArchetypeType *opened); + + /// Erase DynamicSelfType from the given type by replacing it with its + /// underlying type. + Type eraseDynamicSelfType(); /// \brief Compute and return the set of type variables that occur within this /// type. @@ -643,6 +648,23 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// with a class type. bool mayHaveSuperclass(); + /// \brief Determine whether this type can be used as a base type for AST + /// name lookup, which is the case for nominal types, protocol compositions + /// and archetypes. + /// + /// Generally, the static vs instanec and mutating vs nonmutating distinction + /// is handled elsewhere, so metatypes, lvalue types and inout types are not + /// allowed here. + /// + /// Similarly, tuples formally have members, but this does not go through + /// name lookup. + bool mayHaveMembers() { + return (is() || + is() || + isExistentialType() || + getAnyNominal()); + } + /// \brief Retrieve the superclass of this type. /// /// \param resolver The resolver for lazy type checking, or null if the @@ -778,6 +800,13 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// the result would be the (parenthesized) type ((int, int)). Type getUnlabeledType(ASTContext &Context); + /// Retrieve the type without any labels around it. For example, given + /// \code + /// (p : int) + /// \endcode + /// the result would be the (unparenthesized) type 'int'. + Type getWithoutImmediateLabel(); + /// Retrieve the type without any parentheses around it. Type getWithoutParens(); @@ -792,8 +821,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// replacing the type. With uncurry level == 0, this simply /// replaces the current type with the new result type. Type replaceCovariantResultType(Type newResultType, - unsigned uncurryLevel, - bool preserveOptionality = true); + unsigned uncurryLevel); /// Returns a new function type exactly like this one but with the self /// parameter replaced. Only makes sense for function members of types. @@ -3548,7 +3576,7 @@ class ProtocolType : public NominalType, public llvm::FoldingSetNode { public: /// \brief Retrieve the type when we're referencing the given protocol. /// declaration. - static ProtocolType *get(ProtocolDecl *D, const ASTContext &C); + static ProtocolType *get(ProtocolDecl *D, Type Parent, const ASTContext &C); ProtocolDecl *getDecl() const { return reinterpret_cast(NominalType::getDecl()); @@ -3593,7 +3621,8 @@ class ProtocolType : public NominalType, public llvm::FoldingSetNode { private: friend class NominalTypeDecl; - ProtocolType(ProtocolDecl *TheDecl, const ASTContext &Ctx); + ProtocolType(ProtocolDecl *TheDecl, Type Parent, const ASTContext &Ctx, + RecursiveTypeProperties properties); }; BEGIN_CAN_TYPE_WRAPPER(ProtocolType, NominalType) void getAnyExistentialTypeProtocols(SmallVectorImpl &protos) { @@ -4431,12 +4460,7 @@ inline Type TypeBase::getRValueObjectType() { type = lv->getObjectType(); // Look through argument list tuples. - if (auto tupleTy = type->getAs()) { - if (tupleTy->getNumElements() == 1 && !tupleTy->getElement(0).isVararg()) - type = tupleTy->getElementType(0); - } - - return type; + return type->getWithoutImmediateLabel(); } /// getLValueOrInOutObjectType - For an @lvalue or inout type, retrieves the @@ -4526,10 +4550,6 @@ ParameterTypeFlags::fromParameterType(Type paramTy, bool isVariadic) { return {isVariadic, autoclosure, escaping}; } -inline CanType Type::getCanonicalTypeOrNull() const { - return isNull() ? CanType() : getPointer()->getCanonicalType(); -} - #define TYPE(id, parent) #define SUGARED_TYPE(id, parent) \ template <> \ diff --git a/include/swift/Basic/DemangleNodes.def b/include/swift/Basic/DemangleNodes.def index 3c32c40357b81..a9bfb8bf80e75 100644 --- a/include/swift/Basic/DemangleNodes.def +++ b/include/swift/Basic/DemangleNodes.def @@ -177,5 +177,7 @@ NODE(ThrowsAnnotation) NODE(EmptyList) NODE(FirstElementMarker) NODE(VariadicMarker) +NODE(OutlinedCopy) +NODE(OutlinedConsume) #undef CONTEXT_NODE #undef NODE diff --git a/include/swift/Basic/Range.h b/include/swift/Basic/Range.h index 798c409c6f3e1..39ceed47a5b24 100644 --- a/include/swift/Basic/Range.h +++ b/include/swift/Basic/Range.h @@ -9,25 +9,27 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// -// -// This file provides classes and functions for conveniently working -// with ranges, -// -// reversed returns an iterator_range out of the reverse iterators of a type. -// -// map creates an iterator_range which applies a function to all the elements -// in another iterator_range. -// -// IntRange is a template class for iterating over a range of -// integers. -// -// indices returns the range of indices from [0..size()) on a -// subscriptable type. -// -// Note that this is kept in Swift because it's really only useful in -// C++11, and there aren't any major open-source subprojects of LLVM -// that can use C++11 yet. -// +/// +/// \file +/// +/// This file provides classes and functions for conveniently working +/// with ranges, +/// +/// reversed returns an iterator_range out of the reverse iterators of a type. +/// +/// map creates an iterator_range which applies a function to all the elements +/// in another iterator_range. +/// +/// IntRange is a template class for iterating over a range of +/// integers. +/// +/// indices returns the range of indices from [0..size()) on a +/// subscriptable type. +/// +/// Note that this is kept in Swift because it's really only useful in +/// C++11, and there aren't any major open-source subprojects of LLVM +/// that can use C++11 yet. +/// //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_RANGE_H @@ -178,6 +180,13 @@ static inline IntRange range(unsigned end) { return range(0, end); } +/// Returns a reverse Int range (start, end]. +static inline auto reverse_range(unsigned start, unsigned end) -> + decltype(reversed(range(start+1, end+1))) { + assert(start <= end && "Invalid integral range"); + return reversed(range(start+1, end+1)); +} + /// A random access range that provides iterators that can be used to iterate /// over the (element, index) pairs of a collection. template class EnumeratorRange { diff --git a/include/swift/Config.h.in b/include/swift/Config.h.in index 652fbf4670869..263e3086c5724 100644 --- a/include/swift/Config.h.in +++ b/include/swift/Config.h.in @@ -6,6 +6,4 @@ #cmakedefine SWIFT_HAVE_WORKING_STD_REGEX 1 -#cmakedefine HAVE_UNICODE_LIBEDIT 1 - #endif // SWIFT_CONFIG_H diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 127d091de229b..e49f78313dfc4 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -14,6 +14,7 @@ #define SWIFT_IDE_UTILS_H #include "swift/Basic/LLVM.h" +#include "swift/AST/ASTNode.h" #include "swift/AST/Module.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/SourceEntityWalker.h" @@ -206,6 +207,14 @@ enum class RangeKind : int8_t{ MultiStatement, }; +struct DeclaredDecl { + ValueDecl *VD; + bool ReferedAfterRange; + DeclaredDecl(ValueDecl* VD) : VD(VD), ReferedAfterRange(false) {} + DeclaredDecl(): DeclaredDecl(nullptr) {} + bool operator==(const DeclaredDecl& other); +}; + struct ReferencedDecl { ValueDecl *VD; Type Ty; @@ -218,18 +227,23 @@ struct ResolvedRangeInfo { RangeKind Kind; Type Ty; StringRef Content; - ArrayRef DeclaredDecls; + + // The topmost ast nodes contained in the given range. + ArrayRef ContainedNodes; + ArrayRef DeclaredDecls; ArrayRef ReferencedDecls; DeclContext* RangeContext; ResolvedRangeInfo(RangeKind Kind, Type Ty, StringRef Content, DeclContext* RangeContext, - ArrayRef DeclaredDecls, + ArrayRef ContainedNodes, + ArrayRef DeclaredDecls, ArrayRef ReferencedDecls): Kind(Kind), - Ty(Ty), Content(Content), DeclaredDecls(DeclaredDecls), + Ty(Ty), Content(Content), ContainedNodes(ContainedNodes), + DeclaredDecls(DeclaredDecls), ReferencedDecls(ReferencedDecls), RangeContext(RangeContext) {} ResolvedRangeInfo() : - ResolvedRangeInfo(RangeKind::Invalid, Type(), StringRef(), nullptr, {}, {}) {} + ResolvedRangeInfo(RangeKind::Invalid, Type(), StringRef(), nullptr, {}, {}, {}) {} void print(llvm::raw_ostream &OS); }; diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 1591544418204..97640815f15c1 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -229,8 +229,8 @@ class SILCloner : protected SILVisitor { } // Register a re-mapping for opened existentials. - void registerOpenedExistentialRemapping(ArchetypeType *From, CanType To) { - OpenedExistentialSubs.addSubstitution(CanType(From), To); + void registerOpenedExistentialRemapping(ArchetypeType *From, ArchetypeType *To) { + OpenedExistentialSubs.addSubstitution(CanType(From), CanType(To)); } protected: diff --git a/include/swift/SIL/SILOpenedArchetypesTracker.h b/include/swift/SIL/SILOpenedArchetypesTracker.h index 033d01069f917..d53929266e59e 100644 --- a/include/swift/SIL/SILOpenedArchetypesTracker.h +++ b/include/swift/SIL/SILOpenedArchetypesTracker.h @@ -31,7 +31,7 @@ namespace swift { /// The intended clients of this class are SILGen, SIL deserializers, etc. class SILOpenedArchetypesTracker : public DeleteNotificationHandler { public: - typedef llvm::DenseMap OpenedArchetypeDefsMap; + typedef llvm::DenseMap OpenedArchetypeDefsMap; SILOpenedArchetypesTracker(SILOpenedArchetypesTracker &Tracker) : SILOpenedArchetypesTracker(Tracker.F, Tracker) {} @@ -60,9 +60,9 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler { const SILFunction &getFunction() const { return F; } // Register a definition of a given opened archetype. - void addOpenedArchetypeDef(Type archetype, SILValue Def); + void addOpenedArchetypeDef(ArchetypeType *archetype, SILValue Def); - void removeOpenedArchetypeDef(Type archetype, SILValue Def) { + void removeOpenedArchetypeDef(ArchetypeType *archetype, SILValue Def) { auto FoundDef = getOpenedArchetypeDef(archetype); assert(FoundDef && "Opened archetype definition is not registered in SILFunction"); @@ -72,7 +72,7 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler { // Return the SILValue defining a given archetype. // If the defining value is not known, return an empty SILValue. - SILValue getOpenedArchetypeDef(Type archetype) const { + SILValue getOpenedArchetypeDef(ArchetypeType *archetype) const { return OpenedArchetypeDefs.lookup(archetype); } @@ -163,12 +163,12 @@ class SILOpenedArchetypesState { /// Lookup the instruction defining an opened archetype by first /// performing a quick lookup in the opened archetypes operands /// and then in the opened archetypes tracker. - SILValue getOpenedArchetypeDef(Type Ty) const; + SILValue getOpenedArchetypeDef(ArchetypeType *archetypeTy) const; }; /// Find an opened archetype defined by an instruction. /// \returns The found archetype or empty type otherwise. -CanType getOpenedArchetypeOf(const SILInstruction *I); +ArchetypeType *getOpenedArchetypeOf(const SILInstruction *I); /// Find an opened archetype represented by this type. /// It is assumed by this method that the type contains @@ -178,7 +178,7 @@ CanType getOpenedArchetypeOf(const SILInstruction *I); /// recursively check any children of this type, because /// this is the task of the type visitor invoking it. /// \returns The found archetype or empty type otherwise. -CanType getOpenedArchetypeOf(CanType Ty); +ArchetypeType *getOpenedArchetypeOf(Type Ty); } // end swift namespace #endif diff --git a/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h b/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h index d25b6431c950c..e48770d5a34a3 100644 --- a/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h @@ -36,7 +36,7 @@ class DestructorAnalysis : public SILAnalysis { protected: bool cacheResult(CanType Type, bool Result); - bool isSafeType(Type Ty); + bool isSafeType(CanType Ty); bool implementsDestructorSafeContainerProtocol(NominalTypeDecl *NomDecl); bool areTypeParametersSafe(CanType Ty); ASTContext &getASTContext(); diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h index b64abc916de4c..e645e28c02a95 100644 --- a/include/swift/Serialization/ModuleFile.h +++ b/include/swift/Serialization/ModuleFile.h @@ -81,6 +81,41 @@ class ModuleFile : public LazyMemberLoader { /// A callback to be invoked every time a type was deserialized. std::function DeserializedTypeCallback; + /// The number of entities that are currently being deserialized. + unsigned NumCurrentDeserializingEntities = 0; + + /// Declaration contexts with delayed generic environments, which will be + /// completed as a pending action. + /// + /// FIXME: This is needed because completing a generic environment can + /// require the type checker, which might be gone if we delay generic + /// environments too far. It is a hack. + std::vector DelayedGenericEnvironments; + + /// RAII class to be used when deserializing an entity. + class DeserializingEntityRAII { + ModuleFile &MF; + + public: + DeserializingEntityRAII(ModuleFile &MF) : MF(MF) { + ++MF.NumCurrentDeserializingEntities; + } + ~DeserializingEntityRAII() { + assert(MF.NumCurrentDeserializingEntities > 0 && + "Imbalanced currently-deserializing count?"); + if (MF.NumCurrentDeserializingEntities == 1) { + MF.finishPendingActions(); + } + + --MF.NumCurrentDeserializingEntities; + } + }; + friend class DeserializingEntityRAII; + + /// Finish any pending actions that were waiting for the topmost entity to + /// be deserialized. + void finishPendingActions(); + public: /// Represents another module that has been imported as a dependency. class Dependency { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 651c5fba3c99b..6057b0efd850e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -766,48 +766,36 @@ static FuncDecl *findLibraryIntrinsic(const ASTContext &ctx, return nullptr; } -static CanType stripImmediateLabels(CanType type) { - while (auto tuple = dyn_cast(type)) { - if (tuple->getNumElements() == 1) { - type = tuple.getElementType(0); - } else { - break; - } - } - return type; -} - /// Check whether the given function is non-generic. static bool isNonGenericIntrinsic(FuncDecl *fn, bool allowTypeMembers, - CanType &input, - CanType &output) { - CanType type = fn->getInterfaceType()->getCanonicalType(); + Type &input, + Type &output) { + auto type = fn->getInterfaceType(); if (allowTypeMembers && fn->getDeclContext()->isTypeContext()) { - auto fnType = dyn_cast(type); + auto fnType = type->getAs(); if (!fnType) return false; - type = fnType.getResult(); + type = fnType->getResult(); } - auto fnType = dyn_cast(type); - if (!fnType) - return false; + auto fnType = type->getAs(); + if (!fnType) return false; - input = stripImmediateLabels(fnType.getInput()); - output = stripImmediateLabels(fnType.getResult()); + input = fnType->getInput()->getWithoutImmediateLabel(); + output = fnType->getResult(); return true; } /// Check whether the given type is Builtin.Int1. -static bool isBuiltinInt1Type(CanType type) { - if (auto intType = dyn_cast(type)) +static bool isBuiltinInt1Type(Type type) { + if (auto intType = type->getAs()) return intType->isFixedWidth() && intType->getFixedWidth() == 1; return false; } /// Check whether the given type is Builtin.Word. -static bool isBuiltinWordType(CanType type) { - if (auto intType = dyn_cast(type)) +static bool isBuiltinWordType(Type type) { + if (auto intType = type->getAs()) return intType->getWidth().isPointerWidth(); return false; } @@ -817,7 +805,7 @@ FuncDecl *ASTContext::getGetBoolDecl(LazyResolver *resolver) const { return Impl.GetBoolDecl; // Look for the function. - CanType input, output; + Type input, output; auto decl = findLibraryIntrinsic(*this, "_getBool", resolver); if (!decl || !isNonGenericIntrinsic(decl, /*allowTypeMembers=*/false, input, output)) @@ -828,10 +816,7 @@ FuncDecl *ASTContext::getGetBoolDecl(LazyResolver *resolver) const { return nullptr; // Output must be a global type named Bool. - auto nominalType = dyn_cast(output); - if (!nominalType || - nominalType.getParent() || - nominalType->getDecl()->getName().str() != "Bool") + if (!output->isEqual(getBoolDecl()->getDeclaredType())) return nullptr; Impl.GetBoolDecl = decl; @@ -841,9 +826,9 @@ FuncDecl *ASTContext::getGetBoolDecl(LazyResolver *resolver) const { FuncDecl *ASTContext::getEqualIntDecl() const { if (Impl.EqualIntDecl) return Impl.EqualIntDecl; - - CanType intType = getIntDecl()->getDeclaredType().getCanonicalTypeOrNull(); - CanType boolType = getBoolDecl()->getDeclaredType().getCanonicalTypeOrNull(); + + auto intType = getIntDecl()->getDeclaredType(); + auto boolType = getBoolDecl()->getDeclaredType(); SmallVector equalFuncs; lookupInSwiftModule("==", equalFuncs); @@ -862,20 +847,22 @@ FuncDecl *ASTContext::getEqualIntDecl() const { if (auto resolver = getLazyResolver()) resolver->resolveDeclSignature(funcDecl); - CanType input, resultType; + Type input, resultType; if (!isNonGenericIntrinsic(funcDecl, /*allowTypeMembers=*/true, input, resultType)) continue; // Check for the signature: (Int, Int) -> Bool - auto tType = dyn_cast(input.getPointer()); - assert(tType); - if (tType->getNumElements() != 2) + auto tupleType = dyn_cast(input.getPointer()); + assert(tupleType); + if (tupleType->getNumElements() != 2) continue; - CanType argType1 = tType->getElementType(0).getCanonicalTypeOrNull(); - CanType argType2 = tType->getElementType(1).getCanonicalTypeOrNull(); - if (argType1 == intType && argType2 == intType && resultType == boolType) { + auto argType1 = tupleType->getElementType(0); + auto argType2 = tupleType->getElementType(1); + if (argType1->isEqual(intType) && + argType2->isEqual(intType) && + resultType->isEqual(boolType)) { Impl.EqualIntDecl = funcDecl; return funcDecl; } @@ -889,7 +876,7 @@ ASTContext::getUnimplementedInitializerDecl(LazyResolver *resolver) const { return Impl.UnimplementedInitializerDecl; // Look for the function. - CanType input, output; + Type input, output; auto decl = findLibraryIntrinsic(*this, "_unimplementedInitializer", resolver); if (!decl || @@ -922,7 +909,7 @@ FuncDecl *ASTContext::getIsOSVersionAtLeastDecl(LazyResolver *resolver) const { return Impl.IsOSVersionAtLeastDecl; // Look for the function. - CanType input, output; + Type input, output; auto decl = findLibraryIntrinsic(*this, "_stdlib_isOSVersionAtLeast", resolver); if (!decl || @@ -930,14 +917,11 @@ FuncDecl *ASTContext::getIsOSVersionAtLeastDecl(LazyResolver *resolver) const { return nullptr; // Input must be (Builtin.Word, Builtin.Word, Builtin.Word) - auto inputTuple = dyn_cast(input); + auto inputTuple = input->getAs(); if (!inputTuple || inputTuple->getNumElements() != 3 || - !isBuiltinWordType( - inputTuple->getElementType(0).getCanonicalTypeOrNull()) || - !isBuiltinWordType( - inputTuple->getElementType(1).getCanonicalTypeOrNull()) || - !isBuiltinWordType( - inputTuple->getElementType(2).getCanonicalTypeOrNull())) { + !isBuiltinWordType(inputTuple->getElementType(0)) || + !isBuiltinWordType(inputTuple->getElementType(1)) || + !isBuiltinWordType(inputTuple->getElementType(2))) { return nullptr; } @@ -1107,7 +1091,7 @@ Optional> ASTContext::createTrivialSubstitutions(BoundGenericType *BGT, DeclContext *gpContext) const { assert(gpContext && "No generic parameter context"); - assert(gpContext->isValidGenericContext() && + assert(gpContext->getGenericEnvironmentOfContext() != nullptr && "Not type-checked yet"); assert(BGT->getGenericArgs().size() == 1); Substitution Subst(BGT->getGenericArgs()[0], {}); @@ -1395,6 +1379,8 @@ ASTContext::getConformance(Type conformingType, SourceLoc loc, DeclContext *dc, ProtocolConformanceState state) { + assert(dc->isTypeContext()); + llvm::FoldingSetNodeID id; NormalProtocolConformance::Profile(id, protocol, dc); @@ -2645,7 +2631,7 @@ NominalType *NominalType::get(NominalTypeDecl *D, Type Parent, const ASTContext case DeclKind::Class: return ClassType::get(cast(D), Parent, C); case DeclKind::Protocol: { - return ProtocolType::get(cast(D), C); + return ProtocolType::get(cast(D), Parent, C); } default: @@ -3288,12 +3274,8 @@ ImplicitlyUnwrappedOptionalType *ImplicitlyUnwrappedOptionalType::get(Type base) return entry = new (C, arena) ImplicitlyUnwrappedOptionalType(C, base, properties); } -ProtocolType *ProtocolType::get(ProtocolDecl *D, const ASTContext &C) { - // Protocol types can never be nested inside other types, but we should - // model this anyway to fix some compiler crashes when computing - // substitutions on invalid code. - Type Parent; - +ProtocolType *ProtocolType::get(ProtocolDecl *D, Type Parent, + const ASTContext &C) { llvm::FoldingSetNodeID id; ProtocolType::Profile(id, D, Parent); @@ -3306,15 +3288,16 @@ ProtocolType *ProtocolType::get(ProtocolDecl *D, const ASTContext &C) { = C.Impl.getArena(arena).ProtocolTypes.FindNodeOrInsertPos(id, insertPos)) return protoTy; - auto protoTy = new (C, arena) ProtocolType(D, C); + auto protoTy = new (C, arena) ProtocolType(D, Parent, C, properties); C.Impl.getArena(arena).ProtocolTypes.InsertNode(protoTy, insertPos); return protoTy; } -ProtocolType::ProtocolType(ProtocolDecl *TheDecl, const ASTContext &Ctx) - : NominalType(TypeKind::Protocol, &Ctx, TheDecl, /*Parent=*/Type(), - RecursiveTypeProperties()) { } +ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent, + const ASTContext &Ctx, + RecursiveTypeProperties properties) + : NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { } void ProtocolType::Profile(llvm::FoldingSetNodeID &ID, ProtocolDecl *D, Type Parent) { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 723687bcd87ad..4c2f182c76e26 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -33,15 +33,39 @@ using namespace swift; -#define DEF_COLOR(NAME, COLOR)\ -static const llvm::raw_ostream::Colors NAME##Color = llvm::raw_ostream::COLOR; +struct TerminalColor { + llvm::raw_ostream::Colors Color; + bool Bold; +}; -DEF_COLOR(Func, YELLOW) -DEF_COLOR(Extension, MAGENTA) -DEF_COLOR(Pattern, RED) -DEF_COLOR(TypeRepr, GREEN) -DEF_COLOR(Type, BLUE) -DEF_COLOR(TypeField, CYAN) +#define DEF_COLOR(NAME, COLOR, BOLD) \ +static const TerminalColor NAME##Color = { llvm::raw_ostream::COLOR, BOLD }; + +DEF_COLOR(Func, YELLOW, false) +DEF_COLOR(Range, YELLOW, false) +DEF_COLOR(Accessibility, YELLOW, false) +DEF_COLOR(ASTNode, YELLOW, true) +DEF_COLOR(Parameter, YELLOW, false) +DEF_COLOR(Extension, MAGENTA, false) +DEF_COLOR(Pattern, RED, true) +DEF_COLOR(Override, RED, false) +DEF_COLOR(Stmt, RED, true) +DEF_COLOR(Captures, RED, false) +DEF_COLOR(Arguments, RED, false) +DEF_COLOR(TypeRepr, GREEN, false) +DEF_COLOR(LiteralValue, GREEN, false) +DEF_COLOR(Decl, GREEN, true) +DEF_COLOR(Parenthesis, BLUE, false) +DEF_COLOR(Type, BLUE, false) +DEF_COLOR(Discriminator, BLUE, false) +DEF_COLOR(InterfaceType, GREEN, false) +DEF_COLOR(Identifier, GREEN, false) +DEF_COLOR(Expr, MAGENTA, true) +DEF_COLOR(ExprModifier, CYAN, false) +DEF_COLOR(DeclModifier, CYAN, false) +DEF_COLOR(ClosureModifier, CYAN, false) +DEF_COLOR(TypeField, CYAN, false) +DEF_COLOR(Location, CYAN, false) #undef DEF_COLOR @@ -51,33 +75,47 @@ namespace { class PrintWithColorRAII { raw_ostream &OS; bool ShowColors; - + public: - PrintWithColorRAII(raw_ostream &os, llvm::raw_ostream::Colors color) + PrintWithColorRAII(raw_ostream &os, TerminalColor color) : OS(os), ShowColors(false) { if (&os == &llvm::errs() || &os == &llvm::outs()) ShowColors = llvm::errs().has_colors() && llvm::outs().has_colors(); - - if (ShowColors) { - if (auto str = llvm::sys::Process::OutputColor(color, false, false)) { - OS << str; - } - } + + if (ShowColors) + OS.changeColor(color.Color, color.Bold); } - + ~PrintWithColorRAII() { if (ShowColors) { OS.resetColor(); } } - + + raw_ostream &getOS() const { return OS; } + template friend raw_ostream &operator<<(PrintWithColorRAII &&printer, const T &value){ printer.OS << value; return printer.OS; } + + friend raw_ostream &operator<<(PrintWithColorRAII &&printer, + AccessSemantics accessKind){ + switch (accessKind) { + case AccessSemantics::Ordinary: + return printer.OS; + case AccessSemantics::DirectToStorage: + return printer.OS << " direct_to_storage"; + case AccessSemantics::DirectToAccessor: + return printer.OS << " direct_to_accessor"; + case AccessSemantics::BehaviorInitialization: + return printer.OS << " behavior_init"; + } + llvm_unreachable("bad access kind"); + } }; } // end anonymous namespace @@ -215,28 +253,17 @@ namespace { } raw_ostream &printCommon(Pattern *P, const char *Name) { - OS.indent(Indent) << '('; - - // Support optional color output. - if (ShowColors) { - if (const char *CStr = - llvm::sys::Process::OutputColor(PatternColor, false, false)) { - OS << CStr; - } - } - - OS << Name; - - if (ShowColors) - OS.resetColor(); + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, PatternColor) << Name; if (P->isImplicit()) - OS << " implicit"; + PrintWithColorRAII(OS, ExprModifierColor) << " implicit"; if (P->hasType()) { - OS << " type='"; - P->getType().print(OS); - OS << '\''; + PrintWithColorRAII(OS, TypeColor) << " type='"; + P->getType().print(PrintWithColorRAII(OS, TypeColor).getOS()); + PrintWithColorRAII(OS, TypeColor) << "'"; } return OS; } @@ -244,7 +271,7 @@ namespace { void visitParenPattern(ParenPattern *P) { printCommon(P, "pattern_paren") << '\n'; printRec(P->getSubPattern()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTuplePattern(TuplePattern *P) { printCommon(P, "pattern_tuple"); @@ -261,13 +288,16 @@ namespace { OS << '\n'; printRec(elt.getPattern()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitNamedPattern(NamedPattern *P) { - printCommon(P, "pattern_named")<< " '" << P->getNameStr() << "')"; + printCommon(P, "pattern_named"); + PrintWithColorRAII(OS, IdentifierColor) << " '" << P->getNameStr() << "'"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitAnyPattern(AnyPattern *P) { - printCommon(P, "pattern_any") << ')'; + printCommon(P, "pattern_any"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTypedPattern(TypedPattern *P) { printCommon(P, "pattern_typed") << '\n'; @@ -276,18 +306,18 @@ namespace { OS << '\n'; printRec(P->getTypeLoc().getTypeRepr()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitIsPattern(IsPattern *P) { - printCommon(P, "pattern_is") + printCommon(P, "pattern_is") << ' ' << getCheckedCastKindName(P->getCastKind()) << ' '; P->getCastTypeLoc().getType().print(OS); if (auto sub = P->getSubPattern()) { OS << '\n'; printRec(sub); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitExprPattern(ExprPattern *P) { printCommon(P, "pattern_expr"); @@ -296,30 +326,31 @@ namespace { printRec(m); else printRec(P->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitVarPattern(VarPattern *P) { printCommon(P, P->isLet() ? "pattern_let" : "pattern_var"); OS << '\n'; printRec(P->getSubPattern()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitEnumElementPattern(EnumElementPattern *P) { printCommon(P, "pattern_enum_element"); OS << ' '; - P->getParentType().getType().print(OS); - OS << '.' << P->getName(); + P->getParentType().getType().print( + PrintWithColorRAII(OS, TypeColor).getOS()); + PrintWithColorRAII(OS, IdentifierColor) << '.' << P->getName(); if (P->hasSubPattern()) { OS << '\n'; printRec(P->getSubPattern()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOptionalSomePattern(OptionalSomePattern *P) { printCommon(P, "optional_some_element"); OS << '\n'; printRec(P->getSubPattern()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitBoolPattern(BoolPattern *P) { printCommon(P, "pattern_bool"); @@ -357,25 +388,13 @@ namespace { } void printCommon(Decl *D, const char *Name, - llvm::Optional Color = - llvm::Optional()) { - OS.indent(Indent) << '('; - - // Support optional color output. - if (ShowColors && Color.hasValue()) { - if (const char *CStr = - llvm::sys::Process::OutputColor(Color.getValue(), false, false)) { - OS << CStr; - } - } - - OS << Name; - - if (ShowColors) - OS.resetColor(); + TerminalColor Color = DeclColor) { + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, Color) << Name; if (D->isImplicit()) - OS << " implicit"; + PrintWithColorRAII(OS, DeclModifierColor) << " implicit"; } void printInherited(ArrayRef Inherited) { @@ -451,19 +470,24 @@ namespace { } void printDeclName(const ValueDecl *D) { - if (D->getFullName()) - OS << '\"' << D->getFullName() << '\"'; - else - OS << "'anonname=" << (const void*)D << '\''; + if (D->getFullName()) { + PrintWithColorRAII(OS, IdentifierColor) + << '\"' << D->getFullName() << '\"'; + } else { + PrintWithColorRAII(OS, IdentifierColor) + << "'anonname=" << (const void*)D << '\''; + } } void visitTypeAliasDecl(TypeAliasDecl *TAD) { printCommon(TAD, "typealias"); - OS << " type='"; - if (TAD->getUnderlyingTypeLoc().getType()) - OS << TAD->getUnderlyingTypeLoc().getType().getString(); - else - OS << "<<>>"; + PrintWithColorRAII(OS, TypeColor) << " type='"; + if (TAD->getUnderlyingTypeLoc().getType()) { + PrintWithColorRAII(OS, TypeColor) + << TAD->getUnderlyingTypeLoc().getType().getString(); + } else { + PrintWithColorRAII(OS, TypeColor) << "<<>>"; + } printInherited(TAD->getInherited()); OS << "')"; } @@ -503,9 +527,8 @@ namespace { } void printCommon(ValueDecl *VD, const char *Name, - llvm::Optional Color = - llvm::Optional()) { - printCommon((Decl*)VD, Name); + TerminalColor Color = DeclColor) { + printCommon((Decl*)VD, Name, Color); OS << ' '; printDeclName(VD); @@ -515,44 +538,45 @@ namespace { printGenericParameters(OS, GTD->getGenericParams()); if (auto *var = dyn_cast(VD)) { - OS << " type='"; + PrintWithColorRAII(OS, TypeColor) << " type='"; if (var->hasType()) - var->getType().print(OS); + var->getType().print(PrintWithColorRAII(OS, TypeColor).getOS()); else - OS << ""; - OS << '\''; + PrintWithColorRAII(OS, TypeColor) << ""; + PrintWithColorRAII(OS, TypeColor) << "'"; } if (VD->hasInterfaceType()) { - OS << " interface type='"; - VD->getInterfaceType()->print(OS); - OS << '\''; + PrintWithColorRAII(OS, InterfaceTypeColor) << " interface type='"; + VD->getInterfaceType()->print( + PrintWithColorRAII(OS, InterfaceTypeColor).getOS()); + PrintWithColorRAII(OS, InterfaceTypeColor) << "'"; } if (VD->hasAccessibility()) { - OS << " access="; + PrintWithColorRAII(OS, AccessibilityColor) << " access="; switch (VD->getFormalAccess()) { case Accessibility::Private: - OS << "private"; + PrintWithColorRAII(OS, AccessibilityColor) << "private"; break; case Accessibility::FilePrivate: - OS << "fileprivate"; + PrintWithColorRAII(OS, AccessibilityColor) << "fileprivate"; break; case Accessibility::Internal: - OS << "internal"; + PrintWithColorRAII(OS, AccessibilityColor) << "internal"; break; case Accessibility::Public: - OS << "public"; + PrintWithColorRAII(OS, AccessibilityColor) << "public"; break; case Accessibility::Open: - OS << "open"; + PrintWithColorRAII(OS, AccessibilityColor) << "open"; break; } } if (auto Overridden = VD->getOverriddenDecl()) { - OS << " override="; - Overridden->dumpRef(OS); + PrintWithColorRAII(OS, OverrideColor) << " override="; + Overridden->dumpRef(PrintWithColorRAII(OS, OverrideColor).getOS()); } if (VD->isFinal()) @@ -562,8 +586,7 @@ namespace { } void printCommon(NominalTypeDecl *NTD, const char *Name, - llvm::Optional Color = - llvm::Optional()) { + TerminalColor Color = DeclColor) { printCommon((ValueDecl *)NTD, Name, Color); if (NTD->hasInterfaceType()) { @@ -575,7 +598,9 @@ namespace { } void visitSourceFile(const SourceFile &SF) { - OS.indent(Indent) << "(source_file"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, ASTNodeColor) << "source_file"; for (Decl *D : SF.Decls) { if (D->isImplicit()) continue; @@ -583,23 +608,24 @@ namespace { OS << '\n'; printRec(D); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitVarDecl(VarDecl *VD) { printCommon(VD, "var_decl"); if (VD->isStatic()) - OS << " type"; + PrintWithColorRAII(OS, DeclModifierColor) << " type"; if (VD->isLet()) - OS << " let"; + PrintWithColorRAII(OS, DeclModifierColor) << " let"; if (VD->hasNonPatternBindingInit()) - OS << " non_pattern_init"; - OS << " storage_kind=" << getStorageKindName(VD->getStorageKind()); + PrintWithColorRAII(OS, DeclModifierColor) << " non_pattern_init"; + PrintWithColorRAII(OS, DeclModifierColor) + << " storage_kind=" << getStorageKindName(VD->getStorageKind()); if (VD->getAttrs().hasAttribute()) - OS << " lazy"; + PrintWithColorRAII(OS, DeclModifierColor) << " lazy"; printAccessors(VD); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void printAccessors(AbstractStorageDecl *D) { @@ -647,7 +673,7 @@ namespace { OS << '\n'; printRec(D); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitEnumDecl(EnumDecl *ED) { @@ -657,12 +683,12 @@ namespace { OS << '\n'; printRec(D); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitEnumElementDecl(EnumElementDecl *EED) { printCommon(EED, "enum_element_decl"); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitStructDecl(StructDecl *SD) { @@ -687,7 +713,7 @@ namespace { void visitPatternBindingDecl(PatternBindingDecl *PBD) { printCommon(PBD, "pattern_binding_decl"); - + for (auto entry : PBD->getPatternList()) { OS << '\n'; printRec(entry.getPattern()); @@ -696,16 +722,16 @@ namespace { printRec(entry.getInit()); } } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitSubscriptDecl(SubscriptDecl *SD) { printCommon(SD, "subscript_decl"); OS << " storage_kind=" << getStorageKindName(SD->getStorageKind()); printAccessors(SD); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void printCommonAFD(AbstractFunctionDecl *D, const char *Type) { printCommon(D, Type, FuncColor); if (!D->getCaptureInfo().isTrivial()) { @@ -749,30 +775,32 @@ namespace { OS << ",resulttype=" << fec->getResultType().getString(); } } - + void printParameter(const ParamDecl *P) { - OS.indent(Indent) << "(parameter "; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, ParameterColor) << "parameter "; printDeclName(P); if (!P->getArgumentName().empty()) - OS << " apiName=" << P->getArgumentName(); - + PrintWithColorRAII(OS, IdentifierColor) + << " apiName=" << P->getArgumentName(); + if (P->hasType()) { - OS << " type="; - OS << '\''; - P->getType().print(OS); - OS << '\''; + PrintWithColorRAII(OS, TypeColor) << " type='"; + P->getType().print(PrintWithColorRAII(OS, TypeColor).getOS()); + PrintWithColorRAII(OS, TypeColor) << "'"; } - + if (P->hasInterfaceType()) { - OS << " interface type="; - OS << '\''; - P->getInterfaceType().print(OS); - OS << '\''; + PrintWithColorRAII(OS, InterfaceTypeColor) << " interface type='"; + P->getInterfaceType().print( + PrintWithColorRAII(OS, InterfaceTypeColor).getOS()); + PrintWithColorRAII(OS, InterfaceTypeColor) << "'"; } - + if (!P->isLet()) OS << " mutable"; - + if (P->isVariadic()) OS << " variadic"; @@ -809,24 +837,25 @@ namespace { printField("default_arg", "normal"); break; } - + if (auto init = P->getDefaultValue()) { OS << " expression=\n"; printRec(init); } - - OS << ')'; + + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - void printParameterList(const ParameterList *params) { - OS.indent(Indent) << "(parameter_list"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, ParameterColor) << "parameter_list"; Indent += 2; for (auto P : *params) { OS << '\n'; printParameter(P); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; Indent -= 2; } @@ -842,9 +871,10 @@ namespace { OS << '\n'; Indent += 2; OS.indent(Indent); - OS << "(result\n"; + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "result\n"; printRec(FD->getBodyResultTypeLoc().getTypeRepr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; Indent -= 2; } } @@ -853,7 +883,7 @@ namespace { printRec(Body); } } - + void visitFuncDecl(FuncDecl *FD) { printCommonAFD(FD, "func_decl"); if (FD->isStatic()) @@ -872,62 +902,65 @@ namespace { OS << "_for=" << ASD->getFullName(); } - + for (auto VD: FD->getSatisfiedProtocolRequirements()) { OS << '\n'; - OS.indent(Indent+2) << "(conformance "; + OS.indent(Indent+2); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "conformance "; VD->dumpRef(OS); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } printAbstractFunctionDecl(FD); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitConstructorDecl(ConstructorDecl *CD) { printCommonAFD(CD, "constructor_decl"); if (CD->isRequired()) - OS << " required"; + PrintWithColorRAII(OS, DeclModifierColor) << " required"; switch (CD->getInitKind()) { case CtorInitializerKind::Designated: - OS << " designated"; + PrintWithColorRAII(OS, DeclModifierColor) << " designated"; break; case CtorInitializerKind::Convenience: - OS << " convenience"; + PrintWithColorRAII(OS, DeclModifierColor) << " convenience"; break; case CtorInitializerKind::ConvenienceFactory: - OS << " convenience_factory"; + PrintWithColorRAII(OS, DeclModifierColor) << " convenience_factory"; break; case CtorInitializerKind::Factory: - OS << " factory"; + PrintWithColorRAII(OS, DeclModifierColor) << " factory"; break; } - + switch (CD->getFailability()) { case OTK_None: break; case OTK_Optional: - OS << " failable=Optional"; + PrintWithColorRAII(OS, DeclModifierColor) << " failable=Optional"; break; case OTK_ImplicitlyUnwrappedOptional: - OS << " failable=ImplicitlyUnwrappedOptional"; + PrintWithColorRAII(OS, DeclModifierColor) + << " failable=ImplicitlyUnwrappedOptional"; break; } printAbstractFunctionDecl(CD); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDestructorDecl(DestructorDecl *DD) { printCommonAFD(DD, "destructor_decl"); printAbstractFunctionDecl(DD); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { @@ -936,27 +969,35 @@ namespace { OS << "\n"; printRec(TLCD->getBody()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitIfConfigDecl(IfConfigDecl *ICD) { - OS.indent(Indent) << "(#if_decl\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "#if_decl\n"; Indent += 2; for (auto &Clause : ICD->getClauses()) { - OS.indent(Indent) << (Clause.Cond ? "(#if:\n" : "\n(#else:\n"); - if (Clause.Cond) + if (Clause.Cond) { + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "#if:\n"; printRec(Clause.Cond); - + } else { + OS << '\n'; + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "#else:\n"; + } + for (auto D : Clause.Members) { OS << '\n'; printRec(D); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + Indent -= 2; - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitPrecedenceGroupDecl(PrecedenceGroupDecl *PGD) { @@ -986,31 +1027,33 @@ namespace { printRelations("higherThan", PGD->getHigherThan()); printRelations("lowerThan", PGD->getLowerThan()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitInfixOperatorDecl(InfixOperatorDecl *IOD) { printCommon(IOD, "infix_operator_decl "); OS << IOD->getName() << "\n"; OS.indent(Indent+2); OS << "precedence " << IOD->getPrecedenceGroupName(); if (!IOD->getPrecedenceGroup()) OS << " "; - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitPrefixOperatorDecl(PrefixOperatorDecl *POD) { printCommon(POD, "prefix_operator_decl "); - OS << POD->getName() << ')'; + OS << POD->getName(); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitPostfixOperatorDecl(PostfixOperatorDecl *POD) { printCommon(POD, "postfix_operator_decl "); - OS << POD->getName() << ')'; + OS << POD->getName(); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitModuleDecl(ModuleDecl *MD) { printCommon(MD, "module"); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } }; } // end anonymous namespace @@ -1070,11 +1113,15 @@ void swift::printContext(raw_ostream &os, DeclContext *dc) { case DeclContextKind::AbstractClosureExpr: { auto *ACE = cast(dc); - if (isa(ACE)) - os << "explicit closure discriminator="; - if (isa(ACE)) - os << "autoclosure discriminator="; - os << ACE->getDiscriminator(); + if (isa(ACE)) { + PrintWithColorRAII(os, DiscriminatorColor) + << "explicit closure discriminator="; + } + if (isa(ACE)) { + PrintWithColorRAII(os, DiscriminatorColor) + << "autoclosure discriminator="; + } + PrintWithColorRAII(os, DiscriminatorColor) << ACE->getDiscriminator(); break; } @@ -1194,24 +1241,28 @@ class PrintStmt : public StmtVisitor { void printRec(const Pattern *P) { PrintPattern(OS, Indent+2).visit(const_cast(P)); } - + void printRec(StmtConditionElement C) { switch (C.getKind()) { case StmtConditionElement::CK_Boolean: return printRec(C.getBoolean()); case StmtConditionElement::CK_PatternBinding: Indent += 2; - OS.indent(Indent) << "(pattern\n"; - + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, PatternColor) << "pattern\n"; + printRec(C.getPattern()); OS << "\n"; printRec(C.getInitializer()); - OS << ")"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; Indent -= 2; break; case StmtConditionElement::CK_Availability: Indent += 2; - OS.indent(Indent) << "(#available\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "#available\n"; for (auto *Query : C.getAvailability()->getQueries()) { OS << '\n'; switch (Query->getKind()) { @@ -1226,18 +1277,20 @@ class PrintStmt : public StmtVisitor { break; } } - OS << ")"; + PrintWithColorRAII(OS, ParenthesisColor) << ")"; Indent -= 2; break; } } - + void visitBraceStmt(BraceStmt *S) { printASTNodes(S->getElements(), "brace_stmt"); } void printASTNodes(const ArrayRef &Elements, StringRef Name) { - OS.indent(Indent) << "(" << Name; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << "("; + PrintWithColorRAII(OS, ASTNodeColor) << Name; for (auto Elt : Elements) { OS << '\n'; if (Expr *SubExpr = Elt.dyn_cast()) @@ -1247,28 +1300,34 @@ class PrintStmt : public StmtVisitor { else printRec(Elt.get()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitReturnStmt(ReturnStmt *S) { - OS.indent(Indent) << "(return_stmt"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "return_stmt"; if (S->hasResult()) { OS << '\n'; printRec(S->getResult()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitDeferStmt(DeferStmt *S) { - OS.indent(Indent) << "(defer_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "defer_stmt\n"; printRec(S->getTempDecl()); OS << '\n'; printRec(S->getCallExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitIfStmt(IfStmt *S) { - OS.indent(Indent) << "(if_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "if_stmt\n"; for (auto elt : S->getCond()) printRec(elt); OS << '\n'; @@ -1277,60 +1336,77 @@ class PrintStmt : public StmtVisitor { OS << '\n'; printRec(S->getElseStmt()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitGuardStmt(GuardStmt *S) { - OS.indent(Indent) << "(guard_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "guard_stmt\n"; for (auto elt : S->getCond()) printRec(elt); OS << '\n'; printRec(S->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitIfConfigStmt(IfConfigStmt *S) { - OS.indent(Indent) << "(#if_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "#if_stmt\n"; Indent += 2; for (auto &Clause : S->getClauses()) { - OS.indent(Indent) << (Clause.Cond ? "(#if:\n" : "#else"); - if (Clause.Cond) + OS.indent(Indent); + if (Clause.Cond) { + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "#if:\n"; printRec(Clause.Cond); + } else { + PrintWithColorRAII(OS, StmtColor) << "#else"; + } OS << '\n'; Indent += 2; printASTNodes(Clause.Elements, "elements"); Indent -= 2; } - + Indent -= 2; - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDoStmt(DoStmt *S) { - OS.indent(Indent) << "(do_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "do_stmt\n"; printRec(S->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitWhileStmt(WhileStmt *S) { - OS.indent(Indent) << "(while_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "while_stmt\n"; for (auto elt : S->getCond()) printRec(elt); OS << '\n'; printRec(S->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitRepeatWhileStmt(RepeatWhileStmt *S) { - OS.indent(Indent) << "(do_while_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "do_while_stmt\n"; printRec(S->getBody()); OS << '\n'; printRec(S->getCond()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitForStmt(ForStmt *S) { - OS.indent(Indent) << "(for_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "for_stmt\n"; if (!S->getInitializerVarDecls().empty()) { for (auto D : S->getInitializerVarDecls()) { printRec(D); @@ -1356,10 +1432,12 @@ class PrintStmt : public StmtVisitor { } OS << '\n'; printRec(S->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitForEachStmt(ForEachStmt *S) { - OS.indent(Indent) << "(for_each_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "for_each_stmt\n"; printRec(S->getPattern()); OS << '\n'; if (S->getWhere()) { @@ -1382,31 +1460,46 @@ class PrintStmt : public StmtVisitor { OS << '\n'; } printRec(S->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitBreakStmt(BreakStmt *S) { - OS.indent(Indent) << "(break_stmt)"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "break_stmt"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitContinueStmt(ContinueStmt *S) { - OS.indent(Indent) << "(continue_stmt)"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "continue_stmt"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitFallthroughStmt(FallthroughStmt *S) { - OS.indent(Indent) << "(fallthrough_stmt)"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "fallthrough_stmt"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitSwitchStmt(SwitchStmt *S) { - OS.indent(Indent) << "(switch_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "switch_stmt\n"; printRec(S->getSubjectExpr()); for (CaseStmt *C : S->getCases()) { OS << '\n'; printRec(C); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCaseStmt(CaseStmt *S) { - OS.indent(Indent) << "(case_stmt"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "case_stmt"; for (const auto &LabelItem : S->getCaseLabelItems()) { OS << '\n'; - OS.indent(Indent + 2) << "(case_label_item"; + OS.indent(Indent + 2); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "case_label_item"; if (auto *CasePattern = LabelItem.getPattern()) { OS << '\n'; printRec(CasePattern); @@ -1415,30 +1508,37 @@ class PrintStmt : public StmtVisitor { OS << '\n'; Guard->print(OS, Indent+4); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } OS << '\n'; printRec(S->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitFailStmt(FailStmt *S) { - OS.indent(Indent) << "(fail_stmt)"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "fail_stmt"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitThrowStmt(ThrowStmt *S) { - OS.indent(Indent) << "(throw_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "throw_stmt\n"; printRec(S->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDoCatchStmt(DoCatchStmt *S) { - OS.indent(Indent) << "(do_catch_stmt\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "do_catch_stmt\n"; printRec(S->getBody()); OS << '\n'; Indent += 2; visitCatches(S->getCatches()); Indent -= 2; - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCatches(ArrayRef clauses) { for (auto clause : clauses) { @@ -1446,7 +1546,9 @@ class PrintStmt : public StmtVisitor { } } void visitCatchStmt(CatchStmt *clause) { - OS.indent(Indent) << "(catch\n"; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, StmtColor) << "catch\n"; printRec(clause->getErrorPattern()); if (auto guard = clause->getGuardExpr()) { OS << '\n'; @@ -1454,7 +1556,7 @@ class PrintStmt : public StmtVisitor { } OS << '\n'; printRec(clause->getBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } }; @@ -1473,16 +1575,6 @@ void Stmt::print(raw_ostream &OS, unsigned Indent) const { // Printing for Expr and all subclasses. //===----------------------------------------------------------------------===// -static raw_ostream &operator<<(raw_ostream &os, AccessSemantics accessKind) { - switch (accessKind) { - case AccessSemantics::Ordinary: return os; - case AccessSemantics::DirectToStorage: return os << " direct_to_storage"; - case AccessSemantics::DirectToAccessor: return os << " direct_to_accessor"; - case AccessSemantics::BehaviorInitialization: return os << " behavior_init"; - } - llvm_unreachable("bad access kind"); -} - namespace { /// PrintExpr - Visitor implementation of Expr::print. class PrintExpr : public ExprVisitor { @@ -1505,9 +1597,10 @@ class PrintExpr : public ExprVisitor { void printRecLabeled(Expr *E, StringRef label) { Indent += 2; OS.indent(Indent); - OS << '(' << label << '\n'; + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << '\n'; printRec(E); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; Indent -= 2; } @@ -1533,27 +1626,33 @@ class PrintExpr : public ExprVisitor { } raw_ostream &printCommon(Expr *E, const char *C) { - OS.indent(Indent) << '(' << C; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, ExprColor) << C; + if (E->isImplicit()) - OS << " implicit"; - OS << " type='" << E->getType() << '\''; + PrintWithColorRAII(OS, ExprModifierColor) << " implicit"; + PrintWithColorRAII(OS, TypeColor) << " type='" << E->getType() << '\''; - if (E->hasLValueAccessKind()) - OS << " accessKind=" << getAccessKindString(E->getLValueAccessKind()); + if (E->hasLValueAccessKind()) { + PrintWithColorRAII(OS, ExprModifierColor) + << " accessKind=" << getAccessKindString(E->getLValueAccessKind()); + } // If we have a source range and an ASTContext, print the source range. if (auto Ty = E->getType()) { auto &Ctx = Ty->getASTContext(); auto L = E->getLoc(); if (L.isValid()) { - OS << " location="; - L.print(OS, Ctx.SourceMgr); + PrintWithColorRAII(OS, LocationColor) << " location="; + L.print(PrintWithColorRAII(OS, LocationColor).getOS(), Ctx.SourceMgr); } auto R = E->getSourceRange(); if (R.isValid()) { - OS << " range="; - R.print(OS, Ctx.SourceMgr, /*PrintText=*/false); + PrintWithColorRAII(OS, RangeColor) << " range="; + R.print(PrintWithColorRAII(OS, RangeColor).getOS(), + Ctx.SourceMgr, /*PrintText=*/false); } } @@ -1561,58 +1660,72 @@ class PrintExpr : public ExprVisitor { } void visitErrorExpr(ErrorExpr *E) { - printCommon(E, "error_expr") << ')'; + printCommon(E, "error_expr"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCodeCompletionExpr(CodeCompletionExpr *E) { - printCommon(E, "code_completion_expr") << ')'; + printCommon(E, "code_completion_expr"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitNilLiteralExpr(NilLiteralExpr *E) { - printCommon(E, "nil_literal_expr") << ')'; + printCommon(E, "nil_literal_expr"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitIntegerLiteralExpr(IntegerLiteralExpr *E) { printCommon(E, "integer_literal_expr"); if (E->isNegative()) - OS << " negative"; - OS << " value="; + PrintWithColorRAII(OS, LiteralValueColor) << " negative"; + PrintWithColorRAII(OS, LiteralValueColor) << " value="; Type T = E->getType(); if (T.isNull() || !T->is()) - OS << E->getDigitsText(); + PrintWithColorRAII(OS, LiteralValueColor) << E->getDigitsText(); else - OS << E->getValue(); - OS << ')'; + PrintWithColorRAII(OS, LiteralValueColor) << E->getValue(); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitFloatLiteralExpr(FloatLiteralExpr *E) { - printCommon(E, "float_literal_expr") << " value=" - << E->getDigitsText() << ')'; + printCommon(E, "float_literal_expr"); + PrintWithColorRAII(OS, LiteralValueColor) + << " value=" << E->getDigitsText(); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitBooleanLiteralExpr(BooleanLiteralExpr *E) { - printCommon(E, "boolean_literal_expr") - << " value=" << (E->getValue() ? "true" : "false") - << ')'; + printCommon(E, "boolean_literal_expr"); + PrintWithColorRAII(OS, LiteralValueColor) + << " value=" << (E->getValue() ? "true" : "false"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void printStringEncoding(StringLiteralExpr::Encoding encoding) { switch (encoding) { - case StringLiteralExpr::UTF8: OS << "utf8"; break; - case StringLiteralExpr::UTF16: OS << "utf16"; break; - case StringLiteralExpr::OneUnicodeScalar: OS << "unicodeScalar"; break; + case StringLiteralExpr::UTF8: + PrintWithColorRAII(OS, LiteralValueColor) << "utf8"; + break; + case StringLiteralExpr::UTF16: + PrintWithColorRAII(OS, LiteralValueColor) << "utf16"; + break; + case StringLiteralExpr::OneUnicodeScalar: + PrintWithColorRAII(OS, LiteralValueColor) << "unicodeScalar"; + break; } } void visitStringLiteralExpr(StringLiteralExpr *E) { - printCommon(E, "string_literal_expr") - << " encoding="; + printCommon(E, "string_literal_expr"); + PrintWithColorRAII(OS, LiteralValueColor) << " encoding="; printStringEncoding(E->getEncoding()); - OS << " value=" << QuotedString(E->getValue()) - << " builtin_initializer="; - E->getBuiltinInitializer().dump(OS); - OS << " initializer="; - E->getInitializer().dump(OS); - OS << ')'; + PrintWithColorRAII(OS, LiteralValueColor) + << " value=" << QuotedString(E->getValue()) + << " builtin_initializer="; + E->getBuiltinInitializer().dump( + PrintWithColorRAII(OS, LiteralValueColor).getOS()); + PrintWithColorRAII(OS, LiteralValueColor) << " initializer="; + E->getInitializer().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) { printCommon(E, "interpolated_string_literal_expr"); @@ -1620,7 +1733,7 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(Segment); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E) { printCommon(E, "magic_identifier_literal_expr") << " kind="; @@ -1646,7 +1759,7 @@ class PrintExpr : public ExprVisitor { OS << " initializer="; E->getInitializer().dump(OS); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitObjectLiteralExpr(ObjectLiteralExpr *E) { @@ -1658,42 +1771,46 @@ class PrintExpr : public ExprVisitor { } void visitDiscardAssignmentExpr(DiscardAssignmentExpr *E) { - printCommon(E, "discard_assignment_expr") << ')'; + printCommon(E, "discard_assignment_expr"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDeclRefExpr(DeclRefExpr *E) { - printCommon(E, "declref_expr") - << " decl="; - E->getDeclRef().dump(OS); - OS << E->getAccessSemantics(); - OS << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind()); - OS << " specialized=" << (E->isSpecialized()? "yes" : "no"); + printCommon(E, "declref_expr"); + PrintWithColorRAII(OS, DeclColor) << " decl="; + E->getDeclRef().dump(PrintWithColorRAII(OS, DeclColor).getOS()); + PrintWithColorRAII(OS, AccessibilityColor) << E->getAccessSemantics(); + PrintWithColorRAII(OS, ExprModifierColor) + << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind()) + << " specialized=" << (E->isSpecialized()? "yes" : "no"); for (auto TR : E->getGenericArgs()) { OS << '\n'; printRec(TR); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitSuperRefExpr(SuperRefExpr *E) { - printCommon(E, "super_ref_expr") << ')'; + printCommon(E, "super_ref_expr"); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTypeExpr(TypeExpr *E) { printCommon(E, "type_expr"); - OS << " typerepr='"; + PrintWithColorRAII(OS, TypeReprColor) << " typerepr='"; if (E->getTypeRepr()) - E->getTypeRepr()->print(OS); + E->getTypeRepr()->print(PrintWithColorRAII(OS, TypeReprColor).getOS()); else - OS << "<>"; - OS << "')"; + PrintWithColorRAII(OS, TypeReprColor) << "<>"; + PrintWithColorRAII(OS, TypeReprColor) << "'"; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *E) { printCommon(E, "other_constructor_ref_expr") << " decl="; E->getDeclRef().dump(OS); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *E) { printCommon(E, "overloaded_decl_ref_expr") @@ -1707,13 +1824,15 @@ class PrintExpr : public ExprVisitor { OS.indent(Indent); D->dumpRef(OS); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) { - printCommon(E, "unresolved_decl_ref_expr") - << " name=" << E->getName() - << " specialized=" << (E->isSpecialized()? "yes" : "no") << ')' + printCommon(E, "unresolved_decl_ref_expr"); + PrintWithColorRAII(OS, IdentifierColor) << " name=" << E->getName(); + PrintWithColorRAII(OS, ExprModifierColor) + << " specialized=" << (E->isSpecialized()? "yes" : "no") << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *E) { printCommon(E, "unresolved_specialize_expr") << '\n'; @@ -1722,21 +1841,21 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(T.getTypeRepr()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitMemberRefExpr(MemberRefExpr *E) { printCommon(E, "member_ref_expr") << " decl="; E->getMember().dump(OS); - - OS << E->getAccessSemantics(); + + PrintWithColorRAII(OS, AccessibilityColor) << E->getAccessSemantics(); if (E->isSuper()) OS << " super"; - + OS << '\n'; printRec(E->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDynamicMemberRefExpr(DynamicMemberRefExpr *E) { printCommon(E, "dynamic_member_ref_expr") @@ -1744,7 +1863,7 @@ class PrintExpr : public ExprVisitor { E->getMember().dump(OS); OS << '\n'; printRec(E->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { printCommon(E, "unresolved_member_expr") @@ -1760,7 +1879,7 @@ class PrintExpr : public ExprVisitor { printCommon(E, "dot_self_expr"); OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitParenExpr(ParenExpr *E) { printCommon(E, "paren_expr"); @@ -1768,7 +1887,7 @@ class PrintExpr : public ExprVisitor { OS << " trailing-closure"; OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTupleExpr(TupleExpr *E) { printCommon(E, "tuple_expr"); @@ -1776,11 +1895,14 @@ class PrintExpr : public ExprVisitor { OS << " trailing-closure"; if (E->hasElementNames()) { - OS << " names="; + PrintWithColorRAII(OS, IdentifierColor) << " names="; interleave(E->getElementNames(), - [&](Identifier name) { OS << (name.empty()?"''":name.str());}, - [&] { OS << ","; }); + [&](Identifier name) { + PrintWithColorRAII(OS, IdentifierColor) + << (name.empty()?"''":name.str()); + }, + [&] { PrintWithColorRAII(OS, IdentifierColor) << ","; }); } for (unsigned i = 0, e = E->getNumElements(); i != e; ++i) { @@ -1790,7 +1912,7 @@ class PrintExpr : public ExprVisitor { else OS.indent(Indent+2) << "<>"; } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitArrayExpr(ArrayExpr *E) { printCommon(E, "array_expr"); @@ -1798,7 +1920,7 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(elt); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDictionaryExpr(DictionaryExpr *E) { printCommon(E, "dictionary_expr"); @@ -1806,11 +1928,11 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(elt); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitSubscriptExpr(SubscriptExpr *E) { printCommon(E, "subscript_expr"); - OS << E->getAccessSemantics(); + PrintWithColorRAII(OS, AccessibilityColor) << E->getAccessSemantics(); if (E->isSuper()) OS << " super"; if (E->hasDecl()) { @@ -1822,7 +1944,7 @@ class PrintExpr : public ExprVisitor { printRec(E->getBase()); OS << '\n'; printRec(E->getIndex()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDynamicSubscriptExpr(DynamicSubscriptExpr *E) { printCommon(E, "dynamic_subscript_expr") @@ -1833,7 +1955,7 @@ class PrintExpr : public ExprVisitor { printRec(E->getBase()); OS << '\n'; printRec(E->getIndex()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnresolvedDotExpr(UnresolvedDotExpr *E) { printCommon(E, "unresolved_dot_expr") @@ -1843,13 +1965,13 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(E->getBase()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTupleElementExpr(TupleElementExpr *E) { printCommon(E, "tuple_element_expr") << " field #" << E->getFieldNumber() << '\n'; printRec(E->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTupleShuffleExpr(TupleShuffleExpr *E) { printCommon(E, "tuple_shuffle_expr"); @@ -1876,27 +1998,27 @@ class PrintExpr : public ExprVisitor { OS << "\n"; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E) { printCommon(E, "unresolvedtype_conversion_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitFunctionConversionExpr(FunctionConversionExpr *E) { printCommon(E, "function_conversion_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCovariantFunctionConversionExpr(CovariantFunctionConversionExpr *E){ printCommon(E, "covariant_function_conversion_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCovariantReturnConversionExpr(CovariantReturnConversionExpr *E){ printCommon(E, "covariant_return_conversion_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitErasureExpr(ErasureExpr *E) { printCommon(E, "erasure_expr") << '\n'; @@ -1905,24 +2027,24 @@ class PrintExpr : public ExprVisitor { OS << '\n'; } printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitAnyHashableErasureExpr(AnyHashableErasureExpr *E) { printCommon(E, "any_hashable_erasure_expr") << '\n'; printRec(E->getConformance()); OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitLoadExpr(LoadExpr *E) { printCommon(E, "load_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitMetatypeConversionExpr(MetatypeConversionExpr *E) { printCommon(E, "metatype_conversion_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E) { printCommon(E, "collection_upcast_expr"); @@ -1936,99 +2058,99 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRecLabeled(valueConversion.Conversion, "value_conversion"); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDerivedToBaseExpr(DerivedToBaseExpr *E) { printCommon(E, "derived_to_base_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E) { printCommon(E, "archetype_to_super_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitLValueToPointerExpr(LValueToPointerExpr *E) { printCommon(E, "lvalue_to_pointer") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitInjectIntoOptionalExpr(InjectIntoOptionalExpr *E) { printCommon(E, "inject_into_optional") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitClassMetatypeToObjectExpr(ClassMetatypeToObjectExpr *E) { printCommon(E, "class_metatype_to_object") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitExistentialMetatypeToObjectExpr(ExistentialMetatypeToObjectExpr *E) { printCommon(E, "existential_metatype_to_object") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitProtocolMetatypeToObjectExpr(ProtocolMetatypeToObjectExpr *E) { printCommon(E, "protocol_metatype_to_object") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitInOutToPointerExpr(InOutToPointerExpr *E) { printCommon(E, "inout_to_pointer") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitArrayToPointerExpr(ArrayToPointerExpr *E) { printCommon(E, "array_to_pointer") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitStringToPointerExpr(StringToPointerExpr *E) { printCommon(E, "string_to_pointer") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitPointerToPointerExpr(PointerToPointerExpr *E) { printCommon(E, "pointer_to_pointer") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitForeignObjectConversionExpr(ForeignObjectConversionExpr *E) { printCommon(E, "foreign_object_conversion") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitUnevaluatedInstanceExpr(UnevaluatedInstanceExpr *E) { printCommon(E, "unevaluated_instance") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitInOutExpr(InOutExpr *E) { printCommon(E, "inout_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitForceTryExpr(ForceTryExpr *E) { printCommon(E, "force_try_expr"); OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOptionalTryExpr(OptionalTryExpr *E) { printCommon(E, "optional_try_expr"); OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTryExpr(TryExpr *E) { printCommon(E, "try_expr"); OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitSequenceExpr(SequenceExpr *E) { @@ -2037,7 +2159,7 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(E->getElement(i)); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCaptureListExpr(CaptureListExpr *E) { @@ -2050,41 +2172,42 @@ class PrintExpr : public ExprVisitor { Indent -= 2; } printRec(E->getClosureBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } llvm::raw_ostream &printClosure(AbstractClosureExpr *E, char const *name) { printCommon(E, name); - OS << " discriminator=" << E->getDiscriminator(); + PrintWithColorRAII(OS, DiscriminatorColor) + << " discriminator=" << E->getDiscriminator(); if (!E->getCaptureInfo().isTrivial()) { OS << " "; - E->getCaptureInfo().print(OS); + E->getCaptureInfo().print(PrintWithColorRAII(OS, CapturesColor).getOS()); } - + return OS; } void visitClosureExpr(ClosureExpr *E) { printClosure(E, "closure_expr"); if (E->hasSingleExpressionBody()) - OS << " single-expression"; - + PrintWithColorRAII(OS, ClosureModifierColor) << " single-expression"; + if (E->getParameters()) { OS << '\n'; PrintDecl(OS, Indent+2).printParameterList(E->getParameters()); } - + OS << '\n'; if (E->hasSingleExpressionBody()) { printRec(E->getSingleExpressionBody()); } else { printRec(E->getBody()); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitAutoClosureExpr(AutoClosureExpr *E) { printClosure(E, "autoclosure_expr") << '\n'; - + if (E->getParameters()) { OS << '\n'; PrintDecl(OS, Indent+2).printParameterList(E->getParameters()); @@ -2092,33 +2215,37 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(E->getSingleExpressionBody()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDynamicTypeExpr(DynamicTypeExpr *E) { printCommon(E, "metatype_expr"); OS << '\n'; printRec(E->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOpaqueValueExpr(OpaqueValueExpr *E) { printCommon(E, "opaque_value_expr") << " @ " << (void*)E; - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void printArgumentLabels(ArrayRef argLabels) { - OS << " arg_labels="; - for (auto label : argLabels) - OS << (label.empty() ? "_" : label.str()) << ":"; + PrintWithColorRAII(OS, ArgumentsColor) << " arg_labels="; + for (auto label : argLabels) { + PrintWithColorRAII(OS, ArgumentsColor) + << (label.empty() ? "_" : label.str()) << ":"; + } } void printApplyExpr(ApplyExpr *E, const char *NodeName) { printCommon(E, NodeName); if (E->isSuper()) - OS << " super"; - if (E->isThrowsSet()) - OS << (E->throws() ? " throws" : " nothrow"); + PrintWithColorRAII(OS, ExprModifierColor) << " super"; + if (E->isThrowsSet()) { + PrintWithColorRAII(OS, ExprModifierColor) + << (E->throws() ? " throws" : " nothrow"); + } if (auto call = dyn_cast(E)) printArgumentLabels(call->getArgumentLabels()); @@ -2126,7 +2253,7 @@ class PrintExpr : public ExprVisitor { printRec(E->getFn()); OS << '\n'; printRec(E->getArg()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCallExpr(CallExpr *E) { @@ -2152,7 +2279,7 @@ class PrintExpr : public ExprVisitor { printRec(E->getLHS()); OS << '\n'; printRec(E->getRHS()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void printExplicitCastExpr(ExplicitCastExpr *E, const char *name) { @@ -2163,7 +2290,7 @@ class PrintExpr : public ExprVisitor { E->getCastTypeLoc().getType().print(OS); OS << "'\n"; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitForcedCheckedCastExpr(ForcedCheckedCastExpr *E) { printExplicitCastExpr(E, "forced_checked_cast_expr"); @@ -2182,12 +2309,12 @@ class PrintExpr : public ExprVisitor { printRec(E->getArgsExpr()); OS << '\n'; printRec(E->getResultExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) { printCommon(E, "rebind_self_in_constructor_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitIfExpr(IfExpr *E) { printCommon(E, "if_expr") << '\n'; @@ -2196,14 +2323,14 @@ class PrintExpr : public ExprVisitor { printRec(E->getThenExpr()); OS << '\n'; printRec(E->getElseExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitAssignExpr(AssignExpr *E) { OS.indent(Indent) << "(assign_expr\n"; printRec(E->getDest()); OS << '\n'; printRec(E->getSrc()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitEnumIsCaseExpr(EnumIsCaseExpr *E) { printCommon(E, "enum_is_case_expr") << ' ' << @@ -2214,23 +2341,23 @@ class PrintExpr : public ExprVisitor { void visitUnresolvedPatternExpr(UnresolvedPatternExpr *E) { printCommon(E, "unresolved_pattern_expr") << '\n'; printRec(E->getSubPattern()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitBindOptionalExpr(BindOptionalExpr *E) { printCommon(E, "bind_optional_expr") << " depth=" << E->getDepth() << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOptionalEvaluationExpr(OptionalEvaluationExpr *E) { printCommon(E, "optional_evaluation_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitForceValueExpr(ForceValueExpr *E) { printCommon(E, "force_value_expr") << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitOpenExistentialExpr(OpenExistentialExpr *E) { printCommon(E, "open_existential_expr") << '\n'; @@ -2239,6 +2366,15 @@ class PrintExpr : public ExprVisitor { printRec(E->getExistentialValue()); OS << '\n'; printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *E) { + printCommon(E, "make_temporarily_escapable_expr") << '\n'; + printRec(E->getOpaqueValue()); + OS << '\n'; + printRec(E->getNonescapingClosureValue()); + OS << '\n'; + printRec(E->getSubExpr()); OS << ')'; } void visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) { @@ -2251,7 +2387,7 @@ class PrintExpr : public ExprVisitor { OS << '\n'; printRec(ExpTyR); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitObjCSelectorExpr(ObjCSelectorExpr *E) { printCommon(E, "objc_selector_expr"); @@ -2275,7 +2411,7 @@ class PrintExpr : public ExprVisitor { } OS << '\n'; printRec(E->getSubExpr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitObjCKeyPathExpr(ObjCKeyPathExpr *E) { @@ -2350,20 +2486,9 @@ class PrintTypeRepr : public TypeReprVisitor { void printRec(TypeRepr *T) { PrintTypeRepr(OS, Indent + 2).visit(T); } raw_ostream &printCommon(TypeRepr *T, const char *Name) { - OS.indent(Indent) << '('; - - // Support optional color output. - if (ShowColors) { - if (const char *CStr = - llvm::sys::Process::OutputColor(TypeReprColor, false, false)) { - OS << CStr; - } - } - - OS << Name; - - if (ShowColors) - OS.resetColor(); + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + PrintWithColorRAII(OS, TypeReprColor) << Name; return OS; } @@ -2384,12 +2509,13 @@ class PrintTypeRepr : public TypeReprVisitor { for (auto comp : T->getComponentRange()) { OS << '\n'; printCommon(nullptr, "component"); - OS << " id='" << comp->getIdentifier() << '\''; + PrintWithColorRAII(OS, IdentifierColor) + << " id='" << comp->getIdentifier() << '\''; OS << " bind="; if (comp->isBound()) comp->getBoundDecl()->dumpRef(OS); else OS << "none"; - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; if (auto GenIdT = dyn_cast(comp)) { for (auto genArg : GenIdT->getGenericArgs()) { OS << '\n'; @@ -2397,7 +2523,7 @@ class PrintTypeRepr : public TypeReprVisitor { } } } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; Indent -= 2; } @@ -2407,13 +2533,13 @@ class PrintTypeRepr : public TypeReprVisitor { if (T->throws()) OS << " throws "; OS << '\n'; printRec(T->getResultTypeRepr()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitArrayTypeRepr(ArrayTypeRepr *T) { printCommon(T, "type_array") << '\n'; printRec(T->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDictionaryTypeRepr(DictionaryTypeRepr *T) { @@ -2421,7 +2547,7 @@ class PrintTypeRepr : public TypeReprVisitor { printRec(T->getKey()); OS << '\n'; printRec(T->getValue()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitTupleTypeRepr(TupleTypeRepr *T) { @@ -2443,7 +2569,7 @@ class PrintTypeRepr : public TypeReprVisitor { OS << '\n'; printRec(elem); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitCompositionTypeRepr(CompositionTypeRepr *T) { @@ -2452,25 +2578,25 @@ class PrintTypeRepr : public TypeReprVisitor { OS << '\n'; printRec(elem); } - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitMetatypeTypeRepr(MetatypeTypeRepr *T) { printCommon(T, "type_metatype") << '\n'; printRec(T->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitProtocolTypeRepr(ProtocolTypeRepr *T) { printCommon(T, "type_protocol") << '\n'; printRec(T->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitInOutTypeRepr(InOutTypeRepr *T) { printCommon(T, "type_inout") << '\n'; printRec(T->getBase()); - OS << ')'; + PrintWithColorRAII(OS, ParenthesisColor) << ')'; } }; @@ -2517,7 +2643,8 @@ void ProtocolConformanceRef::dump(llvm::raw_ostream &out, getConcrete()->dump(out, indent); } else { out.indent(indent) << "(abstract_conformance protocol=" - << getAbstract()->getName() << ')'; + << getAbstract()->getName(); + PrintWithColorRAII(out, ParenthesisColor) << ')'; } } @@ -2537,8 +2664,10 @@ void ProtocolConformance::dump() const { void ProtocolConformance::dump(llvm::raw_ostream &out, unsigned indent) const { auto printCommon = [&](StringRef kind) { - out.indent(indent) << '(' << kind << "_conformance type=" << getType() - << " protocol=" << getProtocol()->getName(); + out.indent(indent); + PrintWithColorRAII(out, ParenthesisColor) << '('; + out << kind << "_conformance type=" << getType() + << " protocol=" << getProtocol()->getName(); }; switch (getKind()) { @@ -2568,7 +2697,7 @@ void ProtocolConformance::dump(llvm::raw_ostream &out, unsigned indent) const { } } - out << ')'; + PrintWithColorRAII(out, ParenthesisColor) << ')'; } //===----------------------------------------------------------------------===// @@ -2582,7 +2711,8 @@ namespace { raw_ostream &printCommon(const TypeBase *T, StringRef label, StringRef name) { - OS.indent(Indent) << '('; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; if (!label.empty()) { PrintWithColorRAII(OS, TypeFieldColor) << label; OS << "="; @@ -2761,6 +2891,8 @@ namespace { void visitProtocolType(ProtocolType *T, StringRef label) { printCommon(T, label, "protocol_type"); printField("decl", T->getDecl()->printRef()); + if (T->getParent()) + printRec("parent", T->getParent()); OS << ")"; } diff --git a/lib/AST/ASTNode.cpp b/lib/AST/ASTNode.cpp index 66eb7c66296c8..8033a9d6d985e 100644 --- a/lib/AST/ASTNode.cpp +++ b/lib/AST/ASTNode.cpp @@ -66,3 +66,13 @@ void ASTNode::walk(ASTWalker &Walker) { else llvm_unreachable("unsupported AST node"); } +void ASTNode::walk(SourceEntityWalker &Walker) { + if (Expr *E = this->dyn_cast()) + Walker.walk(E); + else if (Stmt *S = this->dyn_cast()) + Walker.walk(S); + else if (Decl *D = this->dyn_cast()) + Walker.walk(D); + else + llvm_unreachable("unsupported AST node"); +} diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index fc6d99be64c75..459d481ee0fe2 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -224,7 +224,7 @@ struct SynthesizedExtensionAnalyzer::Implementation { // the extension to the interface types of the base type's // declaration. TypeSubstitutionMap subMap; - if (!BaseType->isAnyExistentialType()) + if (!BaseType->isExistentialType()) subMap = BaseType->getContextSubstitutions(Ext); auto *M = DC->getParentModule(); @@ -453,7 +453,9 @@ void PrintOptions::clearSynthesizedExtension() { } TypeTransformContext::TypeTransformContext(Type T) - : BaseType(T.getPointer()) {} + : BaseType(T.getPointer()) { + assert(T->mayHaveMembers()); +} TypeTransformContext::TypeTransformContext(NominalTypeDecl *NTD) : BaseType(NTD->getDeclaredTypeInContext().getPointer()), Nominal(NTD) {} @@ -984,8 +986,9 @@ class PrintAST : public ASTVisitor { Type OldType = CurrentType; if (CurrentType && (Old != nullptr || Options.PrintAsMember)) { if (auto *NTD = dyn_cast(D)) { - CurrentType = CurrentType->getTypeOfMember( - Options.CurrentModule, NTD, nullptr); + CurrentType = NTD->getDeclaredInterfaceType().subst( + Options.CurrentModule, + CurrentType->getContextSubstitutions(NTD->getDeclContext())); } } @@ -1259,7 +1262,7 @@ void PrintAST::printSingleDepthOfGenericSignature( ModuleDecl *M = nullptr; if (CurrentType) { - if (!CurrentType->isAnyExistentialType()) { + if (!CurrentType->isExistentialType()) { auto *DC = Current->getInnermostDeclContext()->getInnermostTypeContext(); subMap = CurrentType->getContextSubstitutions(DC); M = DC->getParentModule(); diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 07c999d22b237..a1edda27673ac 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -567,6 +567,7 @@ struct ASTNodeBase {}; if (!shouldVerify(cast(expr))) return false; + assert(!OpaqueValues.count(expr->getOpaqueValue())); OpaqueValues[expr->getOpaqueValue()] = 0; assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==0); OpenedExistentialArchetypes.insert(expr->getOpenedArchetype()); @@ -574,11 +575,26 @@ struct ASTNodeBase {}; } void cleanup(OpenExistentialExpr *expr) { + assert(OpaqueValues.count(expr->getOpaqueValue())); OpaqueValues.erase(expr->getOpaqueValue()); assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==1); OpenedExistentialArchetypes.erase(expr->getOpenedArchetype()); } + bool shouldVerify(MakeTemporarilyEscapableExpr *expr) { + if (!shouldVerify(cast(expr))) + return false; + + assert(!OpaqueValues.count(expr->getOpaqueValue())); + OpaqueValues[expr->getOpaqueValue()] = 0; + return true; + } + + void cleanup(MakeTemporarilyEscapableExpr *expr) { + assert(OpaqueValues.count(expr->getOpaqueValue())); + OpaqueValues.erase(expr->getOpaqueValue()); + } + // Keep a stack of the currently-live optional evaluations. bool shouldVerify(OptionalEvaluationExpr *expr) { if (!shouldVerify(cast(expr))) @@ -665,7 +681,8 @@ struct ASTNodeBase {}; } } - if (D->getAttrs().hasAttribute()) { + if (D->didEarlyAttrValidation() && + D->getAttrs().hasAttribute()) { if (!D->isInvalid() && D->hasInterfaceType() && !isa(D->getDeclContext()) && !isa(D->getDeclContext())) { @@ -1632,6 +1649,48 @@ struct ASTNodeBase {}; } verifyCheckedBase(E); } + + void verifyChecked(MakeTemporarilyEscapableExpr *E) { + PrettyStackTraceExpr debugStack( + Ctx, "verifying MakeTemporarilyEscapableExpr", E); + + // Expression type should match subexpression. + if (!E->getType()->isEqual(E->getSubExpr()->getType())) { + Out << "MakeTemporarilyEscapableExpr type does not match subexpression"; + abort(); + } + + // Closure and opaque value should both be functions, with the closure + // noescape and the opaque value escapable but otherwise matching. + auto closureFnTy = E->getNonescapingClosureValue()->getType() + ->getAs(); + if (!closureFnTy) { + Out << "MakeTemporarilyEscapableExpr closure type is not a closure"; + abort(); + } + auto opaqueValueFnTy = E->getOpaqueValue()->getType() + ->getAs(); + if (!opaqueValueFnTy) { + Out<<"MakeTemporarilyEscapableExpr opaque value type is not a closure"; + abort(); + } + if (!closureFnTy->isNoEscape()) { + Out << "MakeTemporarilyEscapableExpr closure type should be noescape"; + abort(); + } + if (opaqueValueFnTy->isNoEscape()) { + Out << "MakeTemporarilyEscapableExpr opaque value type should be " + "escaping"; + abort(); + } + if (!closureFnTy->isEqual( + opaqueValueFnTy->withExtInfo(opaqueValueFnTy->getExtInfo() + .withNoEscape()))) { + Out << "MakeTemporarilyEscapableExpr closure and opaque value type " + "don't match"; + abort(); + } + } static bool hasEnclosingFunctionContext(DeclContext *dc) { switch (dc->getContextKind()) { @@ -2155,7 +2214,8 @@ struct ASTNodeBase {}; // If the function has a generic interface type, it should also have a // generic signature. - if (AFD->isGenericContext() != AFD->isValidGenericContext()) { + if (AFD->isGenericContext() != + (AFD->getGenericEnvironment() != nullptr)) { Out << "Functions in generic context must have a generic signature\n"; AFD->dump(Out); abort(); @@ -2279,7 +2339,7 @@ struct ASTNodeBase {}; case AccessorKind::IsDidSet: case AccessorKind::IsMaterializeForSet: if (FD->getAddressorKind() != AddressorKind::NotAddressor) { - Out << "non-addressor accessor has an addressor kind"; + Out << "non-addressor accessor has an addressor kind\n"; abort(); } break; @@ -2287,7 +2347,7 @@ struct ASTNodeBase {}; case AccessorKind::IsAddressor: case AccessorKind::IsMutableAddressor: if (FD->getAddressorKind() == AddressorKind::NotAddressor) { - Out << "addressor does not have an addressor kind"; + Out << "addressor does not have an addressor kind\n"; abort(); } break; @@ -2303,7 +2363,7 @@ struct ASTNodeBase {}; unsigned MinParamPatterns = FD->getImplicitSelfDecl() ? 2 : 1; if (FD->getParameterLists().size() < MinParamPatterns) { Out << "should have at least " << MinParamPatterns - << " parameter patterns"; + << " parameter patterns\n"; abort(); } @@ -2312,7 +2372,7 @@ struct ASTNodeBase {}; if (FD->getImplicitSelfDecl()) NumExpectedParamPatterns++; if (FD->getParameterLists().size() != NumExpectedParamPatterns) { - Out << "accessors should not be curried"; + Out << "accessors should not be curried\n"; abort(); } } @@ -2320,7 +2380,7 @@ struct ASTNodeBase {}; if (auto *VD = FD->getAccessorStorageDecl()) { if (isa(VD) && cast(VD)->isStatic() != FD->isStatic()) { - Out << "getter or setter static-ness must match static-ness of var"; + Out << "getter or setter static-ness must match static-ness of var\n"; abort(); } } @@ -2331,7 +2391,7 @@ struct ASTNodeBase {}; void verifyChecked(ClassDecl *CD) { PrettyStackTraceDecl debugStack("verifying ClassDecl", CD); - if (!CD->hasLazyMembers() && !CD->hasClangNode()) { + if (!CD->hasLazyMembers()) { unsigned NumDestructors = 0; for (auto Member : CD->getMembers()) { if (isa(Member)) { @@ -2340,15 +2400,15 @@ struct ASTNodeBase {}; } if (NumDestructors != 1) { Out << "every class should have exactly one destructor, " - "explicitly provided or created by the type checker"; - abort(); - } - - if (!CD->hasDestructor()) { - Out << "every class's 'has destructor' bit must be set"; + "explicitly provided or created by the type checker\n"; abort(); } } + + if (!CD->hasDestructor()) { + Out << "every class's 'has destructor' bit must be set\n"; + abort(); + } verifyCheckedBase(CD); } @@ -2359,7 +2419,7 @@ struct ASTNodeBase {}; auto *DC = ATD->getDeclContext(); if (!isa(DC) || !isa(cast(DC))) { - Out << "AssociatedTypeDecl should only occur inside a protocol"; + Out << "AssociatedTypeDecl should only occur inside a protocol\n"; abort(); } verifyParsedBase(ATD); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index a6bb7f909286a..8f8815c3363b2 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -848,6 +848,18 @@ class Traversal : public ASTVisitorsetSubExpr(sub); return E; } + + Expr *visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *E) { + Expr *closure = doIt(E->getNonescapingClosureValue()); + if (!closure) return nullptr; + + Expr *sub = doIt(E->getSubExpr()); + if (!sub) return nullptr; + + E->setNonescapingClosureValue(closure); + E->setSubExpr(sub); + return E; + } Expr *visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) { HANDLE_SEMANTIC_EXPR(E); diff --git a/lib/AST/ArchetypeBuilder.cpp b/lib/AST/ArchetypeBuilder.cpp index 743a53c031dcc..04a7f7164d7b3 100644 --- a/lib/AST/ArchetypeBuilder.cpp +++ b/lib/AST/ArchetypeBuilder.cpp @@ -1343,9 +1343,11 @@ bool ArchetypeBuilder::addAbstractTypeParamRequirements( // If this is an associated type that already has an archetype assigned, // use that information. - if (isa(decl) && - decl->getDeclContext()->isValidGenericContext()) { - auto *archetype = decl->getDeclContext()->mapTypeIntoContext( + auto *genericEnv = decl->getDeclContext() + ->getGenericEnvironmentOfContext(); + if (isa(decl) && genericEnv != nullptr) { + auto *archetype = genericEnv->mapTypeIntoContext( + &Mod, decl->getDeclaredInterfaceType()) ->getAs(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 191dfc112f5b4..be6b8597b9b5b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2043,11 +2043,8 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) { return interfaceType; auto *genericEnv = decl->getGenericEnvironmentOfContext(); - if (genericEnv == nullptr) - return ErrorType::get(ctx); - - return genericEnv->mapTypeIntoContext(decl->getModuleContext(), - interfaceType)->getCanonicalType(); + return GenericEnvironment::mapTypeIntoContext( + decl->getModuleContext(), genericEnv, interfaceType); } // Get the parent type. @@ -2064,13 +2061,14 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) { Ty = dc->getDeclaredInterfaceType(); break; } - if (!Ty || Ty->hasError()) - return Ty; + if (!Ty) + return Type(); + if (Ty->is()) + Ty = Type(); } - if (auto proto = dyn_cast(decl)) { - return ProtocolType::get(proto, ctx); - } else if (decl->getGenericParams()) { + if (decl->getGenericParams() && + !isa(decl)) { switch (kind) { case DeclTypeKind::DeclaredType: return UnboundGenericType::get(decl, Ty, ctx); @@ -2286,9 +2284,6 @@ UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { Type AbstractTypeParamDecl::getSuperclass() const { auto *dc = getDeclContext(); - if (!dc->isValidGenericContext()) - return nullptr; - auto contextTy = dc->mapTypeIntoContext(getDeclaredInterfaceType()); if (auto *archetype = contextTy->getAs()) return archetype->getSuperclass(); @@ -2300,9 +2295,6 @@ Type AbstractTypeParamDecl::getSuperclass() const { ArrayRef AbstractTypeParamDecl::getConformingProtocols() const { auto *dc = getDeclContext(); - if (!dc->isValidGenericContext()) - return {}; - auto contextTy = dc->mapTypeIntoContext(getDeclaredInterfaceType()); if (auto *archetype = contextTy->getAs()) return archetype->getConformsTo(); @@ -2890,16 +2882,6 @@ ProtocolDecl::findProtocolSelfReferences(const ValueDecl *value, } } -bool FuncDecl::hasArchetypeSelf() const { - if (auto proto = getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { - return proto->findProtocolSelfReferences(this, - /*allowCovariantParameters=*/true, - /*skipAssocTypes=*/true).result; - } - - return false; -} - bool ProtocolDecl::isAvailableInExistential(const ValueDecl *decl) const { // If the member type uses 'Self' in non-covariant position, // we cannot use the existential type. @@ -2992,7 +2974,7 @@ GenericParamList *ProtocolDecl::createGenericParams(DeclContext *dc) { auto selfId = ctx.Id_Self; auto selfDecl = new (ctx) GenericTypeParamDecl(dc, selfId, SourceLoc(), depth, 0); - auto protoType = ProtocolType::get(this, ctx); + auto protoType = getDeclaredType(); TypeLoc selfInherited[1] = { TypeLoc::withoutLoc(protoType) }; selfDecl->setInherited(ctx.AllocateCopy(selfInherited)); selfDecl->setImplicit(); @@ -3579,7 +3561,8 @@ SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const { if (auto *VP = dyn_cast(Pat)) Pat = VP->getSubPattern(); if (auto *TP = dyn_cast(Pat)) - return TP->getTypeLoc().getTypeRepr()->getSourceRange(); + if (auto typeRepr = TP->getTypeLoc().getTypeRepr()) + return typeRepr->getSourceRange(); return SourceRange(); } @@ -3636,10 +3619,11 @@ Pattern *VarDecl::getParentPattern() const { } bool VarDecl::isSelfParameter() const { - // Note: we need to check the isImplicit() bit here to make sure that we - // don't classify explicit parameters declared with `self` as the self param. - return isa(this) && getName() == getASTContext().Id_self && - isImplicit(); + if (isa(this)) + if (auto *AFD = dyn_cast(getDeclContext())) + return AFD->getImplicitSelfDecl() == this; + + return false; } /// Return true if this stored property needs to be accessed with getters and @@ -3793,15 +3777,8 @@ Type DeclContext::getSelfTypeInContext() const { assert(isTypeContext()); // For a protocol or extension thereof, the type is 'Self'. - if (getAsProtocolOrProtocolExtensionContext()) { - // In the parser, generic parameters won't be wired up yet, just give up on - // producing a type. - if (!isValidGenericContext()) - return Type(); - - auto *genericEnv = getGenericEnvironmentOfContext(); - return genericEnv->mapTypeIntoContext(getProtocolSelfType()); - } + if (getAsProtocolOrProtocolExtensionContext()) + return mapTypeIntoContext(getProtocolSelfType()); return getDeclaredTypeInContext(); } @@ -4004,12 +3981,7 @@ ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind( auto indexTy = getIndicesInterfaceType(); // Look through a named 1-tuple. - if (auto tupleTy = indexTy->getAs()) { - if (tupleTy->getNumElements() == 1 && - !tupleTy->getElement(0).isVararg()) { - indexTy = tupleTy->getElementType(0); - } - } + indexTy = indexTy->getWithoutImmediateLabel(); // If the index type is an integral type, we have an indexed // subscript. @@ -4204,14 +4176,19 @@ void AbstractFunctionDecl::setGenericParams(GenericParamList *GP) { /// Note that some functions don't have an implicit 'self' decl, for example, /// free functions. In this case nullptr is returned. ParamDecl *AbstractFunctionDecl::getImplicitSelfDecl() { - auto paramLists = getParameterLists(); - if (paramLists.empty()) + if (!getDeclContext()->isTypeContext()) return nullptr; // "self" is always the first parameter list. - if (paramLists[0]->size() == 1 && paramLists[0]->get(0)->isSelfParameter()) - return paramLists[0]->get(0); - return nullptr; + auto paramLists = getParameterLists(); + assert(paramLists.size() >= 1); + assert(paramLists[0]->size() == 1); + + auto selfParam = paramLists[0]->get(0); + assert(selfParam->getName() == getASTContext().Id_self); + assert(selfParam->isImplicit()); + + return selfParam; } std::pair diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index edf5a9070fd05..8ec3114aab6bb 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -127,12 +127,12 @@ enum class DeclTypeKind : unsigned { }; static Type computeExtensionType(const ExtensionDecl *ED, DeclTypeKind kind) { - if (ED->isInvalid()) - return ErrorType::get(ED->getASTContext()); - auto type = ED->getExtendedType(); - if (!type) + if (!type) { + if (ED->isInvalid()) + return ErrorType::get(ED->getASTContext()); return Type(); + } if (type->is()) { ED->getASTContext().getLazyResolver()->resolveExtension( @@ -147,8 +147,6 @@ static Type computeExtensionType(const ExtensionDecl *ED, DeclTypeKind kind) { case DeclTypeKind::DeclaredType: return type->getAnyNominal()->getDeclaredType(); case DeclTypeKind::DeclaredTypeInContext: - if (type->is()) - return Type(); return type; case DeclTypeKind::DeclaredInterfaceType: // FIXME: Need a sugar-preserving getExtendedInterfaceType for extensions @@ -231,25 +229,14 @@ GenericSignature *DeclContext::getGenericSignatureOfContext() const { // can occur in generic contexts. continue; - case DeclContextKind::AbstractFunctionDecl: { - auto *AFD = cast(dc); - if (auto genericSig = AFD->getGenericSignature()) - return genericSig; - continue; - } + case DeclContextKind::AbstractFunctionDecl: + return cast(dc)->getGenericSignature(); - case DeclContextKind::GenericTypeDecl: { - auto GTD = cast(dc); - if (auto genericSig = GTD->getGenericSignature()) - return genericSig; - continue; - } + case DeclContextKind::GenericTypeDecl: + return cast(dc)->getGenericSignature(); - case DeclContextKind::ExtensionDecl: { - auto ED = cast(dc); - // Extensions do not capture outer generic parameters. - return ED->getGenericSignature(); - } + case DeclContextKind::ExtensionDecl: + return cast(dc)->getGenericSignature(); } llvm_unreachable("bad DeclContextKind"); } @@ -271,25 +258,14 @@ GenericEnvironment *DeclContext::getGenericEnvironmentOfContext() const { // can occur in generic contexts. continue; - case DeclContextKind::AbstractFunctionDecl: { - auto *AFD = cast(dc); - if (auto genericCtx = AFD->getGenericEnvironment()) - return genericCtx; - continue; - } + case DeclContextKind::AbstractFunctionDecl: + return cast(dc)->getGenericEnvironment(); - case DeclContextKind::GenericTypeDecl: { - auto GTD = cast(dc); - if (auto genericCtx = GTD->getGenericEnvironment()) - return genericCtx; - continue; - } + case DeclContextKind::GenericTypeDecl: + return cast(dc)->getGenericEnvironment(); - case DeclContextKind::ExtensionDecl: { - auto ED = cast(dc); - // Extensions do not capture outer generic parameters. - return ED->getGenericEnvironment(); - } + case DeclContextKind::ExtensionDecl: + return cast(dc)->getGenericEnvironment(); } llvm_unreachable("bad DeclContextKind"); } @@ -482,35 +458,6 @@ bool DeclContext::isGenericContext() const { llvm_unreachable("illegal declcontext hierarchy"); } -bool DeclContext::isValidGenericContext() const { - for (const DeclContext *dc = this; ; dc = dc->getParent()) { - switch (dc->getContextKind()) { - case DeclContextKind::Module: - case DeclContextKind::FileUnit: - case DeclContextKind::TopLevelCodeDecl: - return false; - - case DeclContextKind::Initializer: - case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::SerializedLocal: - case DeclContextKind::SubscriptDecl: - // Check parent context. - continue; - - case DeclContextKind::AbstractFunctionDecl: - return cast(dc)->getGenericEnvironment(); - - case DeclContextKind::GenericTypeDecl: - return cast(dc)->getGenericEnvironment(); - - case DeclContextKind::ExtensionDecl: - return cast(dc)->getGenericEnvironment(); - } - llvm_unreachable("bad decl context kind"); - } - llvm_unreachable("illegal declcontext hierarchy"); -} - /// Get the most optimal resilience expansion for the body of this function. /// If the body is able to be inlined into functions in other resilience /// domains, this ensures that only sufficiently-conservative access patterns diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 283c6f70e93d6..459addcf8f018 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -338,6 +338,7 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind, NON_LVALUE_EXPR(DynamicType) NON_LVALUE_EXPR(RebindSelfInConstructor) NON_LVALUE_EXPR(Apply) + NON_LVALUE_EXPR(MakeTemporarilyEscapable) NON_LVALUE_EXPR(ImplicitConversion) NON_LVALUE_EXPR(ExplicitCast) NON_LVALUE_EXPR(OptionalEvaluation) @@ -450,6 +451,7 @@ ConcreteDeclRef Expr::getReferencedDecl() const { NO_REFERENCE(PostfixUnary); NO_REFERENCE(Binary); NO_REFERENCE(DotSyntaxCall); + NO_REFERENCE(MakeTemporarilyEscapable); PASS_THROUGH_REFERENCE(ConstructorRefCall, getFn); PASS_THROUGH_REFERENCE(Load, getSubExpr); @@ -718,6 +720,7 @@ bool Expr::canAppendCallParentheses() const { return true; case ExprKind::OpenExistential: + case ExprKind::MakeTemporarilyEscapable: return false; case ExprKind::Call: diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index ee210d3e0c175..677a0e3232a9a 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -351,14 +351,18 @@ getSubstitutionMap(ModuleDecl *mod, auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this), LookUpConformanceInModule(mod), SubstOptions()); - auto *archetype = contextTy->castTo(); auto sub = subs.front(); subs = subs.slice(1); // Record the replacement type and its conformances. - result.addSubstitution(CanType(archetype), sub.getReplacement()); - result.addConformances(CanType(archetype), sub.getConformances()); + if (auto *archetype = contextTy->getAs()) { + result.addSubstitution(CanType(archetype), sub.getReplacement()); + result.addConformances(CanType(archetype), sub.getConformances()); + continue; + } + + assert(contextTy->is()); } for (auto reqt : getGenericSignature()->getRequirements()) { diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index c5c998655772e..52ceb1b9476c9 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -98,9 +98,11 @@ CanGenericSignature GenericSignature::getCanonical( SmallVector canonicalRequirements; canonicalRequirements.reserve(requirements.size()); for (auto &reqt : requirements) { + auto secondTy = reqt.getSecondType(); canonicalRequirements.push_back(Requirement(reqt.getKind(), reqt.getFirstType()->getCanonicalType(), - reqt.getSecondType().getCanonicalTypeOrNull())); + secondTy ? secondTy->getCanonicalType() + : CanType())); } auto canSig = get(canonicalParams, canonicalRequirements, /*isKnownCanonical=*/true); diff --git a/lib/AST/LookupVisibleDecls.cpp b/lib/AST/LookupVisibleDecls.cpp index 524e0fd13dc46..1a0f77892fa2c 100644 --- a/lib/AST/LookupVisibleDecls.cpp +++ b/lib/AST/LookupVisibleDecls.cpp @@ -829,8 +829,9 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, // Constructors and destructors don't have 'self' in parameter patterns. if (isa(AFD) || isa(AFD)) - Consumer.foundDecl(const_cast(AFD->getImplicitSelfDecl()), - DeclVisibilityKind::FunctionParameter); + if (auto *selfParam = AFD->getImplicitSelfDecl()) + Consumer.foundDecl(const_cast(selfParam), + DeclVisibilityKind::FunctionParameter); if (AFD->getDeclContext()->isTypeContext()) { ExtendedType = AFD->getDeclContext()->getSelfTypeInContext(); diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 919d50474d940..6ec787ca97a0e 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -602,6 +602,12 @@ TypeBase::gatherAllSubstitutions(Module *module, continue; } + if (auto protocol = parent->getAs()) { + parent = protocol->getParent(); + lastGenericIndex--; + continue; + } + if (auto nominal = parent->getAs()) { parent = nominal->getParent(); continue; @@ -672,6 +678,11 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, LazyResolver *resolver) { ASTContext &ctx = getASTContext(); + // A dynamic Self type conforms to whatever its underlying type + // conforms to. + if (auto selfType = type->getAs()) + type = selfType->getSelfType(); + // An archetype conforms to a protocol if the protocol is listed in the // archetype's list of conformances, or if the archetype has a superclass // constraint and the superclass conforms to the protocol. @@ -756,11 +767,8 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, // UnresolvedType is a placeholder for an unknown type used when generating // diagnostics. We consider it to conform to all protocols, since the // intended type might have. - if (type->is()) { - return ProtocolConformanceRef( - ctx.getConformance(type, protocol, protocol->getLoc(), this, - ProtocolConformanceState::Complete)); - } + if (type->is()) + return ProtocolConformanceRef(protocol); auto nominal = type->getAnyNominal(); @@ -815,11 +823,6 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, // the specialized conformance. auto substitutions = type->gatherAllSubstitutions(this, resolver, explicitConformanceDC); - - for (auto sub : substitutions) { - if (sub.getReplacement()->hasError()) - return None; - } // Create the specialized conformance entry. auto result = ctx.getSpecializedConformance(type, conformance, diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index a4526bb50434d..97dd541ffe485 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -472,9 +472,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, } // Walk scopes outward from the innermost scope until we find something. - bool lookupInNominalIsStatic = true; ParamDecl *selfDecl = nullptr; - bool withinDefaultArgument = false; for (auto currentScope = lookupScope; currentScope; currentScope = currentScope->getParent()) { // Perform local lookup within this scope. @@ -510,8 +508,6 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, // affect lookup in an enclosing nominal type or extension thereof. if (auto *bindingInit = dyn_cast(dc)) { if (auto binding = bindingInit->getBinding()) { - lookupInNominalIsStatic = binding->isStatic(); - // Look for 'self' for a lazy variable initializer. if (auto singleVar = binding->getSingleVar()) // We only care about lazy variables. @@ -539,38 +535,17 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, // Default arguments only have 'static' access to the members of the // enclosing type, if there is one. - if (isa(dc)) { - lookupInNominalIsStatic = true; - withinDefaultArgument = true; - continue; - } + if (isa(dc)) continue; // Functions/initializers/deinitializers are only interesting insofar as // they affect lookup in an enclosing nominal type or extension thereof. - if (auto func = dyn_cast(dc)) { - // We don't update the 'static lookup' bit if we came from within a - // default argument. - if (!withinDefaultArgument) - lookupInNominalIsStatic = func->isStatic(); - withinDefaultArgument = false; - continue; - } + if (isa(dc)) continue; // Subscripts have no lookup of their own. - if (auto subscript = dyn_cast(dc)) { - // We don't update the 'static lookup' bit if we came from within a - // default argument. - if (!withinDefaultArgument) - lookupInNominalIsStatic = subscript->isStatic(); - withinDefaultArgument = false; - continue; - } + if (isa(dc)) continue; // Closures have no lookup of their own. - if (isa(dc)) { - withinDefaultArgument = false; - continue; - } + if (isa(dc)) continue; // Top-level declarations have no lookup of their own. if (isa(dc)) continue; @@ -590,6 +565,10 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); if (!nominal) continue; + // FIXME: This is overkill for name lookup. + if (TypeResolver) + TypeResolver->resolveDeclSignature(nominal); + // Dig out the type we're looking into. // FIXME: We shouldn't need to compute a type to perform this lookup. Type lookupType = dc->getSelfTypeInContext(); @@ -602,15 +581,6 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, if (!lookupType || lookupType->hasError()) continue; - // If we're performing a static lookup, use the metatype. - // FIXME: This is awful. The client should filter, not us. - if (lookupInNominalIsStatic) - lookupType = MetatypeType::get(lookupType, Ctx); - - // FIXME: This is overkill for name lookup. - if (TypeResolver) - TypeResolver->resolveDeclSignature(nominal); - // Perform lookup into the type. NLOptions options = NL_UnqualifiedDefault; if (isCascadingUse.getValue()) @@ -676,16 +646,13 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, ValueDecl *MetaBaseDecl = nullptr; GenericParamList *GenericParams = nullptr; Type ExtendedType; - bool isTypeLookup = false; // If this declcontext is an initializer for a static property, then we're // implicitly doing a static lookup into the parent declcontext. if (auto *PBI = dyn_cast(DC)) if (!DC->getParent()->isModuleScopeContext()) { - if (auto PBD = PBI->getBinding()) { - isTypeLookup = PBD->isStatic(); + if (PBI->getBinding()) DC = DC->getParent(); - } } if (auto *AFD = dyn_cast(DC)) { @@ -724,10 +691,6 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, ->getAsNominalTypeOrNominalTypeExtensionContext(); DC = DC->getParent(); - if (auto *FD = dyn_cast(AFD)) - if (FD->isStatic()) - ExtendedType = MetatypeType::get(ExtendedType); - // If we're not in the body of the function, the base declaration // is the nominal type, not 'self'. if (Loc.isValid() && @@ -781,11 +744,6 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, isCascadingUse = DC->isCascadingContextForLookup(false); } - // If this is implicitly a lookup into the static members, add a metatype - // wrapper. - if (isTypeLookup && ExtendedType) - ExtendedType = MetatypeType::get(ExtendedType, Ctx); - // Check the generic parameters for something with the given name. if (GenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); @@ -1358,17 +1316,6 @@ bool DeclContext::lookupQualified(Type type, } }; - // Look through lvalue and inout types. - type = type->getLValueOrInOutObjectType(); - - // Look through metatypes. - if (auto metaTy = type->getAs()) - type = metaTy->getInstanceType(); - - // Look through DynamicSelf. - if (auto dynamicSelf = type->getAs()) - type = dynamicSelf->getSelfType(); - // Look for module references. if (auto moduleTy = type->getAs()) { Module *module = moduleTy->getModule(); @@ -1480,6 +1427,8 @@ bool DeclContext::lookupQualified(Type type, } } } + } else { + llvm_unreachable("Bad type for qualified lookup"); } // Allow filtering of the visible declarations based on various diff --git a/lib/AST/SourceEntityWalker.cpp b/lib/AST/SourceEntityWalker.cpp index 37193d6fddd82..2b837ee3bf7aa 100644 --- a/lib/AST/SourceEntityWalker.cpp +++ b/lib/AST/SourceEntityWalker.cpp @@ -478,6 +478,16 @@ bool SourceEntityWalker::walk(Module &Mod) { return Mod.walk(Annotator); } +bool SourceEntityWalker::walk(Stmt *S) { + SemaAnnotator Annotator(*this); + return S->walk(Annotator); +} + +bool SourceEntityWalker::walk(Expr *E) { + SemaAnnotator Annotator(*this); + return E->walk(Annotator); +} + bool SourceEntityWalker::walk(Decl *D) { SemaAnnotator Annotator(*this); return D->walk(Annotator); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d5a6422a917f3..70308810637b8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -416,17 +416,45 @@ void TypeBase::getOpenedExistentials( }); } -Type TypeBase::eraseOpenedExistential(Module *module, - ArchetypeType *opened) { +Type TypeBase::eraseOpenedExistential(ArchetypeType *opened) { assert(opened->getOpenedExistentialType() && "Not an opened existential type?"); if (!hasOpenedExistential()) return Type(this); - TypeSubstitutionMap substitutions; - substitutions[opened] = opened->getOpenedExistentialType(); - return Type(this).subst(module, substitutions, None); + auto existentialType = opened->getOpenedExistentialType(); + + return Type(this).transform([&](Type t) -> Type { + // A metatype with an opened existential type becomes an + // existential metatype. + if (auto *metatypeType = dyn_cast(t.getPointer())) { + auto instanceType = metatypeType->getInstanceType(); + if (instanceType->hasOpenedExistential()) { + instanceType = instanceType->eraseOpenedExistential(opened); + return ExistentialMetatypeType::get(instanceType); + } + } + + // @opened P => P + if (auto *archetypeType = dyn_cast(t.getPointer())) { + if (archetypeType == opened) + return existentialType; + } + + return t; + }); +} + +Type TypeBase::eraseDynamicSelfType() { + if (!hasDynamicSelfType()) + return this; + + return Type(this).transform([](Type t) -> Type { + if (auto *selfTy = dyn_cast(t.getPointer())) + return selfTy->getSelfType(); + return t; + }); } void @@ -720,19 +748,25 @@ Type TypeBase::getWithoutParens() { return Ty; } +Type TypeBase::getWithoutImmediateLabel() { + Type Ty = this; + if (auto tupleTy = dyn_cast(Ty.getPointer())) { + if (tupleTy->getNumElements() == 1 && !tupleTy->getElement(0).isVararg()) + Ty = tupleTy->getElementType(0); + } + return Ty; +} + Type TypeBase::replaceCovariantResultType(Type newResultType, - unsigned uncurryLevel, - bool preserveOptionality) { + unsigned uncurryLevel) { if (uncurryLevel == 0) { - if (preserveOptionality) { - OptionalTypeKind resultOTK; - if (auto objectType = getAnyOptionalObjectType(resultOTK)) { - assert(!newResultType->getAnyOptionalObjectType()); - return OptionalType::get( - resultOTK, - objectType->replaceCovariantResultType( - newResultType, uncurryLevel, preserveOptionality)); - } + OptionalTypeKind resultOTK; + if (auto objectType = getAnyOptionalObjectType(resultOTK)) { + assert(!newResultType->getAnyOptionalObjectType()); + return OptionalType::get( + resultOTK, + objectType->replaceCovariantResultType( + newResultType, uncurryLevel)); } return newResultType; @@ -743,9 +777,8 @@ Type TypeBase::replaceCovariantResultType(Type newResultType, Type inputType = fnType->getInput(); Type resultType = fnType->getResult()->replaceCovariantResultType(newResultType, - uncurryLevel - 1, - preserveOptionality); - + uncurryLevel - 1); + // Produce the resulting function type. if (auto genericFn = dyn_cast(fnType)) { return GenericFunctionType::get(genericFn->getGenericSignature(), @@ -1106,7 +1139,8 @@ CanType TypeBase::getCanonicalType() { case TypeKind::Enum: case TypeKind::Struct: - case TypeKind::Class: { + case TypeKind::Class: + case TypeKind::Protocol: { auto nominalTy = cast(this); auto parentTy = nominalTy->getParent()->getCanonicalType(); Result = NominalType::get(nominalTy->getDecl(), parentTy, @@ -1284,6 +1318,7 @@ TypeBase *TypeBase::getDesugaredType() { case TypeKind::Enum: case TypeKind::Struct: case TypeKind::Class: + case TypeKind::Protocol: case TypeKind::GenericTypeParam: case TypeKind::DependentMember: case TypeKind::UnownedStorage: @@ -1432,6 +1467,7 @@ bool TypeBase::isSpelledLike(Type other) { case TypeKind::Enum: case TypeKind::Struct: case TypeKind::Class: + case TypeKind::Protocol: case TypeKind::NameAlias: case TypeKind::GenericTypeParam: case TypeKind::DependentMember: @@ -1555,7 +1591,8 @@ bool TypeBase::isSpelledLike(Type other) { } Type TypeBase::getSuperclass(LazyResolver *resolver) { - ClassDecl *classDecl = getClassOrBoundGenericClass(); + auto *nominalDecl = getAnyNominal(); + auto *classDecl = dyn_cast_or_null(nominalDecl); // Handle some special non-class types here. if (!classDecl) { @@ -1576,7 +1613,8 @@ Type TypeBase::getSuperclass(LazyResolver *resolver) { Type superclassTy = classDecl->getSuperclass(); // If there's no superclass, or it is fully concrete, we're done. - if (!superclassTy || !superclassTy->hasTypeParameter()) + if (!superclassTy || !superclassTy->hasTypeParameter() || + hasUnboundGenericType()) return superclassTy; // Gather substitutions from the self type, and apply them to the original @@ -2093,10 +2131,6 @@ getForeignRepresentable(Type type, ForeignLanguage language, nullptr }; } - // In Objective-C, type parameters are always objects. - if (type->isTypeParameter() && language == ForeignLanguage::ObjectiveC) - return { ForeignRepresentableKind::Object, nullptr }; - auto nominal = type->getAnyNominal(); if (!nominal) return failure(); @@ -2205,6 +2239,13 @@ getForeignRepresentable(Type type, ForeignLanguage language, if (typeArg->getAnyOptionalObjectType()) return failure(); + // A type parameter can appear here when we're looking at an + // extension of an @objc imported class. + // + // FIXME: Make this more principled. + if (typeArg->isTypeParameter()) + continue; + // And must be representable either an object or bridged. switch (typeArg->getForeignRepresentableIn(language, dc).first) { case ForeignRepresentableKind::None: @@ -3038,14 +3079,15 @@ Type Type::substDependentTypesWithErrorTypes() const { return substType(*this, [](SubstitutableType *t) -> Type { return Type(); }, MakeAbstractConformanceForGenericType(), - SubstFlags::UseErrorType); + (SubstFlags::AllowLoweredTypes | + SubstFlags::UseErrorType)); } Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass, LazyResolver *resolver) { Type t(this); while (t) { - auto *derivedClass = t->getClassOrBoundGenericClass(); + auto *derivedClass = dyn_cast_or_null(t->getAnyNominal()); assert(derivedClass && "expected a class here"); if (derivedClass == baseClass) @@ -3057,23 +3099,15 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass, } TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) { + assert(dc->isTypeContext()); + Type baseTy(this); - // Ignore lvalues in the base type. - Type baseTy(getRValueType()); - - // Look through the metatype; it has no bearing on the result. - if (auto metaBase = baseTy->getAs()) { - baseTy = metaBase->getInstanceType()->getRValueType(); - } + assert(!baseTy->isLValueType() && !baseTy->is()); // The resulting set of substitutions. Always use this to ensure we // don't miss out on NRVO anywhere. TypeSubstitutionMap substitutions; - // Look through non-type contexts. - while (!dc->isTypeContext()) - dc = dc->getParent(); - // If the member is part of a protocol or extension thereof, we need // to substitute in the type of Self. if (dc->getAsProtocolOrProtocolExtensionContext()) { @@ -3085,19 +3119,24 @@ TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) { return substitutions; } + // If we found a member of a concrete type from a protocol extension, + // get the superclass out of the archetype. + if (auto *archetypeTy = baseTy->getAs()) + baseTy = archetypeTy->getSuperclass(); + // Extract the lazy resolver. LazyResolver *resolver = dc->getASTContext().getLazyResolver(); // Find the superclass type with the context matching that of the member. // // FIXME: Do this in the caller? - if (baseTy->getAnyNominal()) { - auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); - if (auto *ownerClass = dyn_cast(ownerNominal)) - baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver); + assert(baseTy->getAnyNominal()); - assert(ownerNominal == baseTy->getAnyNominal()); - } + auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); + if (auto *ownerClass = dyn_cast(ownerNominal)) + baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver); + + assert(ownerNominal == baseTy->getAnyNominal()); // If the base type isn't specialized, there's nothing to substitute. if (!baseTy->isSpecialized()) @@ -3122,14 +3161,20 @@ TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) { continue; } + // Continue looking into the parent. + if (auto protocolTy = baseTy->getAs()) { + baseTy = protocolTy->getParent(); + curGenericParams = curGenericParams->getOuterParameters(); + continue; + } + // Continue looking into the parent. if (auto nominalTy = baseTy->getAs()) { baseTy = nominalTy->getParent(); continue; } - // We're done. - break; + llvm_unreachable("Bad base type"); } return substitutions; @@ -3140,12 +3185,9 @@ TypeSubstitutionMap TypeBase::getMemberSubstitutions(const ValueDecl *member) { TypeSubstitutionMap substitutions; - // If the member is not part of a type, there's nothing to substitute. - if (!memberDC->isTypeContext()) - return substitutions; - // Compute the set of member substitutions to apply. - substitutions = getContextSubstitutions(memberDC); + if (memberDC->isTypeContext()) + substitutions = getContextSubstitutions(memberDC); // If the member itself is generic, preserve its generic parameters. // We need this since code completion and diagnostics want to be able @@ -3174,12 +3216,7 @@ Type TypeBase::getTypeOfMember(Module *module, const ValueDecl *member, assert(memberType); - // Compute the set of member substitutions to apply. auto substitutions = getMemberSubstitutions(member); - if (substitutions.empty()) - return memberType; - - // Perform the substitutions. return memberType.subst(module, substitutions, SubstFlags::UseErrorType); } @@ -3264,7 +3301,8 @@ case TypeKind::Id: case TypeKind::Enum: case TypeKind::Struct: - case TypeKind::Class: { + case TypeKind::Class: + case TypeKind::Protocol: { auto nominalTy = cast(base); if (auto parentTy = nominalTy->getParent()) { parentTy = parentTy.transform(fn); diff --git a/lib/Basic/Demangle.cpp b/lib/Basic/Demangle.cpp index e92f7d5effcb4..e7de1579fe8fa 100644 --- a/lib/Basic/Demangle.cpp +++ b/lib/Basic/Demangle.cpp @@ -2544,6 +2544,8 @@ class NodePrinter { case Node::Kind::EmptyList: case Node::Kind::FirstElementMarker: case Node::Kind::VariadicMarker: + case Node::Kind::OutlinedCopy: + case Node::Kind::OutlinedConsume: return false; } unreachable("bad node kind"); @@ -2975,6 +2977,14 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) Printer << "curry thunk of "; print(pointer->getChild(0), asContext, suppressType); return; + case Node::Kind::OutlinedCopy: + Printer << "outlined copy of "; + print(pointer->getChild(0), asContext, suppressType); + return; + case Node::Kind::OutlinedConsume: + Printer << "outlined consume of "; + print(pointer->getChild(0), asContext, suppressType); + return; case Node::Kind::Directness: Printer << toString(Directness(pointer->getIndex())) << " "; return; diff --git a/lib/Basic/Demangler.cpp b/lib/Basic/Demangler.cpp index bc6ba760953d2..45eefa586740a 100644 --- a/lib/Basic/Demangler.cpp +++ b/lib/Basic/Demangler.cpp @@ -1320,6 +1320,14 @@ NodePointer Demangler::demangleWitness() { return createWithChildren(Node::Kind::AssociatedTypeWitnessTableAccessor, Conf, Name, ProtoTy); } + case 'y': { + return createWithChild(Node::Kind::OutlinedCopy, + popNode(Node::Kind::Type)); + } + case 'e': { + return createWithChild(Node::Kind::OutlinedConsume, + popNode(Node::Kind::Type)); + } default: return nullptr; } diff --git a/lib/Basic/Remangle.cpp b/lib/Basic/Remangle.cpp index 676ec845e20e1..65b37a11b99f3 100644 --- a/lib/Basic/Remangle.cpp +++ b/lib/Basic/Remangle.cpp @@ -1697,6 +1697,16 @@ void Remangler::mangleVariadicMarker(Node *node) { Out << ""; } +void Remangler::mangleOutlinedCopy(Node *node) { + Out << "Wy"; + mangleChildNodes(node); +} + +void Remangler::mangleOutlinedConsume(Node *node) { + Out << "We"; + mangleChildNodes(node); +} + void Remangler::mangleSILBoxTypeWithLayout(Node *node) { assert(node->getKind() == Node::Kind::SILBoxTypeWithLayout); assert(node->getNumChildren() == 1 || node->getNumChildren() == 3); diff --git a/lib/Basic/Remangler.cpp b/lib/Basic/Remangler.cpp index cbc1450669c02..88ee5d765a712 100644 --- a/lib/Basic/Remangler.cpp +++ b/lib/Basic/Remangler.cpp @@ -1626,6 +1626,16 @@ void Remangler::mangleVariadicMarker(Node *node) { Buffer << 'd'; } +void Remangler::mangleOutlinedCopy(Node *node) { + mangleSingleChildNode(node); + Buffer << "Wy"; +} + +void Remangler::mangleOutlinedConsume(Node *node) { + mangleSingleChildNode(node); + Buffer << "We"; +} + void Remangler::mangleSILBoxTypeWithLayout(Node *node) { assert(node->getNumChildren() == 1 || node->getNumChildren() == 3); assert(node->getChild(0)->getKind() == Node::Kind::SILBoxLayout); diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 59435e774450a..533da67bf1bd6 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2897,13 +2897,11 @@ namespace { ParameterList *bodyParams = nullptr; Type type = Impl.importFunctionType(dc, decl, - decl->getReturnType(), { decl->param_begin(), decl->param_size() }, decl->isVariadic(), - decl->isNoReturn(), isInSystemModule(dc), - hasCustomName, bodyParams, name); + name, bodyParams); if (!type) return nullptr; @@ -4754,8 +4752,8 @@ SwiftDeclConverter::importGlobalAsInitializer(const clang::FunctionDecl *decl, /*isInOut=*/selfIsInOut); OptionalTypeKind initOptionality; - auto resultType = Impl.importFunctionReturnType( - dc, decl, decl->getReturnType(), allowNSUIntegerAsInt); + auto resultType = Impl.importFunctionReturnType(dc, decl, + allowNSUIntegerAsInt); (void)resultType->getAnyOptionalObjectType(initOptionality); auto result = Impl.createDeclWithClangNode( @@ -4823,8 +4821,8 @@ Decl *SwiftDeclConverter::importGlobalAsMethod(const clang::FunctionDecl *decl, bodyParams.push_back(getNonSelfParamList( dc, decl, selfIdx, name.getArgumentNames(), allowNSUIntegerAsInt, !name)); - auto swiftResultTy = Impl.importFunctionReturnType( - dc, decl, decl->getReturnType(), allowNSUIntegerAsInt); + auto swiftResultTy = Impl.importFunctionReturnType(dc, decl, + allowNSUIntegerAsInt); auto fnType = ParameterList::getFullInterfaceType(swiftResultTy, bodyParams, C); diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index aceb53bb8afec..be8cf9f5293ba 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1639,7 +1639,7 @@ ImportedName NameImporter::importName(const clang::NamedDecl *decl, } ++ImportNameNumCacheMisses; auto res = importNameImpl(decl, version); - res.info.version = version; + res.setVersion(version); importNameCache[key] = res; return res; } diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h index 7ef6797445aca..e463e3ada4df9 100644 --- a/lib/ClangImporter/ImportName.h +++ b/lib/ClangImporter/ImportName.h @@ -90,8 +90,10 @@ class ImportedName { /// For an initializer, the kind of initializer to import. CtorInitializerKind initKind; - /// The version of Swift this name corresponds to - ImportNameVersion version : NumImportNameVersions; + /// The version of Swift this name corresponds to. + /// + /// \see ImportNameVersion + unsigned rawVersion : 2; /// What kind of accessor this name refers to, if any. ImportedAccessorKind accessorKind : NumImportedAccessorKindBits; @@ -114,7 +116,7 @@ class ImportedName { Info() : errorInfo(), selfIndex(), initKind(CtorInitializerKind::Designated), - version(), accessorKind(ImportedAccessorKind::None), + rawVersion(), accessorKind(ImportedAccessorKind::None), hasCustomName(false), droppedVariadic(false), importAsMember(false), hasSelfIndex(false), hasErrorInfo(false) {} } info; @@ -137,7 +139,14 @@ class ImportedName { } /// The highest version of Swift that this name comes from - ImportNameVersion getVersion() const { return info.version; } + ImportNameVersion getVersion() const { + return static_cast(info.rawVersion); + } + + void setVersion(ImportNameVersion version) { + info.rawVersion = static_cast(version); + assert(getVersion() == version && "not enough bits"); + } /// For an initializer, the kind of initializer to import. CtorInitializerKind getInitKind() const { return info.initKind; } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index a372eb8a14fcd..75c96fd6bfb8b 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1522,7 +1522,7 @@ static Type applyNoEscape(Type type) { Type ClangImporter::Implementation::importFunctionReturnType( DeclContext *dc, - const clang::FunctionDecl *clangDecl, clang::QualType resultType, + const clang::FunctionDecl *clangDecl, bool allowNSUIntegerAsInt) { // CF function results can be managed if they are audited or // the ownership convention is explicitly declared. @@ -1541,7 +1541,7 @@ Type ClangImporter::Implementation::importFunctionReturnType( } // Import the result type. - auto type = importType(resultType, + auto type = importType(clangDecl->getReturnType(), (isAuditedResult ? ImportTypeKind::AuditedResult : ImportTypeKind::Result), allowNSUIntegerAsInt, @@ -1555,17 +1555,15 @@ Type ClangImporter::Implementation::importFunctionReturnType( Type ClangImporter::Implementation:: importFunctionType(DeclContext *dc, const clang::FunctionDecl *clangDecl, - clang::QualType resultType, ArrayRef params, - bool isVariadic, bool isNoReturn, - bool isFromSystemModule, bool hasCustomName, - ParameterList *¶meterList, DeclName &name) { + bool isVariadic, bool isFromSystemModule, + DeclName name, ParameterList *¶meterList) { bool allowNSUIntegerAsInt = shouldAllowNSUIntegerAsInt(isFromSystemModule, clangDecl); auto swiftResultTy = - importFunctionReturnType(dc, clangDecl, resultType, allowNSUIntegerAsInt); + importFunctionReturnType(dc, clangDecl, allowNSUIntegerAsInt); if (!swiftResultTy) return Type(); @@ -1575,7 +1573,7 @@ importFunctionType(DeclContext *dc, if (!parameterList) return Type(); - if (isNoReturn) + if (clangDecl->isNoReturn()) swiftResultTy = SwiftContext.getNeverType(); // Form the function type. diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 6b1702ab108e7..b0ef4a6146e04 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -914,31 +914,31 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// function declaration, because it produces a function type whose input /// tuple has argument names. /// + /// \param dc The context the function is being imported into. /// \param clangDecl The underlying declaration, if any; should only be /// considered for any attributes it might carry. - /// \param resultType The result type of the function. /// \param params The parameter types to the function. /// \param isVariadic Whether the function is variadic. - /// \param isNoReturn Whether the function is noreturn. - /// \param parameterList The parameters visible inside the function body. + /// \param isFromSystemModule Whether to apply special rules that only apply + /// to system APIs. + /// \param name The name of the function. + /// \param[out] parameterList The parameters visible inside the function body. /// /// \returns the imported function type, or null if the type cannot be /// imported. Type importFunctionType(DeclContext *dc, const clang::FunctionDecl *clangDecl, - clang::QualType resultType, ArrayRef params, - bool isVariadic, bool isNoReturn, + bool isVariadic, bool isFromSystemModule, - bool hasCustomName, - ParameterList *¶meterList, - DeclName &name); + DeclName name, + ParameterList *¶meterList); /// \brief Import the given function return type. /// + /// \param dc The context the function is being imported into. /// \param clangDecl The underlying declaration, if any; should only be /// considered for any attributes it might carry. - /// \param resultType The result type of the function. /// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int /// in certain contexts. If false, it will always be imported as UInt. /// @@ -946,7 +946,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// imported. Type importFunctionReturnType(DeclContext *dc, const clang::FunctionDecl *clangDecl, - clang::QualType resultType, bool allowNSUIntegerAsInt); /// \brief Import the parameter list for a function diff --git a/lib/Frontend/AppleHostVersionDetection.h b/lib/Frontend/AppleHostVersionDetection.h new file mode 100644 index 0000000000000..8f271c22034ed --- /dev/null +++ b/lib/Frontend/AppleHostVersionDetection.h @@ -0,0 +1,31 @@ +//===--- AppleHostVersionDetection.h - NSProcessInfo interface --*- c++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_FRONTEND_APPLEHOSTVERSIONDETECTION_H +#define SWIFT_FRONTEND_APPLEHOSTVERSIONDETECTION_H + +#import "clang/Basic/VersionTuple.h" + +namespace swift { + +/// Returns a string in a form suitable for llvm::Triple's OS component +/// representing the current host OS. +/// +/// Returns an empty version if the host OS version cannot be detected. +/// +/// Note that this will load additional code into the process to detect the +/// OS version properly. +clang::VersionTuple inferAppleHostOSVersion(); + +} // end namespace swift + +#endif diff --git a/lib/Frontend/AppleHostVersionDetection.mm b/lib/Frontend/AppleHostVersionDetection.mm new file mode 100644 index 0000000000000..fd25d08647742 --- /dev/null +++ b/lib/Frontend/AppleHostVersionDetection.mm @@ -0,0 +1,81 @@ +//===--- AppleHostVersionDetection.mm - Interface to NSProcessInfo --------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "AppleHostVersionDetection.h" + +#define OBJC_OLD_DISPATCH_PROTOTYPES 0 + +#import +#include +#include +#include + +using namespace swift; + +// Note that these conditions must come in this order. TARGET_OS_MAC is set on +// nearly all Apple platforms; it's in contrast to things like TARGET_OS_WIN32. +#if TARGET_OS_IPHONE +# define REQUIRED_CF_VERSION kCFCoreFoundationVersionNumber_iOS_8_0 +#elif TARGET_OS_MAC +# define REQUIRED_CF_VERSION kCFCoreFoundationVersionNumber10_10 +#else +# error "Unknown Apple platform" +#endif + +#define DLSYM(LIBRARY, SYMBOL) \ + reinterpret_cast(dlsym(LIBRARY, #SYMBOL)) + +clang::VersionTuple swift::inferAppleHostOSVersion() { + // Simulate [[NSProcessInfo processInfo] operatingSystemVersion]. + // DYLD_PRINT_STATISTICS shows that the cost of linking Foundation when we + // don't need to is a non-trivial percentage of our pre-main startup time. + // Which, to be fair, is pretty small anyway, but even so. + + // Use RTLD_GLOBAL here, even though we don't need it, because the JIT might + // end up importing Foundation later, and at that point it /does/ need to be + // global. (This is arguably a bug in macOS's implementation of dlopen.) + auto *foundation = + dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", + RTLD_LAZY | RTLD_GLOBAL); + if (!foundation) + return {}; + + auto *cfVersionPtr = DLSYM(foundation, kCFCoreFoundationVersionNumber); + if (!cfVersionPtr || *cfVersionPtr < REQUIRED_CF_VERSION) + return {}; + + auto objcGetClass = DLSYM(foundation, objc_getClass); + if (!objcGetClass) + return {}; + + Class nsProcessInfo = objcGetClass("NSProcessInfo"); + if (!nsProcessInfo) + return {}; + + auto objcMsgSendProcessInfo = + reinterpret_cast( + DLSYM(foundation, objc_msgSend)); + NSProcessInfo *sharedProcessInfo = + objcMsgSendProcessInfo(nsProcessInfo, @selector(processInfo)); + if (!sharedProcessInfo) + return {}; + + auto objcMsgSendVersion = + reinterpret_cast( + DLSYM(foundation, objc_msgSend_stret)); + NSOperatingSystemVersion version = + objcMsgSendVersion(sharedProcessInfo, @selector(operatingSystemVersion)); + + return clang::VersionTuple(static_cast(version.majorVersion), + static_cast(version.minorVersion), + static_cast(version.patchVersion)); +} diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 9db8f2c643d23..809aba054bdd0 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -1,3 +1,9 @@ +if(APPLE) + set(AppleHostVersionDetection AppleHostVersionDetection.mm) +else() + set(AppleHostVersionDetection) +endif() + add_swift_library(swiftFrontend STATIC CompilerInvocation.cpp DiagnosticVerifier.cpp @@ -5,6 +11,7 @@ add_swift_library(swiftFrontend STATIC FrontendOptions.cpp PrintingDiagnosticConsumer.cpp SerializedDiagnosticConsumer.cpp + ${AppleHostVersionDetection} DEPENDS SwiftOptions LINK_LIBRARIES swiftSIL diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f5d9b58d3c25d..d40c2598d17bf 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -12,6 +12,10 @@ #include "swift/Frontend/Frontend.h" +#if __APPLE__ +# include "AppleHostVersionDetection.h" +#endif + #include "swift/Strings.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/Platform.h" @@ -904,6 +908,21 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Target = llvm::Triple(A->getValue()); TargetArg = A->getValue(); } +#if __APPLE__ + else if (FrontendOpts.actionIsImmediate()) { + clang::VersionTuple currentOSVersion = inferAppleHostOSVersion(); + if (currentOSVersion.getMajor() != 0) { + llvm::Triple::OSType currentOS = Target.getOS(); + if (currentOS == llvm::Triple::Darwin) + currentOS = llvm::Triple::MacOSX; + + SmallString<16> newOSBuf; + llvm::raw_svector_ostream newOS(newOSBuf); + newOS << llvm::Triple::getOSTypeName(currentOS) << currentOSVersion; + Target.setOSName(newOS.str()); + } + } +#endif Opts.EnableObjCInterop = Target.isOSDarwin(); if (auto A = Args.getLastArg(OPT_enable_objc_interop, diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index d4699f434cb60..78f391d39417e 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -914,7 +914,7 @@ static CodeCompletionResult::ExpectedTypeRelation calculateTypeRelation( Ty->getKind() == TypeKind::Error || ExpectedTy->getKind() == TypeKind::Error) return CodeCompletionResult::ExpectedTypeRelation::Unrelated; - if (Ty.getCanonicalTypeOrNull() == ExpectedTy.getCanonicalTypeOrNull()) + if (Ty->isEqual(ExpectedTy)) return CodeCompletionResult::ExpectedTypeRelation::Identical; if (isConvertibleTo(Ty, ExpectedTy, *DC)) return CodeCompletionResult::ExpectedTypeRelation::Convertible; @@ -1975,8 +1975,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Type ContextTy = VD->getDeclContext()->getDeclaredInterfaceType(); if (ContextTy) { // Look through lvalue types and metatypes - Type MaybeNominalType = (*ExprType)->getRValueType() - ->getRValueInstanceType(); + Type MaybeNominalType = (*ExprType)->getRValueType(); + + if (auto Metatype = MaybeNominalType->getAs()) + MaybeNominalType = Metatype->getInstanceType(); + + if (auto SelfType = MaybeNominalType->getAs()) + MaybeNominalType = SelfType->getSelfType(); // For optional protocol requirements and dynamic dispatch, // strip off optionality from the base type, but only if @@ -1989,6 +1994,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (MaybeNominalType->isAnyObject()) return T; + // FIXME: Sometimes ExprType is the type of the member here, + // and not the type of the base. That is inconsistent and + // should be cleaned up. + if (!MaybeNominalType->mayHaveMembers()) + return T; + // For everything else, substitute in the base type. auto Subs = MaybeNominalType->getMemberSubstitutions(VD); @@ -2865,23 +2876,24 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (auto *NTD = dyn_cast(D)) { addNominalTypeRef(NTD, Reason); - addConstructorCallsForType(NTD->getInterfaceType(), NTD->getName(), - Reason); + addConstructorCallsForType(NTD->getDeclaredInterfaceType(), + NTD->getName(), Reason); return; } if (auto *TAD = dyn_cast(D)) { addTypeAliasRef(TAD, Reason); auto type = TAD->mapTypeIntoContext(TAD->getUnderlyingTypeLoc().getType()); - addConstructorCallsForType(type, TAD->getName(), Reason); + if (type->mayHaveMembers()) + addConstructorCallsForType(type, TAD->getName(), Reason); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason); for (auto *protocol : GP->getConformingProtocols()) - addConstructorCallsForType(protocol->getInterfaceType(), GP->getName(), - Reason); + addConstructorCallsForType(protocol->getDeclaredInterfaceType(), + GP->getName(), Reason); return; } @@ -2934,23 +2946,24 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (auto *NTD = dyn_cast(D)) { addNominalTypeRef(NTD, Reason); - addConstructorCallsForType(NTD->getInterfaceType(), NTD->getName(), - Reason); + addConstructorCallsForType(NTD->getDeclaredInterfaceType(), + NTD->getName(), Reason); return; } if (auto *TAD = dyn_cast(D)) { addTypeAliasRef(TAD, Reason); auto type = TAD->mapTypeIntoContext(TAD->getDeclaredInterfaceType()); - addConstructorCallsForType(type, TAD->getName(), Reason); + if (type->mayHaveMembers()) + addConstructorCallsForType(type, TAD->getName(), Reason); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason); for (auto *protocol : GP->getConformingProtocols()) - addConstructorCallsForType(protocol->getInterfaceType(), GP->getName(), - Reason); + addConstructorCallsForType(protocol->getDeclaredInterfaceType(), + GP->getName(), Reason); return; } diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index 1585ce3cba9b1..1a137774a78d4 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -211,8 +211,14 @@ void ResolvedRangeInfo::print(llvm::raw_ostream &OS) { printContext(OS, RangeContext); OS << "\n"; - for (auto *VD : DeclaredDecls) { - OS << "" << VD->getNameStr() << "\n"; + for (auto &VD : DeclaredDecls) { + OS << "" << VD.VD->getNameStr() << ""; + OS << ""; + if (VD.ReferedAfterRange) + OS << "true"; + else + OS << "false"; + OS << "\n"; } for (auto &RD : ReferencedDecls) { OS << "" << RD.VD->getNameStr() << ""; @@ -220,9 +226,15 @@ void ResolvedRangeInfo::print(llvm::raw_ostream &OS) { RD.Ty->print(OS); OS << "\n"; } + + OS << "" << ContainedNodes.size() << "\n"; OS << "\n"; } +bool DeclaredDecl::operator==(const DeclaredDecl& Other) { + return VD == Other.VD; +} + bool ReferencedDecl::operator==(const ReferencedDecl& Other) { return VD == Other.VD && Ty.getPointer() == Other.Ty.getPointer(); } @@ -241,9 +253,14 @@ struct RangeResolver::Implementation { struct ContextInfo { ASTNode Parent; + + // Whether the context is entirely contained in the given range under + // scrutiny. + bool ContainedInRange; std::vector StartMatches; std::vector EndMatches; - ContextInfo(ASTNode Parent) : Parent(Parent) {} + ContextInfo(ASTNode Parent, bool ContainedInRange) : Parent(Parent), + ContainedInRange(ContainedInRange) {} }; SourceLoc Start; @@ -256,9 +273,12 @@ struct RangeResolver::Implementation { return ContextStack.back(); } - std::vector DeclaredDecls; + std::vector DeclaredDecls; std::vector ReferencedDecls; + // Keep track of the AST nodes contained in the range under question. + std::vector ContainedASTNodes; + /// Collect the type that an ASTNode should be evaluated to. Type resolveNodeType(ASTNode N) { if (N.is()) { @@ -275,21 +295,25 @@ struct RangeResolver::Implementation { ResolvedRangeInfo getSingleNodeKind(ASTNode Node) { assert(!Node.isNull()); + assert(ContainedASTNodes.size() == 1); if (Node.is()) return ResolvedRangeInfo(RangeKind::SingleExpression, resolveNodeType(Node), Content, getImmediateContext(), + llvm::makeArrayRef(ContainedASTNodes), llvm::makeArrayRef(DeclaredDecls), llvm::makeArrayRef(ReferencedDecls)); else if (Node.is()) return ResolvedRangeInfo(RangeKind::SingleStatement, resolveNodeType(Node), Content, getImmediateContext(), + llvm::makeArrayRef(ContainedASTNodes), llvm::makeArrayRef(DeclaredDecls), llvm::makeArrayRef(ReferencedDecls)); else { assert(Node.is()); return ResolvedRangeInfo(RangeKind::SingleDecl, Type(), Content, getImmediateContext(), + llvm::makeArrayRef(ContainedASTNodes), llvm::makeArrayRef(DeclaredDecls), llvm::makeArrayRef(ReferencedDecls)); } @@ -354,7 +378,24 @@ struct RangeResolver::Implementation { public: bool hasResult() { return Result.hasValue(); } - void enter(ASTNode Node) { ContextStack.emplace_back(Node); } + + void enter(ASTNode Node) { + bool ContainedInRange; + if (!Node.getOpaqueValue()) { + // If the node is the root, it's not contained for sure. + ContainedInRange = false; + } else if (ContextStack.back().ContainedInRange) { + // If the node's parent is contained in the range, so is the node. + ContainedInRange = true; + } else { + // If the node's parent is not contained in the range, check if this node is. + ContainedInRange = isContainedInSelection(CharSourceRange(SM, + Node.getStartLoc(), + Node.getEndLoc())); + } + ContextStack.emplace_back(Node, ContainedInRange); + } + void leave(ASTNode Node) { assert(ContextStack.back().Parent.getOpaqueValue() == Node.getOpaqueValue()); ContextStack.pop_back(); @@ -385,26 +426,84 @@ struct RangeResolver::Implementation { return createInstance(File, StartOff, EndOff - StartOff); } - void analyze(ASTNode Node) { - Decl *D = Node.is() ? Node.get() : nullptr; - + void analyzeDecl(Decl *D) { // Collect declared decls in the range. if (auto *VD = dyn_cast_or_null(D)) { if (isContainedInSelection(CharSourceRange(SM, VD->getStartLoc(), VD->getEndLoc()))) - DeclaredDecls.push_back(VD); + if(std::find(DeclaredDecls.begin(), DeclaredDecls.end(), + DeclaredDecl(VD)) == DeclaredDecls.end()) + DeclaredDecls.push_back(VD); } + } + class CompleteWalker : public SourceEntityWalker { + Implementation *Impl; + bool walkToDeclPre(Decl *D, CharSourceRange Range) override { + Impl->analyzeDecl(D); + return true; + } + bool visitDeclReference(ValueDecl *D, CharSourceRange Range, + TypeDecl *CtorTyRef, Type T, + SemaReferenceKind Kind) override { + Impl->analyzeDeclRef(D, Range, T, Kind); + return true; + } + public: + CompleteWalker(Implementation *Impl) : Impl(Impl) {} + }; + + /// This walker walk the current decl context and analyze whether declared + /// decls in the range is referenced after it. + class FurtherReferenceWalker : public SourceEntityWalker { + Implementation *Impl; + bool visitDeclReference(ValueDecl *D, CharSourceRange Range, + TypeDecl *CtorTyRef, Type T, + SemaReferenceKind Kind) override { + // If the reference is after the given range, continue logic. + if (!Impl->SM.isBeforeInBuffer(Impl->End, Range.getStart())) + return true; + + // If the referenced decl is declared in the range, than the declared decl + // is referenced out of scope/range. + auto It = std::find(Impl->DeclaredDecls.begin(), + Impl->DeclaredDecls.end(), D); + if (It != Impl->DeclaredDecls.end()) { + It->ReferedAfterRange = true; + } + return true; + } + public: + FurtherReferenceWalker(Implementation *Impl) : Impl(Impl) {} + }; + + void postAnalysis(ASTNode EndNode) { + // Visit the content of this node thoroughly, because the walker may + // abort early. + EndNode.walk(CompleteWalker(this)); + + // Analyze whether declared decls in the range is referenced outside of it. + FurtherReferenceWalker(this).walk(getImmediateContext()); + } + + void analyze(ASTNode Node) { + Decl *D = Node.is() ? Node.get() : nullptr; + analyzeDecl(D); auto &DCInfo = getCurrentDC(); switch (getRangeMatchKind(Node.getSourceRange())) { case RangeMatchKind::NoneMatch: // PatternBindingDecl is not visited; we need to explicitly analyze here. if (auto *VA = dyn_cast_or_null(D)) analyze(VA->getParentPatternBinding()); - return; - case RangeMatchKind::RangeMatch: + break; + case RangeMatchKind::RangeMatch: { + postAnalysis(Node); + + // The node is contained in the given range. + ContainedASTNodes.push_back(Node); Result = getSingleNodeKind(Node); return; + } case RangeMatchKind::StartMatch: DCInfo.StartMatches.emplace_back(Node); break; @@ -413,11 +512,25 @@ struct RangeResolver::Implementation { break; } + // If the node's parent is not contained in the range under question but the + // node itself is, we keep track of the node as top-level contained node. + if (!getCurrentDC().ContainedInRange && + isContainedInSelection(CharSourceRange(SM, Node.getStartLoc(), + Node.getEndLoc()))) { + if (std::find_if(ContainedASTNodes.begin(), ContainedASTNodes.end(), + [&](ASTNode N) { return SM.rangeContains(N.getSourceRange(), + Node.getSourceRange()); }) == ContainedASTNodes.end()) { + ContainedASTNodes.push_back(Node); + } + } + if (!DCInfo.StartMatches.empty() && !DCInfo.EndMatches.empty()) { + postAnalysis(DCInfo.EndMatches.back()); Result = {RangeKind::MultiStatement, /* Last node has the type */ resolveNodeType(DCInfo.EndMatches.back()), Content, getImmediateContext(), + llvm::makeArrayRef(ContainedASTNodes), llvm::makeArrayRef(DeclaredDecls), llvm::makeArrayRef(ReferencedDecls)}; return; diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp index aceeef5ecbc37..6a60205aac0f2 100644 --- a/lib/IDE/TypeReconstruction.cpp +++ b/lib/IDE/TypeReconstruction.cpp @@ -1195,15 +1195,15 @@ static bool CompareFunctionTypes(const AnyFunctionType *f, if (nullptr == g) return false; - auto f_input = f->getInput().getCanonicalTypeOrNull(); - auto g_input = g->getInput().getCanonicalTypeOrNull(); + auto f_input = f->getInput(); + auto g_input = g->getInput(); - auto f_output = f->getResult().getCanonicalTypeOrNull(); - auto g_output = g->getResult().getCanonicalTypeOrNull(); + auto f_output = f->getResult(); + auto g_output = g->getResult(); - if (f_input == g_input) { + if (f_input->isEqual(g_input)) { in_matches = true; - if (f_output == g_output) + if (f_output->isEqual(g_output)) out_matches = true; } diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 8a4bd11d21723..ae89e4db376d5 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -124,8 +124,6 @@ class GenClangType : public CanTypeVisitor { IRGenModule &IGM; ClangTypeConverter &Converter; - clang::QualType convertFunctionType(CanFunctionType type); - public: GenClangType(IRGenModule &IGM, ClangTypeConverter &converter) : IGM(IGM), Converter(converter) {} @@ -454,6 +452,9 @@ GenClangType::visitBoundGenericType(CanBoundGenericType type) { .Default(StructKind::Invalid); auto args = type.getGenericArgs(); + assert(args.size() == 1 && + "should have a single generic argument!"); + auto loweredArgTy = IGM.getLoweredType(args[0]).getSwiftRValueType(); switch (kind) { case StructKind::Invalid: @@ -463,28 +464,22 @@ GenClangType::visitBoundGenericType(CanBoundGenericType type) { case StructKind::UnsafeMutablePointer: case StructKind::Unmanaged: case StructKind::AutoreleasingUnsafeMutablePointer: { - assert(args.size() == 1 && - "*Pointer should have a single generic argument!"); - auto clangCanTy = Converter.convert(IGM, args.front()); + auto clangCanTy = Converter.convert(IGM, loweredArgTy); if (!clangCanTy) return clang::CanQualType(); return getClangASTContext().getPointerType(clangCanTy); } case StructKind::UnsafePointer: { - assert(args.size() == 1 && - "*Pointer should have a single generic argument!"); clang::QualType clangTy - = Converter.convert(IGM, args.front()).withConst(); + = Converter.convert(IGM, loweredArgTy).withConst(); return getCanonicalType(getClangASTContext().getPointerType(clangTy)); } case StructKind::CFunctionPointer: { auto &clangCtx = getClangASTContext(); - assert(args.size() == 1 && - "CFunctionPointer should have a single generic argument!"); clang::QualType functionTy; - if (auto ft = dyn_cast(args[0])) { - functionTy = convertFunctionType(ft); + if (isa(loweredArgTy)) { + functionTy = Converter.convert(IGM, loweredArgTy); } else { // Fall back to void(). functionTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); @@ -510,51 +505,8 @@ clang::CanQualType GenClangType::visitEnumType(CanEnumType type) { type->getDecl()->getRawType()->getCanonicalType()); } -clang::QualType GenClangType::convertFunctionType(CanFunctionType type) { - auto &clangCtx = getClangASTContext(); - SmallVector paramTypes; - CanType result = type.getResult(); - CanType input = type.getInput(); - auto resultType = Converter.convert(IGM, result); - { - if (resultType.isNull()) - goto no_clang_type; - - if (auto tuple = dyn_cast(input)) { - for (auto argType: tuple.getElementTypes()) { - auto clangType = Converter.convert(IGM, argType); - if (clangType.isNull()) - goto no_clang_type; - paramTypes.push_back(clangType); - } - } else { - auto clangType = Converter.convert(IGM, input); - if (clangType.isNull()) - goto no_clang_type; - paramTypes.push_back(clangType); - } - clang::FunctionProtoType::ExtProtoInfo DefaultEPI; - return clangCtx.getFunctionType(resultType, paramTypes, DefaultEPI); - } -no_clang_type: - // Fall back to void(^)() for block types we can't convert otherwise. As long - // as it's a pointer type it doesn't matter exactly which for either ABI type - // generation or standard Obj-C type encoding, but protocol extended method - // encodings will break. - return clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); -} - -// FIXME: We hit this building Foundation, with a call on the type -// encoding path. It seems like we shouldn't see FunctionType -// at that point. clang::CanQualType GenClangType::visitFunctionType(CanFunctionType type) { - auto &clangCtx = getClangASTContext(); - - // Convert to a Clang function type. - auto fnTy = convertFunctionType(type); - // Turn it into a block pointer. - auto blockTy = clangCtx.getBlockPointerType(fnTy); - return clangCtx.getCanonicalType(blockTy); + llvm_unreachable("FunctionType should have been lowered away"); } clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) { diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index ed0132a893114..202e1032ad562 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -117,6 +117,7 @@ #include "GenProto.h" #include "GenType.h" #include "IRGenDebugInfo.h" +#include "IRGenMangler.h" #include "IRGenModule.h" #include "LoadableTypeInfo.h" #include "NonFixedTypeInfo.h" @@ -1338,6 +1339,20 @@ namespace { llvm::Value *extraTag = ExtraTagBitCount > 0 ? src.claimNext() : nullptr; return {payload, extraTag}; } + std::pair + getPayloadAndExtraTagFromExplosionOutlined(IRGenFunction &IGF, + Explosion &src) const { + EnumPayload payload; + unsigned claimSZ = src.size(); + if (ExtraTagBitCount > 0) { + --claimSZ; + } + for (unsigned i = 0; i < claimSZ; ++i) { + payload.PayloadValues.push_back(src.claimNext()); + } + llvm::Value *extraTag = ExtraTagBitCount > 0 ? src.claimNext() : nullptr; + return {payload, extraTag}; + } std::pair emitPrimitiveLoadPayloadAndExtraTag(IRGenFunction &IGF, Address addr) const{ @@ -1385,6 +1400,27 @@ namespace { } }; + static void computePayloadTypesAndTagType( + IRGenModule &IGM, const TypeInfo &TI, + SmallVector &PayloadTypesAndTagType) { + for (auto &element : TI.getSchema()) { + auto type = element.getScalarType(); + PayloadTypesAndTagType.push_back(type); + } + } + + static llvm::Function *createOutlineLLVMFunction( + IRGenModule &IGM, std::string &name, + SmallVector &PayloadTypesAndTagType) { + auto consumeTy = llvm::FunctionType::get(IGM.VoidTy, PayloadTypesAndTagType, + /*isVarArg*/ false); + auto func = + llvm::Function::Create(consumeTy, llvm::GlobalValue::InternalLinkage, + llvm::StringRef(name), IGM.getModule()); + func->setAttributes(IGM.constructInitialAttributes()); + return func; + } + class SinglePayloadEnumImplStrategy final : public PayloadEnumImplStrategyBase { @@ -1436,6 +1472,74 @@ namespace { unsigned NumExtraInhabitantTagValues = ~0U; + llvm::Function *copyEnumFunction = nullptr; + llvm::Function *consumeEnumFunction = nullptr; + SmallVector PayloadTypesAndTagType; + + llvm::Function *emitCopyEnumFunction(IRGenModule &IGM, EnumDecl *theEnum) { + IRGenMangler Mangler; + std::string name = Mangler.mangleOutlinedCopyFunction(theEnum); + auto func = createOutlineLLVMFunction(IGM, name, PayloadTypesAndTagType); + + IRGenFunction IGF(IGM, func); + Explosion src = IGF.collectParameters(); + + EnumPayload payload; + llvm::Value *extraTag; + std::tie(payload, extraTag) = + getPayloadAndExtraTagFromExplosionOutlined(IGF, src); + llvm::BasicBlock *endBB = + testFixedEnumContainsPayload(IGF, payload, extraTag); + + if (PayloadBitCount > 0) { + ConditionalDominanceScope condition(IGF); + Explosion payloadValue; + Explosion payloadCopy; + auto &loadableTI = getLoadablePayloadTypeInfo(); + loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0); + loadableTI.copy(IGF, payloadValue, payloadCopy, Atomicity::Atomic); + payloadCopy.claimAll(); // FIXME: repack if not bit-identical + } + + IGF.Builder.CreateBr(endBB); + IGF.Builder.emitBlock(endBB); + + IGF.Builder.CreateRetVoid(); + return func; + } + + llvm::Function *emitConsumeEnumFunction(IRGenModule &IGM, + EnumDecl *theEnum) { + IRGenMangler Mangler; + std::string name = Mangler.mangleOutlinedConsumeFunction(theEnum); + auto func = createOutlineLLVMFunction(IGM, name, PayloadTypesAndTagType); + + IRGenFunction IGF(IGM, func); + Explosion src = IGF.collectParameters(); + + EnumPayload payload; + llvm::Value *extraTag; + std::tie(payload, extraTag) = + getPayloadAndExtraTagFromExplosionOutlined(IGF, src); + llvm::BasicBlock *endBB = + testFixedEnumContainsPayload(IGF, payload, extraTag); + + // If we did, consume it. + if (PayloadBitCount > 0) { + ConditionalDominanceScope condition(IGF); + Explosion payloadValue; + auto &loadableTI = getLoadablePayloadTypeInfo(); + loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0); + loadableTI.consume(IGF, payloadValue, Atomicity::Atomic); + } + + IGF.Builder.CreateBr(endBB); + IGF.Builder.emitBlock(endBB); + + IGF.Builder.CreateRetVoid(); + return func; + } + static EnumPayloadSchema getPreferredPayloadSchema(Element payloadElement) { // TODO: If the payload type info provides a preferred explosion schema, // use it. For now, just use a generic word-chunked schema. @@ -2130,6 +2234,18 @@ namespace { } } + void fillExplosionForOutlinedCall(IRGenFunction &IGF, Explosion &src, + Explosion &out) const { + assert(out.empty() && "Out explosion must be empty!"); + EnumPayload payload; + llvm::Value *extraTag; + std::tie(payload, extraTag) = + getPayloadAndExtraTagFromExplosion(IGF, src); + payload.explode(IGF.IGM, out); + if (extraTag) + out.add(extraTag); + } + public: void copy(IRGenFunction &IGF, Explosion &src, Explosion &dest, Atomicity atomicity) const override { @@ -2141,37 +2257,22 @@ namespace { return; case Normal: { - // Copy the payload, if we have it. - EnumPayload payload; llvm::Value *extraTag; - std::tie(payload, extraTag) - = getPayloadAndExtraTagFromExplosion(IGF, src); - - llvm::BasicBlock *endBB = testFixedEnumContainsPayload(IGF, payload, extraTag); - - if (PayloadBitCount > 0) { - ConditionalDominanceScope condition(IGF); - Explosion payloadValue; - Explosion payloadCopy; - auto &loadableTI = getLoadablePayloadTypeInfo(); - loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0); - loadableTI.copy(IGF, payloadValue, payloadCopy, Atomicity::Atomic); - payloadCopy.claimAll(); // FIXME: repack if not bit-identical - } - - IGF.Builder.CreateBr(endBB); - IGF.Builder.emitBlock(endBB); - + assert(copyEnumFunction && "Did not create copy function for enum"); + Explosion tmp; + fillExplosionForOutlinedCall(IGF, src, tmp); + llvm::CallInst *call = + IGF.Builder.CreateCall(copyEnumFunction, tmp.getAll()); + call->setCallingConv(IGF.IGM.DefaultCC); // Copy to the new explosion. - payload.explode(IGF.IGM, dest); - if (extraTag) dest.add(extraTag); + dest.add(tmp.claimAll()); return; } case NullableRefcounted: { // Bitcast to swift.refcounted*, and retain the pointer. llvm::Value *val = src.claimNext(); - llvm::Value *ptr = IGF.Builder.CreateBitOrPointerCast(val, - getRefcountedPtrType(IGF.IGM)); + llvm::Value *ptr = IGF.Builder.CreateBitOrPointerCast( + val, getRefcountedPtrType(IGF.IGM)); retainRefcountedPayload(IGF, ptr); dest.add(val); return; @@ -2189,38 +2290,25 @@ namespace { return; case Normal: { - // Check that we have a payload. - EnumPayload payload; llvm::Value *extraTag; - std::tie(payload, extraTag) - = getPayloadAndExtraTagFromExplosion(IGF, src); - - llvm::BasicBlock *endBB - = testFixedEnumContainsPayload(IGF, payload, extraTag); - - // If we did, consume it. - if (PayloadBitCount > 0) { - ConditionalDominanceScope condition(IGF); - Explosion payloadValue; - auto &loadableTI = getLoadablePayloadTypeInfo(); - loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0); - loadableTI.consume(IGF, payloadValue, Atomicity::Atomic); - } - - IGF.Builder.CreateBr(endBB); - IGF.Builder.emitBlock(endBB); + assert(consumeEnumFunction && + "Did not create consume function for enum"); + Explosion tmp; + fillExplosionForOutlinedCall(IGF, src, tmp); + llvm::CallInst *call = + IGF.Builder.CreateCall(consumeEnumFunction, tmp.claimAll()); + call->setCallingConv(IGF.IGM.DefaultCC); return; } case NullableRefcounted: { // Bitcast to swift.refcounted*, and hand to swift_release. llvm::Value *val = src.claimNext(); - llvm::Value *ptr = IGF.Builder.CreateBitOrPointerCast(val, - getRefcountedPtrType(IGF.IGM)); + llvm::Value *ptr = IGF.Builder.CreateBitOrPointerCast( + val, getRefcountedPtrType(IGF.IGM)); releaseRefcountedPayload(IGF, ptr); return; } } - } void fixLifetime(IRGenFunction &IGF, Explosion &src) const override { @@ -2802,6 +2890,59 @@ namespace { ReferenceCounting Refcounting; bool AllowFixedLayoutOptimizations; + llvm::Function *copyEnumFunction = nullptr; + llvm::Function *consumeEnumFunction = nullptr; + SmallVector PayloadTypesAndTagType; + + llvm::Function *emitCopyEnumFunction(IRGenModule &IGM, EnumDecl *theEnum) { + IRGenMangler Mangler; + std::string name = Mangler.mangleOutlinedCopyFunction(theEnum); + auto func = createOutlineLLVMFunction(IGM, name, PayloadTypesAndTagType); + + IRGenFunction IGF(IGM, func); + Explosion src = IGF.collectParameters(); + + auto parts = destructureAndTagLoadableEnumFromOutlined(IGF, src); + + forNontrivialPayloads(IGF, parts.tag, [&](unsigned tagIndex, + EnumImplStrategy::Element elt) { + auto <i = cast(*elt.ti); + Explosion value; + projectPayloadValue(IGF, parts.payload, tagIndex, lti, value); + + Explosion tmp; + lti.copy(IGF, value, tmp, Atomicity::Atomic); + tmp.claimAll(); // FIXME: repack if not bit-identical + }); + + IGF.Builder.CreateRetVoid(); + return func; + } + + llvm::Function *emitConsumeEnumFunction(IRGenModule &IGM, + EnumDecl *theEnum) { + IRGenMangler Mangler; + std::string name = Mangler.mangleOutlinedCopyFunction(theEnum); + auto func = createOutlineLLVMFunction(IGM, name, PayloadTypesAndTagType); + + IRGenFunction IGF(IGM, func); + Explosion src = IGF.collectParameters(); + + auto parts = destructureAndTagLoadableEnumFromOutlined(IGF, src); + + forNontrivialPayloads(IGF, parts.tag, [&](unsigned tagIndex, + EnumImplStrategy::Element elt) { + auto <i = cast(*elt.ti); + Explosion value; + projectPayloadValue(IGF, parts.payload, tagIndex, lti, value); + + lti.consume(IGF, value, Atomicity::Atomic); + }); + + IGF.Builder.CreateRetVoid(); + return func; + } + static EnumPayloadSchema getPayloadSchema(ArrayRef payloads) { // TODO: We might be able to form a nicer schema if the payload elements // share a schema. For now just use a generic schema. @@ -3066,6 +3207,22 @@ namespace { return {destructured.payload, destructured.extraTagBits, tag}; } + DestructuredAndTaggedLoadableEnum + destructureAndTagLoadableEnumFromOutlined(IRGenFunction &IGF, + Explosion &src) const { + EnumPayload payload; + unsigned claimSZ = src.size(); + if (ExtraTagBitCount > 0) { + --claimSZ; + } + for (unsigned i = 0; i < claimSZ; ++i) { + payload.PayloadValues.push_back(src.claimNext()); + } + llvm::Value *extraTagBits = + ExtraTagBitCount > 0 ? src.claimNext() : nullptr; + llvm::Value *tag = extractPayloadTag(IGF, payload, extraTagBits); + return {payload, extraTagBits, tag}; + } /// Returns a tag index in the range [0..NumElements-1]. llvm::Value * @@ -3729,7 +3886,16 @@ namespace { APInt mask = ~PayloadTagBits.asAPInt(); payload.emitApplyAndMask(IGF, mask); } - + + void fillExplosionForOutlinedCall(IRGenFunction &IGF, Explosion &src, + Explosion &out) const { + assert(out.empty() && "Out explosion must be empty!"); + auto parts = destructureAndTagLoadableEnum(IGF, src); + parts.payload.explode(IGF.IGM, out); + if (parts.extraTagBits) + out.add(parts.extraTagBits); + } + public: void emitValueInjection(IRGenFunction &IGF, EnumElementDecl *elt, @@ -3762,25 +3928,15 @@ namespace { case BitwiseTakable: case Normal: { - auto parts = destructureAndTagLoadableEnum(IGF, src); - - forNontrivialPayloads(IGF, parts.tag, - [&](unsigned tagIndex, EnumImplStrategy::Element elt) { - auto <i = cast(*elt.ti); - Explosion value; - projectPayloadValue(IGF, parts.payload, tagIndex, lti, value); - - Explosion tmp; - lti.copy(IGF, value, tmp, Atomicity::Atomic); - tmp.claimAll(); // FIXME: repack if not bit-identical - }); - - parts.payload.explode(IGF.IGM, dest); - if (parts.extraTagBits) - dest.add(parts.extraTagBits); + assert(copyEnumFunction && "Did not create copy function for enum"); + Explosion tmp; + fillExplosionForOutlinedCall(IGF, src, tmp); + llvm::CallInst *call = + IGF.Builder.CreateCall(copyEnumFunction, tmp.getAll()); + call->setCallingConv(IGF.IGM.DefaultCC); + dest.add(tmp.claimAll()); return; } - case TaggedRefcounted: { auto parts = destructureLoadableEnum(IGF, src); @@ -3791,8 +3947,8 @@ namespace { maskTagBitsFromPayload(IGF, parts.payload); // Retain the pointer. - auto ptr = parts.payload.extractValue(IGF, - getRefcountedPtrType(IGF.IGM), 0); + auto ptr = + parts.payload.extractValue(IGF, getRefcountedPtrType(IGF.IGM), 0); retainRefcountedPayload(IGF, ptr); origPayload.explode(IGF.IGM, dest); @@ -3801,13 +3957,11 @@ namespace { return; } } - } void consume(IRGenFunction &IGF, Explosion &src, Atomicity atomicity) const override { assert(TIK >= Loadable); - switch (CopyDestroyKind) { case POD: src.claim(getExplosionSize()); @@ -3815,27 +3969,23 @@ namespace { case BitwiseTakable: case Normal: { - auto parts = destructureAndTagLoadableEnum(IGF, src); - - forNontrivialPayloads(IGF, parts.tag, - [&](unsigned tagIndex, EnumImplStrategy::Element elt) { - auto <i = cast(*elt.ti); - Explosion value; - projectPayloadValue(IGF, parts.payload, tagIndex, lti, value); - - lti.consume(IGF, value, Atomicity::Atomic); - }); + assert(consumeEnumFunction && + "Did not create consume function for enum"); + Explosion tmp; + fillExplosionForOutlinedCall(IGF, src, tmp); + llvm::CallInst *call = + IGF.Builder.CreateCall(consumeEnumFunction, tmp.claimAll()); + call->setCallingConv(IGF.IGM.DefaultCC); return; } - case TaggedRefcounted: { auto parts = destructureLoadableEnum(IGF, src); // Mask the tag bits out of the payload, if any. maskTagBitsFromPayload(IGF, parts.payload); - + // Release the pointer. - auto ptr = parts.payload.extractValue(IGF, - getRefcountedPtrType(IGF.IGM), 0); + auto ptr = + parts.payload.extractValue(IGF, getRefcountedPtrType(IGF.IGM), 0); releaseRefcountedPayload(IGF, ptr); return; } @@ -5376,11 +5526,18 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout( auto alignment = payloadTI.getFixedAlignment(); applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/true, alignment); - - return getFixedEnumTypeInfo(enumTy, Size(sizeWithTag), std::move(spareBits), - alignment, - payloadTI.isPOD(ResilienceExpansion::Maximal), - payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal)); + + getFixedEnumTypeInfo( + enumTy, Size(sizeWithTag), std::move(spareBits), alignment, + payloadTI.isPOD(ResilienceExpansion::Maximal), + payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal)); + if (TIK >= Loadable && CopyDestroyKind == Normal) { + computePayloadTypesAndTagType(TC.IGM, *TI, PayloadTypesAndTagType); + copyEnumFunction = emitCopyEnumFunction(TC.IGM, theEnum); + consumeEnumFunction = emitConsumeEnumFunction(TC.IGM, theEnum); + } + + return const_cast(TI); } TypeInfo *SinglePayloadEnumImplStrategy::completeDynamicLayout( @@ -5561,8 +5718,16 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC, applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/ true, worstAlignment); - return getFixedEnumTypeInfo(enumTy, Size(sizeWithTag), std::move(spareBits), - worstAlignment, isPOD, isBT); + getFixedEnumTypeInfo(enumTy, Size(sizeWithTag), std::move(spareBits), + worstAlignment, isPOD, isBT); + if (TIK >= Loadable && + (CopyDestroyKind == Normal || CopyDestroyKind == BitwiseTakable)) { + computePayloadTypesAndTagType(TC.IGM, *TI, PayloadTypesAndTagType); + copyEnumFunction = emitCopyEnumFunction(TC.IGM, theEnum); + consumeEnumFunction = emitConsumeEnumFunction(TC.IGM, theEnum); + } + + return const_cast(TI); } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 2167dff1847b6..bf8cfa4d5c75a 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -4704,7 +4704,9 @@ namespace { CanType getParentType() const { Type type = Target->getDeclaredTypeInContext(); Type parentType = type->getNominalParent(); - return parentType.getCanonicalTypeOrNull(); + if (parentType) + return parentType->getCanonicalType(); + return CanType(); } public: diff --git a/lib/IRGen/IRBuilder.h b/lib/IRGen/IRBuilder.h index b91cf4aa6f6d8..db6c694605043 100644 --- a/lib/IRGen/IRBuilder.h +++ b/lib/IRGen/IRBuilder.h @@ -268,7 +268,8 @@ class IRBuilder : public IRBuilderBase { llvm::CallInst *CreateCall(llvm::Value *Callee, ArrayRef Args, const Twine &Name = "", llvm::MDNode *FPMathTag = nullptr) { - assert((!DebugInfo || getCurrentDebugLocation()) && "no debugloc on call"); + // assert((!DebugInfo || getCurrentDebugLocation()) && "no debugloc on + // call"); auto Call = IRBuilderBase::CreateCall(Callee, Args, Name, FPMathTag); setCallingConvUsingCallee(Call); return Call; @@ -288,7 +289,8 @@ class IRBuilder : public IRBuilderBase { ArrayRef Args, const Twine &Name = "", llvm::MDNode *FPMathTag = nullptr) { - assert((!DebugInfo || getCurrentDebugLocation()) && "no debugloc on call"); + // assert((!DebugInfo || getCurrentDebugLocation()) && "no debugloc on + // call"); auto Call = IRBuilderBase::CreateCall(Callee, Args, Name, FPMathTag); setCallingConvUsingCallee(Call); return Call; diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h index 0caeb103e87be..16d59ccda8766 100644 --- a/lib/IRGen/IRGenMangler.h +++ b/lib/IRGen/IRGenMangler.h @@ -147,6 +147,19 @@ class IRGenMangler : public NewMangling::ASTMangler { return mangleNominalTypeSymbol(Decl, "MC"); } + std::string mangleOutlinedCopyFunction(const NominalTypeDecl *Decl) { + beginMangling(); + appendNominalType(Decl); + appendOperator("Wy"); + return finalize(); + } + std::string mangleOutlinedConsumeFunction(const NominalTypeDecl *Decl) { + beginMangling(); + appendNominalType(Decl); + appendOperator("We"); + return finalize(); + } + std::string manglePartialApplyForwarder(StringRef FuncName); protected: diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp index abb57f6f5c12f..5e2c80813862c 100644 --- a/lib/Immediate/REPL.cpp +++ b/lib/Immediate/REPL.cpp @@ -13,7 +13,6 @@ #include "swift/Immediate/Immediate.h" #include "ImmediateImpl.h" -#include "swift/Config.h" #include "swift/Subsystems.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsFrontend.h" @@ -35,9 +34,11 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" -#if HAVE_UNICODE_LIBEDIT +#if defined(__APPLE__) || defined(__FreeBSD__) +// FIXME: Support REPL on non-Apple platforms. Ubuntu 14.10's editline does not +// include the wide character entry points needed by the REPL yet. #include -#endif +#endif // __APPLE__ using namespace swift; using namespace swift::immediate; @@ -130,7 +131,7 @@ class ConvertForWcharSize<4> { using Convert = ConvertForWcharSize; -#if HAVE_UNICODE_LIBEDIT +#if defined(__APPLE__) || defined(__FreeBSD__) static void convertFromUTF8(llvm::StringRef utf8, llvm::SmallVectorImpl &out) { size_t reserve = out.size() + utf8.size(); @@ -162,7 +163,7 @@ static void convertToUTF8(llvm::ArrayRef wide, } // end anonymous namespace -#if HAVE_UNICODE_LIBEDIT +#if defined(__APPLE__) || defined(__FreeBSD__) static bool appendToREPLFile(SourceFile &SF, PersistentParserState &PersistentState, @@ -1181,7 +1182,7 @@ void swift::runREPL(CompilerInstance &CI, const ProcessCmdLine &CmdLine, } while (env.handleREPLInput(inputKind, Line)); } -#else +#else // __APPLE__ void swift::runREPL(CompilerInstance &CI, const ProcessCmdLine &CmdLine, bool ParseStdlib) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 785699ea12e2a..39241d9a37d52 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -607,8 +607,10 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, StringRef alignmentText = Tok.getText(); unsigned alignmentValue; - if (alignmentText.getAsInteger(0, alignmentValue)) - llvm_unreachable("not valid integer literal token?!"); + if (alignmentText.getAsInteger(0, alignmentValue)) { + diagnose(Loc, diag::alignment_must_be_positive_integer); + return false; + } consumeToken(tok::integer_literal); @@ -3140,61 +3142,66 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param, // owner or pinned owner. } else if (Kind == AccessorKind::IsAddressor || Kind == AccessorKind::IsMutableAddressor) { - // Construct "Unsafe{,Mutable}Pointer". - - TypeRepr *args[] = { ElementTy.clone(P->Context).getTypeRepr() }; - - // FIXME: the fact that this could resolve in the local scope is dumb. - bool isMutable = (Kind == AccessorKind::IsMutableAddressor); - Identifier name = P->Context.getIdentifier( - isMutable ? "UnsafeMutablePointer" : "UnsafePointer"); - - TypeRepr *resultType = - new (P->Context) GenericIdentTypeRepr(SourceLoc(), name, - P->Context.AllocateCopy(args), - SourceRange()); - auto makeKnownType = [&](Type type) -> TypeRepr* { - return new (P->Context) FixedTypeRepr(type, SourceLoc()); - }; - auto makePairType = [&](TypeRepr *fst, TypeRepr *snd) -> TypeRepr* { - return TupleTypeRepr::create(P->Context, {fst, snd}, SourceRange()); - }; - - switch (addressorKind) { - case AddressorKind::NotAddressor: - llvm_unreachable("not an addressor!"); + // If we don't have a declared type, we will diagnose later, + // so skip this to avoid crashing. + if (ElementTy.getTypeRepr()) { + // Construct "Unsafe{,Mutable}Pointer". + + TypeRepr *args[] = { ElementTy.clone(P->Context).getTypeRepr() }; + + // FIXME: the fact that this could resolve in the local scope is dumb. + bool isMutable = (Kind == AccessorKind::IsMutableAddressor); + Identifier name = P->Context.getIdentifier( + isMutable ? "UnsafeMutablePointer" : "UnsafePointer"); + + TypeRepr *resultType = + new (P->Context) GenericIdentTypeRepr(SourceLoc(), name, + P->Context.AllocateCopy(args), + SourceRange()); + + auto makeKnownType = [&](Type type) -> TypeRepr* { + return new (P->Context) FixedTypeRepr(type, SourceLoc()); + }; + auto makePairType = [&](TypeRepr *fst, TypeRepr *snd) -> TypeRepr* { + return TupleTypeRepr::create(P->Context, {fst, snd}, SourceRange()); + }; + + switch (addressorKind) { + case AddressorKind::NotAddressor: + llvm_unreachable("not an addressor!"); + + // For unsafe addressors, that's all we've got. + case AddressorKind::Unsafe: + break; - // For unsafe addressors, that's all we've got. - case AddressorKind::Unsafe: - break; + // For non-native owning addressors, the return type is actually + // (Unsafe{,Mutable}Pointer, Builtin.UnknownObject) + case AddressorKind::Owning: + resultType = makePairType(resultType, + makeKnownType(P->Context.TheUnknownObjectType)); + break; - // For non-native owning addressors, the return type is actually - // (Unsafe{,Mutable}Pointer, Builtin.UnknownObject) - case AddressorKind::Owning: - resultType = makePairType(resultType, - makeKnownType(P->Context.TheUnknownObjectType)); - break; + // For native owning addressors, the return type is actually + // (Unsafe{,Mutable}Pointer, Builtin.NativeObject) + case AddressorKind::NativeOwning: + resultType = makePairType(resultType, + makeKnownType(P->Context.TheNativeObjectType)); + break; - // For native owning addressors, the return type is actually - // (Unsafe{,Mutable}Pointer, Builtin.NativeObject) - case AddressorKind::NativeOwning: - resultType = makePairType(resultType, - makeKnownType(P->Context.TheNativeObjectType)); - break; + // For native pinning addressors, the return type is actually + // (Unsafe{,Mutable}Pointer, Builtin.NativeObject?) + case AddressorKind::NativePinning: { + auto optNativePtr = new (P->Context) OptionalTypeRepr( + makeKnownType(P->Context.TheNativeObjectType), + SourceLoc()); + resultType = makePairType(resultType, optNativePtr); + break; + } + } - // For native pinning addressors, the return type is actually - // (Unsafe{,Mutable}Pointer, Builtin.NativeObject?) - case AddressorKind::NativePinning: { - auto optNativePtr = new (P->Context) OptionalTypeRepr( - makeKnownType(P->Context.TheNativeObjectType), - SourceLoc()); - resultType = makePairType(resultType, optNativePtr); - break; + ReturnType = resultType; } - } - - ReturnType = resultType; // Everything else returns (). } else { diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index f6da981bde7ac..f9fa2fb55a3a4 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -576,7 +576,7 @@ ParserResult Parser::parseExprKeyPath() { if (Tok.is(tok::r_paren)) rParenLoc = consumeToken(); else - rParenLoc = Tok.getLoc(); + rParenLoc = PreviousLoc; } else { parseMatchingToken(tok::r_paren, rParenLoc, diag::expr_keypath_expected_rparen, lParenLoc); @@ -654,7 +654,7 @@ ParserResult Parser::parseExprSelector() { if (subExpr.hasCodeCompletion()) return makeParserCodeCompletionResult(); - // Parse the closing ')' + // Parse the closing ')'. SourceLoc rParenLoc; if (subExpr.isParseError()) { skipUntilDeclStmtRBrace(tok::r_paren); @@ -968,6 +968,11 @@ getMagicIdentifierLiteralKind(tok Kind) { /// See if type(of: ) can be parsed backtracking on failure. static bool canParseTypeOf(Parser &P) { + // We parsed `type(of:)` as a special syntactic form in Swift 3. In Swift 4 + // it is handled by overload resolution. + if (!P.Context.LangOpts.isSwiftVersion3()) + return false; + if (!(P.Tok.getText() == "type" && P.peekToken().is(tok::l_paren))) { return false; } diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index e9268a53dfe95..65f694c248ce9 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -917,7 +917,7 @@ parseOptionalPatternTypeAnnotation(ParserResult result, // In an if-let, the actual type of the expression is Optional of whatever // was written. if (isOptional) - repr = new (Context) OptionalTypeRepr(repr, Tok.getLoc()); + repr = new (Context) OptionalTypeRepr(repr, Tok.isNot(tok::eof) ? Tok.getLoc() : PreviousLoc); return makeParserResult(new (Context) TypedPattern(P, repr)); } diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp index 9b15707106533..693147b8bd6e4 100644 --- a/lib/PrintAsObjC/PrintAsObjC.cpp +++ b/lib/PrintAsObjC/PrintAsObjC.cpp @@ -31,6 +31,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Module.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" @@ -125,6 +126,38 @@ static bool looksLikeInitMethod(ObjCSelector selector) { return !(firstPiece.size() > 4 && clang::isLowercase(firstPiece[4])); } +/// Returns the name of an type minus the leading "OS_", +/// or an empty string if \p decl is not an type. +static StringRef maybeGetOSObjectBaseName(const clang::NamedDecl *decl) { + StringRef name = decl->getName(); + if (!name.consume_front("OS_")) + return StringRef(); + + clang::SourceLocation loc = decl->getLocation(); + if (!loc.isMacroID()) + return StringRef(); + + // Hack: check to see if the name came from a macro in . + clang::SourceManager &sourceMgr = decl->getASTContext().getSourceManager(); + clang::SourceLocation expansionLoc = + sourceMgr.getImmediateExpansionRange(loc).first; + clang::SourceLocation spellingLoc = sourceMgr.getSpellingLoc(expansionLoc); + + if (!sourceMgr.getFilename(spellingLoc).endswith("/os/object.h")) + return StringRef(); + + return name; +} + +/// Returns true if \p decl represents an type. +static bool isOSObjectType(const clang::Decl *decl) { + auto *named = dyn_cast_or_null(decl); + if (!named) + return false; + return !maybeGetOSObjectBaseName(named).empty(); +} + + namespace { using DelayedMemberSet = llvm::SmallSetVector; @@ -427,7 +460,11 @@ class ObjCPrinter : private DeclVisitor, break; } } - return methodTy->getResult(); + + auto result = methodTy->getResult(); + if (result->isUninhabited()) + return M.getASTContext().TheEmptyTupleType; + return result; } void printAbstractFunctionAsMethod(AbstractFunctionDecl *AFD, @@ -551,6 +588,7 @@ class ObjCPrinter : private DeclVisitor, os << " SWIFT_METHOD_FAMILY(none)"; } if (!methodTy->getResult()->isVoid() && + !methodTy->getResult()->isUninhabited() && !AFD->getAttrs().hasAttribute()) { os << " SWIFT_WARN_UNUSED_RESULT"; } @@ -1320,18 +1358,21 @@ class ObjCPrinter : private DeclVisitor, assert(CD->isObjC()); auto clangDecl = dyn_cast_or_null(CD->getClangDecl()); if (clangDecl) { - if (isa(clangDecl)) { + // Hack for types, which use classes in Swift but + // protocols in Objective-C, and a typedef to hide the difference. + StringRef osObjectName = maybeGetOSObjectBaseName(clangDecl); + if (!osObjectName.empty()) { + os << osObjectName << "_t"; + } else if (isa(clangDecl)) { os << clangDecl->getName() << " *"; - printNullability(optionalKind); } else { maybePrintTagKeyword(CD); os << clangDecl->getName(); - printNullability(optionalKind); } } else { os << getNameForObjC(CD) << " *"; - printNullability(optionalKind); } + printNullability(optionalKind); } void visitProtocolType(ProtocolType *PT, @@ -1799,7 +1840,8 @@ class ModuleWriter { bool forwardDeclare(const ClassDecl *CD) { if (!CD->isObjC() || - CD->getForeignClassKind() == ClassDecl::ForeignKind::CFType) { + CD->getForeignClassKind() == ClassDecl::ForeignKind::CFType || + isOSObjectType(CD->getClangDecl())) { return false; } forwardDeclare(CD, [&]{ os << "@class " << getNameForObjC(CD) << ";\n"; }); diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp index 3e203d7e5f356..d2256c3020595 100644 --- a/lib/SIL/DynamicCasts.cpp +++ b/lib/SIL/DynamicCasts.cpp @@ -637,7 +637,7 @@ swift::classifyDynamicCast(Module *M, // If the bridged ObjC type is known, check if // source type can be cast into it. return classifyDynamicCast(M, source, - ObjCTy.getCanonicalTypeOrNull(), + ObjCTy->getCanonicalType(), /* isSourceTypeExact */ false, isWholeModuleOpts); } return DynamicCastFeasibility::MaySucceed; @@ -650,7 +650,7 @@ swift::classifyDynamicCast(Module *M, // If the bridged ObjC type is known, check if // this type can be cast into target type. return classifyDynamicCast(M, - ObjCTy.getCanonicalTypeOrNull(), + ObjCTy->getCanonicalType(), target, /* isSourceTypeExact */ false, isWholeModuleOpts); } diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 4c08fb2fdcbcf..2f70e077b5e2e 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -2209,6 +2209,28 @@ namespace { substObjectType)); } + /// Metatypes get DynamicSelfType stripped off the instance type. + CanType visitMetatypeType(CanMetatypeType origType) { + CanType origInstanceType = origType.getInstanceType(); + CanType substInstanceType = origInstanceType.subst( + Subst, Conformances, None)->getCanonicalType(); + + // If the substitution didn't change anything, we know that the + // original type was a lowered type, so we're good. + if (origInstanceType == substInstanceType) { + return origType; + } + + // If this is a DynamicSelf metatype, turn it into a metatype of the + // underlying self type. + if (auto dynamicSelf = dyn_cast(substInstanceType)) { + substInstanceType = dynamicSelf.getSelfType(); + } + + return CanMetatypeType::get(substInstanceType, + origType->getRepresentation()); + } + /// Any other type is would be a valid type in the AST. Just /// apply the substitution on the AST level and then lower that. CanType visitType(CanType origType) { diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index d29ccf1c7c156..59041d283be5a 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -35,9 +35,9 @@ using namespace Lowering; // \p openedArchetypes is being used as a set. We don't use a real set type here // for performance reasons. static void -collectDependentTypeInfo(CanType Ty, - SmallVectorImpl &openedArchetypes, - bool &hasDynamicSelf) { +collectDependentTypeInfo(Type Ty, + SmallVectorImpl &openedArchetypes, + bool &hasDynamicSelf) { if (!Ty) return; if (Ty->hasDynamicSelfType()) @@ -50,9 +50,10 @@ collectDependentTypeInfo(CanType Ty, // We don't use a set here, because the number of open archetypes // is usually very small and using a real set may introduce too // much overhead. + auto *archetypeTy = t->castTo(); if (std::find(openedArchetypes.begin(), openedArchetypes.end(), - t->getCanonicalType()) == openedArchetypes.end()) - openedArchetypes.push_back(t.getCanonicalTypeOrNull()); + archetypeTy) == openedArchetypes.end()) + openedArchetypes.push_back(archetypeTy); } }); } @@ -60,14 +61,13 @@ collectDependentTypeInfo(CanType Ty, // Takes a set of open archetypes as input and produces a set of // references to open archetype definitions. static void buildTypeDependentOperands( - SmallVectorImpl &OpenedArchetypes, + SmallVectorImpl &OpenedArchetypes, bool hasDynamicSelf, SmallVectorImpl &TypeDependentOperands, SILOpenedArchetypesState &OpenedArchetypesState, SILFunction &F) { for (auto archetype : OpenedArchetypes) { - auto Def = OpenedArchetypesState.getOpenedArchetypeDef( - F.getModule().Types.getLoweredType(archetype).getSwiftRValueType()); + auto Def = OpenedArchetypesState.getOpenedArchetypeDef(archetype); assert(Def); assert(getOpenedArchetypeOf(Def->getType().getSwiftRValueType()) && "Opened archetype operands should be of an opened existential type"); @@ -87,18 +87,18 @@ static void collectTypeDependentOperands( SmallVectorImpl &TypeDependentOperands, SILOpenedArchetypesState &OpenedArchetypesState, SILFunction &F, - CanType Ty, + Type Ty, ArrayRef subs = ArrayRef()) { - SmallVector openedArchetypes; + SmallVector openedArchetypes; bool hasDynamicSelf = false; collectDependentTypeInfo(Ty, openedArchetypes, hasDynamicSelf); for (auto sub : subs) { - auto ReplTy = sub.getReplacement().getCanonicalTypeOrNull(); + auto ReplTy = sub.getReplacement(); collectDependentTypeInfo(ReplTy, openedArchetypes, hasDynamicSelf); } buildTypeDependentOperands(openedArchetypes, hasDynamicSelf, - TypeDependentOperands, - OpenedArchetypesState, F); + TypeDependentOperands, + OpenedArchetypesState, F); } //===----------------------------------------------------------------------===// diff --git a/lib/SIL/SILOpenedArchetypesTracker.cpp b/lib/SIL/SILOpenedArchetypesTracker.cpp index d33c4d0aa122f..800716b4ff862 100644 --- a/lib/SIL/SILOpenedArchetypesTracker.cpp +++ b/lib/SIL/SILOpenedArchetypesTracker.cpp @@ -14,10 +14,8 @@ using namespace swift; -void SILOpenedArchetypesTracker::addOpenedArchetypeDef(Type archetype, +void SILOpenedArchetypesTracker::addOpenedArchetypeDef(ArchetypeType *archetype, SILValue Def) { - archetype = archetype->getDesugaredType(); - assert(archetype->is() && "The type should be an archetype"); auto OldDef = getOpenedArchetypeDef(archetype); if (OldDef && isa(OldDef)) { // It is a forward definition created during deserialization. @@ -52,19 +50,19 @@ void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(Type Ty) { if (!ty->isOpenedExistential()) return; - ty = ty->getDesugaredType(); - + auto *archetypeTy = ty->castTo(); // Nothing to do if a definition was seen already. - if (getOpenedArchetypeDef(ty)) + if (getOpenedArchetypeDef(archetypeTy)) return; auto &SILMod = this->getFunction().getModule(); // Create a placeholder representing a forward definition. auto Placeholder = new (SILMod) - GlobalAddrInst(SILDebugLocation(), SILMod.Types.getLoweredType(ty)); + GlobalAddrInst(SILDebugLocation(), + SILMod.Types.getLoweredType(archetypeTy)); // Make it available to SILBuilder, so that instructions using this // archetype can be constructed. - addOpenedArchetypeDef(ty, Placeholder); + addOpenedArchetypeDef(archetypeTy, Placeholder); }); } @@ -115,26 +113,28 @@ void SILOpenedArchetypesTracker::handleDeleteNotification( /// Find an opened archetype defined by an instruction. /// \returns The found archetype or empty type otherwise. -CanType swift::getOpenedArchetypeOf(const SILInstruction *I) { +ArchetypeType *swift::getOpenedArchetypeOf(const SILInstruction *I) { if (isa(I) || isa(I) || isa(I) || isa(I)) { auto Ty = getOpenedArchetypeOf(I->getType().getSwiftRValueType()); assert(Ty->isOpenedExistential() && "Type should be an opened archetype"); - return Ty; + return Ty->castTo(); } - return CanType(); + return nullptr; } -bool hasAtMostOneOpenedArchetype(CanType Ty) { +bool hasAtMostOneOpenedArchetype(Type Ty) { + if (!Ty->hasOpenedExistential()) + return true; + int NumOpenedArchetypes = 0; Ty.visit([&](Type t) { - if (t->isOpenedExistential()) { + if (t->isOpenedExistential()) NumOpenedArchetypes++; - } - return; }); + return NumOpenedArchetypes <= 1; } @@ -146,31 +146,28 @@ bool hasAtMostOneOpenedArchetype(CanType Ty) { /// recursively check any children of this type, because /// this is the task of the type visitor invoking it. /// \returns The found archetype or empty type otherwise. -CanType swift::getOpenedArchetypeOf(CanType Ty) { +ArchetypeType *swift::getOpenedArchetypeOf(Type Ty) { if (!Ty) - return CanType(); - assert(hasAtMostOneOpenedArchetype(Ty) && - "Type should contain at most one opened archetype"); - while (auto MetaTy = dyn_cast(Ty)) { - Ty = MetaTy->getInstanceType().getCanonicalTypeOrNull(); - } + return nullptr; + while (auto MetaTy = Ty->getAs()) + Ty = MetaTy->getInstanceType(); if (Ty->isOpenedExistential()) - return Ty; - return CanType(); + return Ty->castTo(); + return nullptr; } -SILValue SILOpenedArchetypesState::getOpenedArchetypeDef(Type Ty) const { - if (!Ty) +SILValue SILOpenedArchetypesState::getOpenedArchetypeDef( + ArchetypeType *archetypeTy) const { + if (!archetypeTy) return SILValue(); - auto CanTy = Ty.getCanonicalTypeOrNull(); // First perform a quick check. for (auto &Op : OpenedArchetypeOperands) { auto Def = Op.get(); - if (getOpenedArchetypeOf(cast(Def)) == CanTy) + if (getOpenedArchetypeOf(cast(Def)) == archetypeTy) return Def; } // Then use a regular lookup. if (OpenedArchetypesTracker) - return OpenedArchetypesTracker->getOpenedArchetypeDef(Ty); + return OpenedArchetypesTracker->getOpenedArchetypeDef(archetypeTy); return SILValue(); } diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 92d21bf6bf734..91723c1452a0a 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -642,7 +642,7 @@ class SILVerifier : public SILVerifierBase { require(isArchetypeValidInFunction(A, F), "Operand is of an ArchetypeType that does not exist in the " "Caller's generic param list."); - if (auto OpenedA = getOpenedArchetype(t.getCanonicalTypeOrNull())) { + if (auto OpenedA = getOpenedArchetypeOf(CanType(A))) { auto Def = OpenedArchetypes.getOpenedArchetypeDef(OpenedA); require (Def, "Opened archetype should be registered in SILFunction"); require(I == nullptr || Def == I || @@ -767,7 +767,7 @@ class SILVerifier : public SILVerifierBase { void checkApplyTypeDependentArguments(ApplySite AS) { SILInstruction *AI = AS.getInstruction(); - llvm::DenseSet FoundOpenedArchetypes; + llvm::DenseSet FoundOpenedArchetypes; unsigned hasDynamicSelf = 0; // Function to collect opened archetypes in FoundOpenedArchetypes and set @@ -778,11 +778,11 @@ class SILVerifier : public SILVerifierBase { require(isArchetypeValidInFunction(A, AI->getFunction()), "Archetype to be substituted must be valid in function."); // Collect all opened archetypes used in the substitutions list. - FoundOpenedArchetypes.insert(Ty.getCanonicalTypeOrNull()); + FoundOpenedArchetypes.insert(A); // Also check that they are properly tracked inside the current // function. auto Def = - OpenedArchetypes.getOpenedArchetypeDef(Ty.getCanonicalTypeOrNull()); + OpenedArchetypes.getOpenedArchetypeDef(A); require(Def, "Opened archetype should be registered in SILFunction"); require(Def == AI || Dominance->properlyDominates(cast(Def), AI), @@ -1949,7 +1949,7 @@ class SILVerifier : public SILVerifierBase { "method's Self parameter should be constrained by protocol"); auto lookupType = AMI->getLookupType(); - if (getOpenedArchetype(lookupType)) { + if (getOpenedArchetypeOf(lookupType)) { require(AMI->getTypeDependentOperands().size() == 1, "Must have a type dependent operand for the opened archetype"); verifyOpenedArchetype(AMI, lookupType); @@ -1971,10 +1971,6 @@ class SILVerifier : public SILVerifierBase { } } - CanType getOpenedArchetype(CanType t) { - return getOpenedArchetypeOf(t); - } - // Get the expected type of a dynamic method reference. SILType getDynamicMethodType(SILType selfType, SILDeclRef method) { auto &C = F.getASTContext(); @@ -2120,7 +2116,7 @@ class SILVerifier : public SILVerifierBase { require(OEI->getType().isAddress(), "open_existential_addr result must be an address"); - auto archetype = getOpenedArchetype(OEI->getType().getSwiftRValueType()); + auto archetype = getOpenedArchetypeOf(OEI->getType().getSwiftRValueType()); require(archetype, "open_existential_addr result must be an opened existential archetype"); require(OpenedArchetypes.getOpenedArchetypeDef(archetype) == OEI, @@ -2142,7 +2138,7 @@ class SILVerifier : public SILVerifierBase { require(OEI->getType().isObject(), "open_existential_ref result must be an address"); - auto archetype = getOpenedArchetype(resultInstanceTy); + auto archetype = getOpenedArchetypeOf(resultInstanceTy); require(archetype, "open_existential_ref result must be an opened existential archetype"); require(OpenedArchetypes.getOpenedArchetypeDef(archetype) == OEI, @@ -2164,7 +2160,7 @@ class SILVerifier : public SILVerifierBase { require(OEI->getType().isAddress(), "open_existential_box result must be an address"); - auto archetype = getOpenedArchetype(resultInstanceTy); + auto archetype = getOpenedArchetypeOf(resultInstanceTy); require(archetype, "open_existential_box result must be an opened existential archetype"); require(OpenedArchetypes.getOpenedArchetypeDef(archetype) == OEI, @@ -2209,7 +2205,7 @@ class SILVerifier : public SILVerifierBase { require(operandInstTy.isExistentialType(), "ill-formed existential metatype in open_existential_metatype " "operand"); - auto archetype = getOpenedArchetype(resultInstTy); + auto archetype = getOpenedArchetypeOf(resultInstTy); require(archetype, "open_existential_metatype result must be an opened " "existential metatype"); require( @@ -2426,7 +2422,8 @@ class SILVerifier : public SILVerifierBase { Ty.visit([&](Type t) { SILValue Def; if (t->isOpenedExistential()) { - Def = OpenedArchetypes.getOpenedArchetypeDef(t); + auto *archetypeTy = t->castTo(); + Def = OpenedArchetypes.getOpenedArchetypeDef(archetypeTy); require(Def, "Opened archetype should be registered in SILFunction"); } else if (t->hasDynamicSelfType()) { require(I->getFunction()->hasSelfParam(), @@ -3449,7 +3446,7 @@ class SILVerifier : public SILVerifierBase { // OpenedArchetypesDefs are existing instructions // belonging to the function F. for (auto KV: OpenedArchetypes.getOpenedArchetypeDefs()) { - require(getOpenedArchetype(KV.first.getCanonicalTypeOrNull()), + require(getOpenedArchetypeOf(KV.first), "Only opened archetypes should be registered in SILFunction"); auto Def = cast(KV.second); require(Def->getFunction() == F, diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 699fe2a4b3bc9..62c34daf2e7ab 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1235,30 +1235,6 @@ void TypeConverter::insert(TypeKey k, const TypeLowering *tl) { Types[k.getCachingKey()] = tl; } -#ifndef NDEBUG -/// Is this type a lowered type? -static bool isLoweredType(CanType type) { - if (isa(type) || isa(type)) - return false; - if (isa(type)) - return false; - if (auto tuple = dyn_cast(type)) { - for (auto elt : tuple.getElementTypes()) - if (!isLoweredType(elt)) - return false; - return true; - } - OptionalTypeKind optKind; - if (auto objectType = type.getAnyOptionalObjectType(optKind)) { - return (optKind == OTK_Optional && isLoweredType(objectType)); - } - if (auto meta = dyn_cast(type)) { - return meta->hasRepresentation(); - } - return true; -} -#endif - /// Lower each of the elements of the substituted type according to /// the abstraction pattern of the given original type. static CanTupleType getLoweredTupleType(TypeConverter &tc, @@ -1525,7 +1501,7 @@ const TypeLowering &TypeConverter::getTypeLowering(SILType type) { const TypeLowering & TypeConverter::getTypeLoweringForLoweredType(TypeKey key) { auto type = key.SubstType; - assert(isLoweredType(type) && "type is not lowered!"); + assert(type->isLegalSILType() && "type is not lowered!"); (void)type; // Re-using uncurry level 0 is reasonable because our uncurrying @@ -1542,7 +1518,7 @@ TypeConverter::getTypeLoweringForLoweredType(TypeKey key) { const TypeLowering & TypeConverter::getTypeLoweringForUncachedLoweredType(TypeKey key) { assert(!find(key) && "re-entrant or already cached"); - assert(isLoweredType(key.SubstType) && "type is not already lowered"); + assert(key.SubstType->isLegalSILType() && "type is not already lowered"); #ifndef NDEBUG // Catch reentrancy bugs. @@ -1765,22 +1741,6 @@ TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, return CanFunctionType::get(Context.TheEmptyTupleType, funcType, extInfo); } -/// Replace any DynamicSelf types with their underlying Self type. -static Type replaceDynamicSelfWithSelf(Type t) { - return t.transform([](Type type) -> Type { - if (auto dynamicSelf = type->getAs()) - return dynamicSelf->getSelfType(); - return type; - }); -} - -/// Replace any DynamicSelf types with their underlying Self type. -static CanType replaceDynamicSelfWithSelf(CanType t) { - if (!t->hasDynamicSelfType()) - return t; - return replaceDynamicSelfWithSelf(Type(t))->getCanonicalType(); -} - CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { ValueDecl *vd = c.loc.dyn_cast(); @@ -1797,8 +1757,7 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { FuncDecl *func = cast(vd); auto funcTy = cast( - func->getInterfaceType()->getCanonicalType()); - funcTy = cast(replaceDynamicSelfWithSelf(funcTy)); + func->getInterfaceType()->eraseDynamicSelfType()->getCanonicalType()); return getFunctionInterfaceTypeWithCaptures(funcTy, func); } diff --git a/lib/SILGen/ArgumentSource.cpp b/lib/SILGen/ArgumentSource.cpp index 954ab625dbeae..3e662adb13351 100644 --- a/lib/SILGen/ArgumentSource.cpp +++ b/lib/SILGen/ArgumentSource.cpp @@ -55,7 +55,35 @@ bool ArgumentSource::requiresCalleeToEvaluate() { case Kind::LValue: return false; case Kind::Expr: - return isa(asKnownExpr()); + // FIXME: TupleShuffleExprs come in two flavors: + // + // 1) as apply arguments, where they're used to insert default + // argument value and collect varargs + // + // 2) as tuple conversions, where they can introduce, eliminate + // and re-order fields + // + // Case 1) must be emitted by ArgEmitter, and Case 2) must be + // emitted by RValueEmitter. + // + // It would be good to split up TupleShuffleExpr into these two + // cases, and simplify ArgEmitter since it no longer has to deal + // with re-ordering. However for now, SubscriptExpr emits the + // index argument via the RValueEmitter, so the RValueEmitter has + // to know about varargs, duplicating some of the logic in + // ArgEmitter. + // + // Once this is fixed, we can also consider allowing subscripts + // to have default arguments. + if (auto *shuffleExpr = dyn_cast(asKnownExpr())) { + for (auto index : shuffleExpr->getElementMapping()) { + if (index == TupleShuffleExpr::DefaultInitialize || + index == TupleShuffleExpr::CallerDefaultInitialize || + index == TupleShuffleExpr::Variadic) + return true; + } + } + return false; } llvm_unreachable("Unhandled Kind in switch."); diff --git a/lib/SILGen/ManagedValue.h b/lib/SILGen/ManagedValue.h index e758599aae2d8..a06fa81e81b4f 100644 --- a/lib/SILGen/ManagedValue.h +++ b/lib/SILGen/ManagedValue.h @@ -26,6 +26,7 @@ #include "swift/SIL/SILValue.h" namespace swift { + enum class CastConsumptionKind : unsigned char; namespace Lowering { @@ -44,8 +45,9 @@ namespace Lowering { /// this represents a value that was emitted directly into an /// initialization stored by an SGFContext. /// -/// The RValue cases may or may not have a cleanup associated with the value. -/// A cleanup is associated with +1 values of non-trivial type. +/// The RValue cases may or may not have a cleanup associated with the value. A +/// cleanup is associated with +1 values of non-trivial type and +0 values of +/// non-trivial type. /// class ManagedValue { /// The value (or address of an address-only value) being managed, and @@ -76,6 +78,7 @@ class ManagedValue { assert(value && "No value specified"); return ManagedValue(value, false, CleanupHandle::invalid()); } + /// Create a managed value for an l-value. static ManagedValue forLValue(SILValue value) { assert(value && "No value specified"); diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 1b2de18c8393f..646d3aa065dcc 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1408,6 +1408,9 @@ void SILGenModule::emitSourceFile(SourceFile *sf, unsigned startElem) { for (Decl *D : llvm::makeArrayRef(sf->Decls).slice(startElem)) visit(D); + for (Decl *D : sf->LocalTypeDecls) + visit(D); + // Mark any conformances as "used". for (auto conformance : sf->getUsedConformances()) useConformance(ProtocolConformanceRef(conformance)); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 42a06719b5a1a..c1614e4861295 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -558,14 +558,14 @@ class Callee { assert(level <= Constant.uncurryLevel && "uncurrying past natural uncurry level of method"); - auto constant = Constant.atUncurryLevel(level); + constant = Constant.atUncurryLevel(level); // Lower the substituted type from the AST, which should have any generic // parameters in the original signature erased to their upper bounds. auto objcFormalType = SubstFormalType.withExtInfo( SubstFormalType->getExtInfo() .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod)); auto fnType = gen.SGM.M.Types - .getUncachedSILFunctionTypeForConstant(constant, objcFormalType); + .getUncachedSILFunctionTypeForConstant(*constant, objcFormalType); auto closureType = replaceSelfTypeForDynamicLookup(gen.getASTContext(), fnType, @@ -574,9 +574,9 @@ class Callee { SILValue fn = gen.B.createDynamicMethod(Loc, SelfValue, - constant, + *constant, SILType::getPrimitiveObjectType(closureType), - /*volatile*/ constant.isForeign); + /*volatile*/ Constant.isForeign); mv = ManagedValue::forUnmanaged(fn); break; } @@ -1104,11 +1104,9 @@ class SILGenApply : public Lowering::ExprVisitor { } } - // If this is a direct reference to a vardecl, it must be a let constant - // (which doesn't need to be loaded). Just emit its value directly. - if (auto *vd = dyn_cast(e->getDecl())) { - (void)vd; - assert(vd->isLet() && "Direct reference to vardecl that isn't a let?"); + // If this is a direct reference to a vardecl, just emit its value directly. + // Recursive references to callable declarations are allowed. + if (isa(e->getDecl())) { visitExpr(e); return; } @@ -4696,15 +4694,16 @@ static RValue emitApplyAllocatingInitializer(SILGenFunction &SGF, { // Determine the self metatype type. CanSILFunctionType substFnType = - SGF.getLoweredType(substFormalType, /*uncurryLevel=*/1) - .castTo(); + initConstant.SILFnType->substGenericArgs(SGF.SGM.M, subs); SILType selfParamMetaTy = substFnType->getSelfParameter().getSILType(); if (overriddenSelfType) { // If the 'self' type has been overridden, form a metatype to the // overriding 'Self' type. Type overriddenSelfMetaType = - MetatypeType::get(overriddenSelfType, SGF.getASTContext()); + MetatypeType::get(overriddenSelfType, + selfParamMetaTy.castTo() + ->getRepresentation()); selfMetaTy = SGF.getLoweredType(overriddenSelfMetaType->getCanonicalType()); } else { diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 4863c7b972e7a..e4e0604c5d86a 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -650,16 +650,14 @@ SILGenFunction::emitBlockToFunc(SILLocation loc, ManagedValue block, CanSILFunctionType funcTy) { CanSILFunctionType substFnTy; - SmallVector subs; - - auto genericEnv = F.getGenericEnvironment(); // Declare the thunk. auto blockTy = block.getType().castTo(); - auto thunkTy = buildThunkType(block, funcTy, substFnTy, subs); - if (!thunkTy->isPolymorphic()) - genericEnv = nullptr; + SubstitutionMap contextSubs, interfaceSubs; + GenericEnvironment *genericEnv = nullptr; + auto thunkTy = buildThunkType(block, funcTy, substFnTy, genericEnv, + contextSubs, interfaceSubs); auto thunk = SGM.getOrCreateReabstractionThunk(genericEnv, thunkTy, @@ -675,6 +673,10 @@ SILGenFunction::emitBlockToFunc(SILLocation loc, buildBlockToFuncThunkBody(thunkSGF, loc, blockTy, funcTy); } + SmallVector subs; + if (auto genericSig = thunkTy->getGenericSignature()) + genericSig->getSubstitutions(interfaceSubs, subs); + // Create it in the current function. auto thunkValue = B.createFunctionRef(loc, thunk); auto thunkedFn = B.createPartialApply(loc, thunkValue, diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 9ad9f62418fb2..1f8b34f0fc8c0 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -201,6 +201,21 @@ void TemporaryInitialization::finishInitialization(SILGenFunction &gen) { gen.Cleanups.setCleanupState(Cleanup, CleanupState::Active); } +namespace { +class EndBorrowCleanup : public Cleanup { + SILValue borrowee; + SILValue borrowed; + +public: + EndBorrowCleanup(SILValue borrowee, SILValue borrowed) + : borrowee(borrowee), borrowed(borrowed) {} + + void emit(SILGenFunction &gen, CleanupLocation l) override { + gen.B.createEndBorrow(l, borrowee, borrowed); + } +}; +} // end anonymous namespace + namespace { class ReleaseValueCleanup : public Cleanup { SILValue v; @@ -1144,6 +1159,12 @@ CleanupHandle SILGenFunction::enterDestroyCleanup(SILValue valueOrAddr) { return Cleanups.getTopCleanup(); } +CleanupHandle SILGenFunction::enterEndBorrowCleanup(SILValue borrowee, + SILValue borrowed) { + Cleanups.pushCleanup(borrowee, borrowed); + return Cleanups.getTopCleanup(); +} + namespace { /// A cleanup that deinitializes an opaque existential container /// before a value has been stored into it, or after its value was taken. diff --git a/lib/SILGen/SILGenDynamicCast.cpp b/lib/SILGen/SILGenDynamicCast.cpp index 11fbf5dcd0178..9bd7522aa1f46 100644 --- a/lib/SILGen/SILGenDynamicCast.cpp +++ b/lib/SILGen/SILGenDynamicCast.cpp @@ -357,20 +357,18 @@ adjustForConditionalCheckedCastOperand(SILLocation loc, ManagedValue src, } std::unique_ptr init; - SGFContext ctx; if (requiresAddress) { init = SGF.emitTemporary(loc, srcAbstractTL); - + + if (hasAbstraction) + src = SGF.emitSubstToOrigValue(loc, src, abstraction, sourceType); + // Okay, if all we need to do is drop the value in an address, // this is easy. - if (!hasAbstraction) { - SGF.B.emitStoreValueOperation(loc, src.forward(SGF), init->getAddress(), - StoreOwnershipQualifier::Init); - init->finishInitialization(SGF); - return init->getManagedAddress(); - } - - ctx = SGFContext(init.get()); + SGF.B.emitStoreValueOperation(loc, src.forward(SGF), init->getAddress(), + StoreOwnershipQualifier::Init); + init->finishInitialization(SGF); + return init->getManagedAddress(); } assert(hasAbstraction); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 86bb384fe6346..764d4052ef3f0 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -78,6 +78,80 @@ ManagedValue SILGenFunction::emitManagedLoadCopy(SILLocation loc, SILValue v, return emitManagedRValueWithCleanup(v, lowering); } +ManagedValue SILGenFunction::emitManagedLoadBorrow(SILLocation loc, + SILValue v) { + auto &lowering = getTypeLowering(v->getType().getSwiftRValueType()); + return emitManagedLoadBorrow(loc, v, lowering); +} + +ManagedValue +SILGenFunction::emitManagedLoadBorrow(SILLocation loc, SILValue v, + const TypeLowering &lowering) { + assert(lowering.getLoweredType().getAddressType() == v->getType()); + if (lowering.isTrivial()) { + v = lowering.emitLoadOfCopy(B, loc, v, IsNotTake); + return ManagedValue::forUnmanaged(v); + } + + assert(!lowering.isAddressOnly() && "cannot retain an unloadable type"); + auto *lbi = B.createLoadBorrow(loc, v); + return emitManagedBorrowedRValueWithCleanup(v, lbi, lowering); +} + +ManagedValue SILGenFunction::emitManagedStoreBorrow(SILLocation loc, SILValue v, + SILValue addr) { + auto &lowering = getTypeLowering(v->getType().getSwiftRValueType()); + return emitManagedStoreBorrow(loc, v, addr, lowering); +} + +ManagedValue SILGenFunction::emitManagedStoreBorrow( + SILLocation loc, SILValue v, SILValue addr, const TypeLowering &lowering) { + assert(lowering.getLoweredType().getObjectType() == v->getType()); + if (lowering.isTrivial()) { + lowering.emitStore(B, loc, v, addr, StoreOwnershipQualifier::Trivial); + return ManagedValue::forUnmanaged(v); + } + assert(!lowering.isAddressOnly() && "cannot retain an unloadable type"); + auto *sbi = B.createStoreBorrow(loc, v, addr); + return emitManagedBorrowedRValueWithCleanup(sbi->getSrc(), sbi, lowering); +} + +ManagedValue SILGenFunction::emitManagedBeginBorrow(SILLocation loc, + SILValue v) { + auto &lowering = getTypeLowering(v->getType().getSwiftRValueType()); + return emitManagedBeginBorrow(loc, v, lowering); +} + +ManagedValue +SILGenFunction::emitManagedBeginBorrow(SILLocation loc, SILValue v, + const TypeLowering &lowering) { + assert(lowering.getLoweredType().getObjectType() == + v->getType().getObjectType()); + if (lowering.isTrivial()) + return ManagedValue::forUnmanaged(v); + auto *bbi = B.createBeginBorrow(loc, v); + return emitManagedBorrowedRValueWithCleanup(v, bbi, lowering); +} + +ManagedValue +SILGenFunction::emitManagedBorrowedRValueWithCleanup(SILValue borrowee, + SILValue borrowed) { + assert(borrowee->getType().getObjectType() == + borrowed->getType().getObjectType()); + auto &lowering = getTypeLowering(borrowee->getType()); + return emitManagedBorrowedRValueWithCleanup(borrowee, borrowed, lowering); +} + +ManagedValue SILGenFunction::emitManagedBorrowedRValueWithCleanup( + SILValue borrowee, SILValue borrowed, const TypeLowering &lowering) { + assert(lowering.getLoweredType().getObjectType() == + borrowee->getType().getObjectType()); + if (lowering.isTrivial()) + return ManagedValue::forUnmanaged(borrowed); + + return ManagedValue(borrowed, enterEndBorrowCleanup(borrowee, borrowed)); +} + ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v) { auto &lowering = getTypeLowering(v->getType()); return emitManagedRValueWithCleanup(v, lowering); @@ -240,6 +314,8 @@ namespace { unsigned numOptionalEvaluations, SGFContext C); RValue visitOpenExistentialExpr(OpenExistentialExpr *E, SGFContext C); + RValue visitMakeTemporarilyEscapableExpr( + MakeTemporarilyEscapableExpr *E, SGFContext C); RValue visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C); @@ -3190,6 +3266,30 @@ RValue RValueEmitter::visitOpenExistentialExpr(OpenExistentialExpr *E, }); } +RValue RValueEmitter::visitMakeTemporarilyEscapableExpr( + MakeTemporarilyEscapableExpr *E, + SGFContext C) { + // TODO: Some day we want to specialize the representation of nonescaping + // closures to be POD and allow an arbitrary payload in their context word. + // At that point, this operation would need to wrap the nonescaping closure + // in an escaping stub, which we could dynamically check at the end of the + // expression to verify it did not in fact escape at runtime. For now, to + // get the syntax for withoutActuallyEscaping in place, this is a no-op. + + // Emit the closure and bind it to an opaque value for use in the + // subexpression. + auto closure = visit(E->getNonescapingClosureValue()); + SILGenFunction::OpaqueValueState opaqueValue{ + std::move(closure).getAsSingleValue(SGF, E), + /*consumable*/ true, + /*hasBeenConsumed*/ false, + }; + + SILGenFunction::OpaqueValueRAII pushOpaqueValue(SGF, E->getOpaqueValue(), + opaqueValue); + return visit(E->getSubExpr(), C); +} + RValue RValueEmitter::visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C) { assert(SGF.OpaqueValues.count(E) && "Didn't bind OpaqueValueExpr"); auto &entry = SGF.OpaqueValues[E]; diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index fcb88a3b4469e..f3941555615df 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -1158,6 +1158,26 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction ManagedValue emitManagedLoadCopy(SILLocation loc, SILValue v, const TypeLowering &lowering); + ManagedValue emitManagedStoreBorrow(SILLocation loc, SILValue v, + SILValue addr); + ManagedValue emitManagedStoreBorrow(SILLocation loc, SILValue v, + SILValue addr, + const TypeLowering &lowering); + + ManagedValue emitManagedLoadBorrow(SILLocation loc, SILValue v); + ManagedValue emitManagedLoadBorrow(SILLocation loc, SILValue v, + const TypeLowering &lowering); + + ManagedValue emitManagedBeginBorrow(SILLocation loc, SILValue v, + const TypeLowering &lowering); + ManagedValue emitManagedBeginBorrow(SILLocation loc, SILValue v); + + ManagedValue emitManagedBorrowedRValueWithCleanup(SILValue borrowee, + SILValue borrower); + ManagedValue + emitManagedBorrowedRValueWithCleanup(SILValue borrowee, SILValue borrower, + const TypeLowering &lowering); + ManagedValue emitManagedRValueWithCleanup(SILValue v); ManagedValue emitManagedRValueWithCleanup(SILValue v, const TypeLowering &lowering); @@ -1515,7 +1535,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction CanSILFunctionType buildThunkType(ManagedValue fn, CanSILFunctionType expectedType, CanSILFunctionType &substFnType, - SmallVectorImpl &subs); + GenericEnvironment *&genericEnv, + SubstitutionMap &contextSubMap, + SubstitutionMap &interfaceSubMap); //===--------------------------------------------------------------------===// // Declarations @@ -1525,7 +1547,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction llvm_unreachable("Not yet implemented"); } - void visitNominalTypeDecl(NominalTypeDecl *D); void visitFuncDecl(FuncDecl *D); void visitPatternBindingDecl(PatternBindingDecl *D); @@ -1534,6 +1555,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction std::unique_ptr emitPatternBindingInitialization(Pattern *P, JumpDest failureDest); + void visitNominalTypeDecl(NominalTypeDecl *D) { + // No lowering support needed. + } + void visitTypeAliasDecl(TypeAliasDecl *D) { // No lowering support needed. } @@ -1597,6 +1622,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction CanType concreteFormalType, ExistentialRepresentation repr); + /// Enter a cleanup to emit an EndBorrow stating that \p borrowed (the + /// borrowed entity) is no longer borrowed from \p borrowee, the original + /// value. + CleanupHandle enterEndBorrowCleanup(SILValue borrowee, SILValue borrowed); + /// Evaluate an Expr as an lvalue. LValue emitLValue(Expr *E, AccessKind accessKind); diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 32ea02c6ac99e..980a3ee9c3167 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -831,10 +831,11 @@ namespace { return true; } - // If the declaration is dynamically dispatched through a protocol, - // we have to use materializeForSet. - if (isa(decl->getDeclContext())) - return true; + // If the declaration is dynamically dispatched through a + // non-ObjC protocol, we have to use materializeForSet. + if (auto *protoDecl = dyn_cast(decl->getDeclContext())) + if (!protoDecl->isObjC()) + return true; return false; } diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp index 53345c2d2277b..6734d430b691d 100644 --- a/lib/SILGen/SILGenMaterializeForSet.cpp +++ b/lib/SILGen/SILGenMaterializeForSet.cpp @@ -385,7 +385,8 @@ struct MaterializeForSetEmitter { /// Given part of the witness's interface type, produce its /// substitution according to the witness substitutions. CanType getSubstWitnessInterfaceType(CanType type) { - auto subs = SubstSelfType->getMemberSubstitutions(WitnessStorage); + auto subs = SubstSelfType->getRValueInstanceType() + ->getMemberSubstitutions(WitnessStorage); return type.subst(SGM.SwiftModule, subs)->getCanonicalType(); } diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 1b061cc8c75fb..0aad88e6bf97a 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -10,10 +10,9 @@ // //===----------------------------------------------------------------------===// // -// In Swift's AST-level type system, function types are allowed to be equivalent -// or have a subtyping relationship even if the SIL-level lowering of the -// calling convention is different. The routines in this file implement thunking -// between lowered function types. +// Swift function types can be equivalent or have a subtyping relationship even +// if the SIL-level lowering of the calling convention is different. The +// routines in this file implement thunking between lowered function types. // // // Re-abstraction thunks @@ -82,9 +81,10 @@ #include "SILGen.h" #include "Scope.h" #include "swift/Basic/Fallthrough.h" -#include "swift/AST/AST.h" +#include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Types.h" #include "swift/SIL/PrettyStackTrace.h" @@ -876,17 +876,49 @@ namespace { // Tuple types are subtypes of their optionals if (auto outputObjectType = outputSubstType.getAnyOptionalObjectType()) { - // The input is exploded and the output is an optional tuple. - // Translate values and collect them into a single optional - // payload. - auto outputTupleType = cast(outputObjectType); + auto outputOrigObjectType = outputOrigType.getAnyOptionalObjectType(); + + if (auto outputTupleType = dyn_cast(outputObjectType)) { + // The input is exploded and the output is an optional tuple. + // Translate values and collect them into a single optional + // payload. + + auto result = + translateAndImplodeIntoOptional(inputOrigType, + inputTupleType, + outputOrigObjectType, + outputTupleType); + Outputs.push_back(result); + return; + } + + // Tuple types are subtypes of optionals of Any, too. + assert(outputObjectType->isAny()); + + // First, construct the existential. + auto result = + translateAndImplodeIntoAny(inputOrigType, + inputTupleType, + outputOrigObjectType, + outputObjectType); + + // Now, convert it to an optional. + translateSingle(outputOrigObjectType, outputObjectType, + outputOrigType, outputSubstType, + result, claimNextOutputType()); + return; + } - return translateAndImplodeIntoOptional(inputOrigType, - inputTupleType, - outputOrigType.getAnyOptionalObjectType(), - outputTupleType); + if (outputSubstType->isAny()) { + claimNextOutputType(); - // FIXME: optional of Any (ugh...) + auto result = + translateAndImplodeIntoAny(inputOrigType, + inputTupleType, + outputOrigType, + outputSubstType); + Outputs.push_back(result); + return; } if (outputTupleType) { @@ -908,7 +940,6 @@ namespace { return; } - // FIXME: Tuple-to-Any conversions llvm_unreachable("Unhandled conversion from exploded tuple"); } @@ -995,10 +1026,11 @@ namespace { /// Handle a tuple that has been exploded in the input but wrapped in /// an optional in the output. - void translateAndImplodeIntoOptional(AbstractionPattern inputOrigType, - CanTupleType inputTupleType, - AbstractionPattern outputOrigType, - CanTupleType outputTupleType) { + ManagedValue + translateAndImplodeIntoOptional(AbstractionPattern inputOrigType, + CanTupleType inputTupleType, + AbstractionPattern outputOrigType, + CanTupleType outputTupleType) { assert(!inputTupleType->hasInOut() && !outputTupleType->hasInOut()); assert(inputTupleType->getNumElements() == @@ -1018,7 +1050,7 @@ namespace { optionalTy = SGF.F.mapTypeIntoContext(optionalTy); auto optional = SGF.B.createEnum(Loc, payload.getValue(), someDecl, optionalTy); - Outputs.push_back(ManagedValue(optional, payload.getCleanup())); + return ManagedValue(optional, payload.getCleanup()); } else { auto optionalBuf = SGF.emitTemporaryAllocation(Loc, optionalTy); auto tupleBuf = SGF.B.createInitEnumDataAddr(Loc, optionalBuf, someDecl, @@ -1033,10 +1065,38 @@ namespace { SGF.B.createInjectEnumAddr(Loc, optionalBuf, someDecl); auto payload = tupleTemp->getManagedAddress(); - Outputs.push_back(ManagedValue(optionalBuf, payload.getCleanup())); + return ManagedValue(optionalBuf, payload.getCleanup()); } } - + + /// Handle a tuple that has been exploded in the input but wrapped + /// in an existential in the output. + ManagedValue + translateAndImplodeIntoAny(AbstractionPattern inputOrigType, + CanTupleType inputTupleType, + AbstractionPattern outputOrigType, + CanType outputSubstType) { + auto existentialTy = SGF.getLoweredType(outputOrigType, outputSubstType); + auto existentialBuf = SGF.emitTemporaryAllocation(Loc, existentialTy); + + auto opaque = AbstractionPattern::getOpaque(); + auto &concreteTL = SGF.getTypeLowering(opaque, inputTupleType); + + auto tupleBuf = + SGF.B.createInitExistentialAddr(Loc, existentialBuf, + inputTupleType, + concreteTL.getLoweredType(), + /*conformances=*/{}); + + auto tupleTemp = SGF.useBufferAsTemporary(tupleBuf, concreteTL); + translateAndImplodeInto(inputOrigType, inputTupleType, + opaque, inputTupleType, + *tupleTemp); + + auto payload = tupleTemp->getManagedAddress(); + return ManagedValue(existentialBuf, payload.getCleanup()); + } + /// Handle a tuple that has been exploded in both the input and /// the output. void translateParallelExploded(AbstractionPattern inputOrigType, @@ -1643,11 +1703,10 @@ void ResultPlanner::plan(AbstractionPattern innerOrigType, CanType outerSubstType, PlanData &planData) { // The substituted types must match up in tuple-ness and arity. - // (Existential erasure could complicate this if we add that as a subtyping - // relationship.) assert(isa(innerSubstType) == isa(outerSubstType) || (isa(innerSubstType) && - outerSubstType->getAnyOptionalObjectType())); + (outerSubstType->isAny() || + outerSubstType->getAnyOptionalObjectType()))); assert(!isa(outerSubstType) || cast(innerSubstType)->getNumElements() == cast(outerSubstType)->getNumElements()); @@ -1772,26 +1831,40 @@ ResultPlanner::planTupleIntoIndirectResult(AbstractionPattern innerOrigType, // Figure out what kind of optional it is. CanType outerSubstObjectType = outerSubstType.getAnyOptionalObjectType(); - assert(outerSubstObjectType && - "inner type was a tuple but outer type was neither a tuple nor " - "optional"); - auto someDecl = Gen.getASTContext().getOptionalSomeDecl(); + if (outerSubstObjectType) { + auto someDecl = Gen.getASTContext().getOptionalSomeDecl(); + + // Prepare the value slot in the optional value. + SILType outerObjectType = + outerResultAddr->getType().getAnyOptionalObjectType(); + SILValue outerObjectResultAddr + = Gen.B.createInitEnumDataAddr(Loc, outerResultAddr, someDecl, + outerObjectType); + + // Emit into that address. + planTupleIntoIndirectResult(innerOrigType, innerSubstType, + outerOrigType.getAnyOptionalObjectType(), + outerSubstObjectType, + planData, outerObjectResultAddr); + + // Add an operation to finish the enum initialization. + addInjectOptionalIndirect(someDecl, outerResultAddr); + return; + } - // Prepare the value slot in the optional value. - SILType outerObjectType = - outerResultAddr->getType().getAnyOptionalObjectType(); - SILValue outerObjectResultAddr - = Gen.B.createInitEnumDataAddr(Loc, outerResultAddr, someDecl, - outerObjectType); + assert(outerSubstType->isAny()); + + // Prepare the value slot in the existential. + auto opaque = AbstractionPattern::getOpaque(); + SILValue outerConcreteResultAddr + = Gen.B.createInitExistentialAddr(Loc, outerResultAddr, innerSubstType, + Gen.getLoweredType(opaque, innerSubstType), + /*conformances=*/{}); // Emit into that address. planTupleIntoIndirectResult(innerOrigType, innerSubstType, - outerOrigType.getAnyOptionalObjectType(), - outerSubstObjectType, - planData, outerObjectResultAddr); - - // Add an operation to finish the enum initialization. - addInjectOptionalIndirect(someDecl, outerResultAddr); + innerOrigType, innerSubstType, + planData, outerConcreteResultAddr); return; } @@ -2324,16 +2397,118 @@ static void buildThunkBody(SILGenFunction &gen, SILLocation loc, gen.B.createReturn(loc, outerResult); } +/// Build a generic signature and environment for a re-abstraction thunk. +/// +/// Most thunks share the generic environment with their original function. +/// The one exception is if the thunk type involves an open existential, +/// in which case we "promote" the opened existential to a new generic parameter. +/// +/// \param gen - the parent function +/// \param openedExistential - the opened existential to promote to a generic +// parameter, if any +/// \param inheritGenericSig - whether to inherit the generic signature from the +/// parent function. +/// \param genericEnv - the new generic environment +/// \param contextSubs - map old archetypes to new archetypes +/// \param interfaceSubs - map interface types to old archetypes +CanGenericSignature +buildThunkSignature(SILGenFunction &gen, + bool inheritGenericSig, + ArchetypeType *openedExistential, + GenericEnvironment *&genericEnv, + SubstitutionMap &contextSubs, + SubstitutionMap &interfaceSubs) { + auto *mod = gen.F.getModule().getSwiftModule(); + auto &ctx = mod->getASTContext(); + + // If there's no opened existential, we just inherit the generic environment + // from the parent function. + if (openedExistential == nullptr) { + auto genericSig = gen.F.getLoweredFunctionType()->getGenericSignature(); + genericEnv = gen.F.getGenericEnvironment(); + auto subsArray = gen.F.getForwardingSubstitutions(); + genericSig->getSubstitutionMap(subsArray, interfaceSubs); + genericEnv->getSubstitutionMap(mod, subsArray, contextSubs); + return genericSig; + } + + ArchetypeBuilder builder(*mod); + + // Add the existing generic signature. + int depth = 0; + if (inheritGenericSig) { + if (auto genericSig = gen.F.getLoweredFunctionType()->getGenericSignature()) { + builder.addGenericSignature(genericSig); + depth = genericSig->getGenericParams().back()->getDepth() + 1; + } + } + + // Add a new generic parameter to replace the opened existential. + auto *newGenericParam = GenericTypeParamType::get(depth, 0, ctx); + builder.addGenericParameter(newGenericParam); + Requirement newRequirement(RequirementKind::Conformance, newGenericParam, + openedExistential->getOpenedExistentialType()); + RequirementSource source(RequirementSource::Explicit, SourceLoc()); + builder.addRequirement(newRequirement, source); + + GenericSignature *genericSig = builder.getGenericSignature(); + genericEnv = builder.getGenericEnvironment(genericSig); + + // Calculate substitutions to map the original function's archetypes to + // the new generic environment's archetypes. + genericSig->enumeratePairedRequirements( + [&](Type depTy, ArrayRef reqs) -> bool { + auto canTy = depTy->getCanonicalType(); + + // Add abstract conformances. + auto conformances = + ctx.AllocateUninitialized( + reqs.size()); + for (unsigned i = 0, e = reqs.size(); i < e; i++) { + auto reqt = reqs[i]; + assert(reqt.getKind() == RequirementKind::Conformance); + auto *proto = reqt.getSecondType() + ->castTo()->getDecl(); + conformances[i] = ProtocolConformanceRef(proto); + } + + ArchetypeType *oldArchetype; + // The opened existential archetype maps to the new generic parameter's + // archetype. + if (depTy->isEqual(newGenericParam)) + oldArchetype = openedExistential; + else + oldArchetype = gen.F.mapTypeIntoContext(depTy)->castTo(); + + // Add the replacement mapping. + auto newArchetype = genericEnv->mapTypeIntoContext(mod, depTy) + ->castTo(); + + contextSubs.addSubstitution(CanType(oldArchetype), newArchetype); + interfaceSubs.addSubstitution(canTy, oldArchetype); + + contextSubs.addConformances(CanType(oldArchetype), conformances); + interfaceSubs.addConformances(canTy, conformances); + + return false; + }); + + return genericSig->getCanonicalSignature(); +} + /// Build the type of a function transformation thunk. CanSILFunctionType SILGenFunction::buildThunkType( ManagedValue fn, CanSILFunctionType expectedType, CanSILFunctionType &substFnType, - SmallVectorImpl &subs) { + GenericEnvironment *&genericEnv, + SubstitutionMap &contextSubs, + SubstitutionMap &interfaceSubs) { auto sourceType = fn.getType().castTo(); assert(!expectedType->isPolymorphic()); assert(!sourceType->isPolymorphic()); + // Can't build a thunk without context, so we require ownership semantics // on the result type. assert(expectedType->getExtInfo().hasContext()); @@ -2341,19 +2516,42 @@ CanSILFunctionType SILGenFunction::buildThunkType( auto extInfo = expectedType->getExtInfo() .withRepresentation(SILFunctionType::Representation::Thin); + // Does the thunk type involve archetypes other than opened existentials? + bool hasArchetypes = false; + // Does the thunk type involve an open existential type? + ArchetypeType *openedExistential = nullptr; + auto archetypeVisitor = [&](Type t) { + if (auto *archetypeTy = t->getAs()) { + if (archetypeTy->getOpenedExistentialType()) { + assert((openedExistential == nullptr || + openedExistential == archetypeTy) && + "one too many open existentials"); + openedExistential = archetypeTy; + } else + hasArchetypes = true; + } + }; + // Use the generic signature from the context if the thunk involves // generic parameters. CanGenericSignature genericSig; if (expectedType->hasArchetype() || sourceType->hasArchetype()) { - genericSig = F.getLoweredFunctionType()->getGenericSignature(); - auto subsArray = F.getForwardingSubstitutions(); - subs.append(subsArray.begin(), subsArray.end()); + expectedType.visit(archetypeVisitor); + sourceType.visit(archetypeVisitor); + + genericSig = buildThunkSignature(*this, + hasArchetypes, + openedExistential, + genericEnv, + contextSubs, + interfaceSubs); + } - // If our parent function was pseudogeneric, this thunk must also be - // pseudogeneric, since we have no way to pass generic parameters. + // If our parent function was pseudogeneric, this thunk must also be + // pseudogeneric, since we have no way to pass generic parameters. + if (genericSig) if (F.getLoweredFunctionType()->isPseudogeneric()) extInfo = extInfo.withIsPseudogeneric(); - } // Add the function type as the parameter. SmallVector params; @@ -2364,32 +2562,47 @@ CanSILFunctionType SILGenFunction::buildThunkType( ? DefaultThickCalleeConvention : ParameterConvention::Direct_Unowned}); + auto &mod = *F.getModule().getSwiftModule(); + auto getCanonicalType = [&](Type t) -> CanType { + if (genericSig) + return genericSig->getCanonicalTypeInContext(t, mod); + return t->getCanonicalType(); + }; + // Map the parameter and expected types out of context to get the interface // type of the thunk. SmallVector interfaceParams; interfaceParams.reserve(params.size()); for (auto ¶m : params) { + auto paramTy = param.getType().subst(contextSubs, + SubstFlags::AllowLoweredTypes); + auto paramIfaceTy = GenericEnvironment::mapTypeOutOfContext( + genericEnv, paramTy); interfaceParams.push_back( - SILParameterInfo( - F.mapTypeOutOfContext(param.getType()) - ->getCanonicalType(), - param.getConvention())); + SILParameterInfo(getCanonicalType(paramIfaceTy), + param.getConvention())); } SmallVector interfaceResults; for (auto &result : expectedType->getAllResults()) { - auto interfaceResult = result.getWithType( - F.mapTypeOutOfContext(result.getType()) - ->getCanonicalType()); + auto resultTy = result.getType().subst(contextSubs, + SubstFlags::AllowLoweredTypes); + auto resultIfaceTy = GenericEnvironment::mapTypeOutOfContext( + genericEnv, resultTy); + auto interfaceResult = result.getWithType(getCanonicalType(resultIfaceTy)); interfaceResults.push_back(interfaceResult); } Optional interfaceErrorResult; if (expectedType->hasErrorResult()) { + auto errorResult = expectedType->getErrorResult(); + auto errorTy = errorResult.getType().subst(contextSubs, + SubstFlags::AllowLoweredTypes); + auto errorIfaceTy = GenericEnvironment::mapTypeOutOfContext( + genericEnv, errorTy); interfaceErrorResult = SILResultInfo( - F.mapTypeOutOfContext(expectedType->getErrorResult().getType()) - ->getCanonicalType(), - expectedType->getErrorResult().getConvention()); + getCanonicalType(errorIfaceTy), + expectedType->getErrorResult().getConvention()); } // The type of the thunk function. @@ -2431,38 +2644,55 @@ static ManagedValue createThunk(SILGenFunction &gen, "bridging in re-abstraction thunk?"); // Declare the thunk. - SmallVector substitutions; CanSILFunctionType substFnType; + SubstitutionMap contextSubs, interfaceSubs; + GenericEnvironment *genericEnv = nullptr; auto thunkType = gen.buildThunkType(fn, expectedType, - substFnType, substitutions); - auto genericEnv = gen.F.getGenericEnvironment(); - if (!thunkType->isPolymorphic()) - genericEnv = nullptr; + substFnType, genericEnv, + contextSubs, interfaceSubs); + + auto fromType = fn.getType() + .subst(gen.F.getModule(), contextSubs) + .castTo(); + auto toType = SILType::getPrimitiveObjectType(expectedType) + .subst(gen.F.getModule(), contextSubs) + .castTo(); auto thunk = gen.SGM.getOrCreateReabstractionThunk( genericEnv, thunkType, - fn.getType().castTo(), - expectedType, + fromType, + toType, gen.F.isFragile()); // Build it if necessary. if (thunk->empty()) { + inputSubstType = cast(inputSubstType.subst(contextSubs) + ->getCanonicalType()); + outputSubstType = cast(outputSubstType.subst(contextSubs) + ->getCanonicalType()); + // Borrow the context archetypes from the enclosing function. thunk->setGenericEnvironment(genericEnv); SILGenFunction thunkSGF(gen.SGM, *thunk); auto loc = RegularLocation::getAutoGeneratedLocation(); buildThunkBody(thunkSGF, loc, - inputOrigType, inputSubstType, - outputOrigType, outputSubstType); + inputOrigType, + inputSubstType, + outputOrigType, + outputSubstType); } + SmallVector subs; + if (auto genericSig = thunkType->getGenericSignature()) + genericSig->getSubstitutions(interfaceSubs, subs); + // Create it in our current function. auto thunkValue = gen.B.createFunctionRef(loc, thunk); auto thunkedFn = gen.B.createPartialApply(loc, thunkValue, SILType::getPrimitiveObjectType(substFnType), - substitutions, fn.forward(gen), + subs, fn.forward(gen), SILType::getPrimitiveObjectType(expectedType)); return gen.emitManagedRValueWithCleanup(thunkedFn, expectedTL); } diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 4a3b684b47f34..b23f9ee4191fc 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -417,10 +417,6 @@ void SILGenModule::visitNominalTypeDecl(NominalTypeDecl *ntd) { SILGenType(*this, ntd).emitType(); } -void SILGenFunction::visitNominalTypeDecl(NominalTypeDecl *ntd) { - SILGenType(SGM, ntd).emitType(); -} - /// SILGenExtension - an ASTVisitor for generating SIL from method declarations /// and protocol conformances inside type extensions. class SILGenExtension : public TypeMemberVisitor { diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp index 8843e3ae8f696..e9f94a8589d9e 100644 --- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp +++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp @@ -545,11 +545,7 @@ bool swift::ArraySemanticsCall::mayHaveBridgedObjectElementType() const { assert(hasSelf() && "Need self parameter"); auto Ty = getSelf()->getType().getSwiftRValueType(); - auto Canonical = Ty.getCanonicalTypeOrNull(); - if (Canonical.isNull()) - return true; - - auto *Struct = Canonical->getStructOrBoundGenericStruct(); + auto *Struct = Ty->getStructOrBoundGenericStruct(); assert(Struct && "Array must be a struct !?"); if (Struct) { auto BGT = dyn_cast(Ty); @@ -558,10 +554,7 @@ bool swift::ArraySemanticsCall::mayHaveBridgedObjectElementType() const { // Check the array element type parameter. bool isClass = true; - for (auto TP : BGT->getGenericArgs()) { - auto EltTy = TP.getCanonicalTypeOrNull(); - if (EltTy.isNull()) - return true; + for (auto EltTy : BGT->getGenericArgs()) { if (EltTy->isBridgeableObjectType()) return true; isClass = false; diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp index d56ac5cf2fd0f..33835e889955d 100644 --- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp @@ -228,8 +228,7 @@ CalleeList CalleeCache::getCalleeList(SILInstruction *I) const { auto Ty = I->getOperand(0)->getType(); while (Ty.getSwiftRValueType()->getAnyOptionalObjectType()) Ty = M.Types.getLoweredType(Ty.getSwiftRValueType() - ->getAnyOptionalObjectType() - .getCanonicalTypeOrNull()); + .getAnyOptionalObjectType()); auto Class = Ty.getSwiftRValueType().getClassOrBoundGenericClass(); if (!Class || Class->hasClangNode() || !Class->hasDestructor()) return CalleeList(); diff --git a/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp b/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp index 0205cba04a1a7..740d8be73add0 100644 --- a/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp @@ -40,13 +40,9 @@ bool DestructorAnalysis::cacheResult(CanType Type, bool Result) { return Result; } -bool DestructorAnalysis::isSafeType(Type Ty) { - CanType Canonical = Ty.getCanonicalTypeOrNull(); - if (Canonical.isNull()) - return false; - +bool DestructorAnalysis::isSafeType(CanType Ty) { // Don't visit types twice. - auto CachedRes = Cached.find(Canonical); + auto CachedRes = Cached.find(Ty); if (CachedRes != Cached.end()) { return CachedRes->second; } @@ -55,43 +51,43 @@ bool DestructorAnalysis::isSafeType(Type Ty) { // position it is safe in the absence of another fact that proves otherwise. // We will reset this value to the correct value once we return from the // recursion below. - cacheResult(Canonical, true); + cacheResult(Ty, true); // Trivial value types. - if (Canonical->getKind() == TypeKind::BuiltinInteger) - return cacheResult(Canonical, true); - if (Canonical->getKind() == TypeKind::BuiltinFloat) - return cacheResult(Canonical, true); + if (Ty->getKind() == TypeKind::BuiltinInteger) + return cacheResult(Ty, true); + if (Ty->getKind() == TypeKind::BuiltinFloat) + return cacheResult(Ty, true); // A struct is safe if // * either it implements the _DestructorSafeContainer protocol and // all the type parameters are safe types. // * or all stored properties are safe types. - if (auto *Struct = Canonical->getStructOrBoundGenericStruct()) { + if (auto *Struct = Ty->getStructOrBoundGenericStruct()) { if (implementsDestructorSafeContainerProtocol(Struct) && - areTypeParametersSafe(Canonical)) - return cacheResult(Canonical, true); + areTypeParametersSafe(Ty)) + return cacheResult(Ty, true); // Check the stored properties. for (auto SP : Struct->getStoredProperties()) - if (!isSafeType(SP->getInterfaceType())) - return cacheResult(Canonical, false); + if (!isSafeType(SP->getInterfaceType()->getCanonicalType())) + return cacheResult(Ty, false); - return cacheResult(Canonical, true); + return cacheResult(Ty, true); } // A tuple type is safe if its elements are safe. - if (auto Tuple = dyn_cast(Canonical)) { + if (auto Tuple = dyn_cast(Ty)) { for (auto &Elt : Tuple->getElements()) - if (!isSafeType(Elt.getType())) - return cacheResult(Canonical, false); - return cacheResult(Canonical, true); + if (!isSafeType(Elt.getType()->getCanonicalType())) + return cacheResult(Ty, false); + return cacheResult(Ty, true); } // TODO: enum types. - return cacheResult(Canonical, false); + return cacheResult(Ty, false); } bool DestructorAnalysis::implementsDestructorSafeContainerProtocol( @@ -113,7 +109,7 @@ bool DestructorAnalysis::areTypeParametersSafe(CanType Ty) { // Make sure all type parameters are safe. for (auto TP : BGT->getGenericArgs()) { - if (!isSafeType(TP)) + if (!isSafeType(TP->getCanonicalType())) return false; } return true; diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 0dd6652b531c3..f55c95cc7a577 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -1162,8 +1162,7 @@ bool EscapeAnalysis::buildConnectionGraphForDestructor( // destructors for its components. while (Ty.getSwiftRValueType()->getAnyOptionalObjectType()) Ty = M.Types.getLoweredType(Ty.getSwiftRValueType() - ->getAnyOptionalObjectType() - .getCanonicalTypeOrNull()); + .getAnyOptionalObjectType()); auto Class = Ty.getSwiftRValueType().getClassOrBoundGenericClass(); if (!Class || !Class->hasDestructor()) return false; diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index 33fa2c4a3fa74..e1e34aba460e7 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -232,7 +232,7 @@ static SILFunction *genGetterFromInit(StoreInst *Store, } // Generate a getter from the global init function without side-effects. - auto refType = varDecl->getType().getCanonicalTypeOrNull(); + auto refType = varDecl->getInterfaceType()->getCanonicalType(); // Function takes no arguments and returns refType SILResultInfo Results[] = { SILResultInfo(refType, ResultConvention::Owned) }; SILFunctionType::ExtInfo EInfo; @@ -485,7 +485,7 @@ static SILFunction *genGetterFromInit(SILFunction *InitF, VarDecl *varDecl) { if (auto *F = InitF->getModule().lookUpFunction(getterName)) return F; - auto refType = varDecl->getType().getCanonicalTypeOrNull(); + auto refType = varDecl->getInterfaceType()->getCanonicalType(); // Function takes no arguments and returns refType SILResultInfo Results[] = { SILResultInfo(refType, ResultConvention::Owned) }; SILFunctionType::ExtInfo EInfo; diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp index 437a39671a366..94a104ea58d1a 100644 --- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp @@ -1863,10 +1863,7 @@ class ArrayPropertiesAnalysis { bool isClassElementTypeArray(SILValue Arr) { auto Ty = Arr->getType().getSwiftRValueType(); - auto Canonical = Ty.getCanonicalTypeOrNull(); - if (Canonical.isNull()) - return false; - auto *Struct = Canonical->getStructOrBoundGenericStruct(); + auto *Struct = Ty->getStructOrBoundGenericStruct(); assert(Struct && "Array must be a struct !?"); if (Struct) { // No point in hoisting generic code. @@ -1876,11 +1873,8 @@ class ArrayPropertiesAnalysis { // Check the array element type parameter. bool isClass = false; - for (auto TP : BGT->getGenericArgs()) { - auto EltTy = TP.getCanonicalTypeOrNull(); - if (EltTy.isNull()) - return false; - if (!EltTy.hasReferenceSemantics()) + for (auto EltTy : BGT->getGenericArgs()) { + if (!EltTy->hasReferenceSemantics()) return false; isClass = true; } diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index 3835f5564f628..a8cd5c7a7f1e0 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -439,6 +439,9 @@ runOnFunctionRecursively(SILFunction *F, FullApplySite AI, // The callee only needs to know about opened archetypes used in // the substitution list. OpenedArchetypesTracker.registerUsedOpenedArchetypes(InnerAI.getInstruction()); + if (PAI) { + OpenedArchetypesTracker.registerUsedOpenedArchetypes(PAI); + } SILInliner Inliner(*F, *CalleeFunction, SILInliner::InlineKind::MandatoryInline, diff --git a/lib/SILOptimizer/SILCombiner/SILCombiner.h b/lib/SILOptimizer/SILCombiner/SILCombiner.h index 9c094733448d4..59be0f31242a7 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombiner.h +++ b/lib/SILOptimizer/SILCombiner/SILCombiner.h @@ -261,7 +261,7 @@ class SILCombiner : CanType ConcreteType, SILValue ConcreteTypeDef, ProtocolConformanceRef Conformance, - CanType OpenedArchetype); + ArchetypeType *OpenedArchetype); SILInstruction * propagateConcreteTypeOfInitExistential(FullApplySite AI, ProtocolDecl *Protocol, diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index f139a6d8749df..f0b39981d976a 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -614,7 +614,7 @@ static SILValue getAddressOfStackInit(AllocStackInst *ASI, /// Find the init_existential, which could be used to determine a concrete /// type of the \p Self. static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, - CanType &OpenedArchetype, + ArchetypeType *&OpenedArchetype, SILValue &OpenedArchetypeDef) { if (auto *Instance = dyn_cast(Self)) { // In case the Self operand is an alloc_stack where a copy_addr copies the @@ -637,14 +637,16 @@ static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, if (!IE) return nullptr; - OpenedArchetype = Open->getType().getSwiftRValueType(); + OpenedArchetype = Open->getType().getSwiftRValueType() + ->castTo(); OpenedArchetypeDef = Open; return IE; } if (auto *Open = dyn_cast(Self)) { if (auto *IE = dyn_cast(Open->getOperand())) { - OpenedArchetype = Open->getType().getSwiftRValueType(); + OpenedArchetype = Open->getType().getSwiftRValueType() + ->castTo(); OpenedArchetypeDef = Open; return IE; } @@ -654,9 +656,10 @@ static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, if (auto *Open = dyn_cast(Self)) { if (auto *IE = dyn_cast(Open->getOperand())) { - OpenedArchetype = Open->getType().getSwiftRValueType(); - while (auto Metatype = dyn_cast(OpenedArchetype)) - OpenedArchetype = Metatype.getInstanceType(); + auto Ty = Open->getType().getSwiftRValueType(); + while (auto Metatype = dyn_cast(Ty)) + Ty = Metatype.getInstanceType(); + OpenedArchetype = Ty->castTo(); OpenedArchetypeDef = Open; return IE; } @@ -674,7 +677,7 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, CanType ConcreteType, SILValue ConcreteTypeDef, ProtocolConformanceRef Conformance, - CanType OpenedArchetype) { + ArchetypeType *OpenedArchetype) { // Create a set of arguments. SmallVector Args; for (auto Arg : AI.getArgumentsWithoutSelf()) { @@ -686,8 +689,8 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, // replaced by a concrete type. SmallVector Substitutions; for (auto Subst : AI.getSubstitutions()) { - if (Subst.getReplacement().getCanonicalTypeOrNull() == - OpenedArchetype) { + auto *A = Subst.getReplacement()->getAs(); + if (A && A == OpenedArchetype) { auto Conformances = AI.getModule().getASTContext() .AllocateUninitialized(1); Conformances[0] = Conformance; @@ -711,8 +714,8 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, NewSubstCalleeType = SILType::getPrimitiveObjectType(SFT); } else { SubstitutionMap Subs; - Subs.addSubstitution(OpenedArchetype, ConcreteType); - Subs.addConformances(OpenedArchetype, Conformance); + Subs.addSubstitution(CanType(OpenedArchetype), ConcreteType); + Subs.addConformances(CanType(OpenedArchetype), Conformance); NewSubstCalleeType = SubstCalleeType.subst(AI.getModule(), Subs); } @@ -820,7 +823,7 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI, // Try to find the init_existential, which could be used to // determine a concrete type of the self. - CanType OpenedArchetype; + ArchetypeType *OpenedArchetype = nullptr; SILValue OpenedArchetypeDef; SILInstruction *InitExistential = findInitExistential(AI, Self, OpenedArchetype, OpenedArchetypeDef); @@ -849,7 +852,8 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI, if (ConcreteType->isOpenedExistential()) { // Prepare a mini-mapping for opened archetypes. // SILOpenedArchetypesTracker OpenedArchetypesTracker(*AI.getFunction()); - OpenedArchetypesTracker.addOpenedArchetypeDef(ConcreteType, ConcreteTypeDef); + OpenedArchetypesTracker.addOpenedArchetypeDef( + ConcreteType->castTo(), ConcreteTypeDef); Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker); } diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index 436959a5640e6..2de032f9da160 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -645,7 +645,7 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V, auto OldOpenedArchetype = getOpenedArchetypeOf(Inst); auto NewOpenedArchetype = getOpenedArchetypeOf(dyn_cast(V)); SubstitutionMap TypeSubstMap; - TypeSubstMap.addSubstitution(OldOpenedArchetype, NewOpenedArchetype); + TypeSubstMap.addSubstitution(CanType(OldOpenedArchetype), NewOpenedArchetype); // Collect all candidates that may contain opened archetypes // that need to be replaced. for (auto Use : Inst->getUses()) { @@ -702,8 +702,9 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V, auto ResultDependsOnOldOpenedArchetype = Candidate->getType().getSwiftRValueType().findIf( [&OldOpenedArchetype](Type t) -> bool { - if (t.getCanonicalTypeOrNull() == OldOpenedArchetype) - return true; + if (auto *archetypeTy = t->getAs()) + if (archetypeTy == OldOpenedArchetype) + return true; return false; }); if (ResultDependsOnOldOpenedArchetype) { diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp index 22126913973d3..cee1da100c052 100644 --- a/lib/SILOptimizer/Utils/Local.cpp +++ b/lib/SILOptimizer/Utils/Local.cpp @@ -1512,7 +1512,7 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, // Create a temporary OptionalTy = OptionalType::get(Dest->getType().getSwiftRValueType()) ->getImplementationType() - .getCanonicalTypeOrNull(); + ->getCanonicalType(); OptionalTy.getAnyOptionalObjectType(OTK); Tmp = Builder.createAllocStack(Loc, SILType::getPrimitiveObjectType(OptionalTy)); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 630bf92074cda..40402cc5893a4 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -387,7 +387,7 @@ namespace { AccessSemantics semantics) { // Determine the declaration selected for this overloaded reference. auto &ctx = cs.getASTContext(); - + // If this is a member of a nominal type, build a reference to the // member with an implied base type. if (decl->getDeclContext()->isTypeContext() && isa(decl)) { @@ -603,6 +603,11 @@ namespace { prev = result; } + // Invalid case -- direct call of a metatype. Has one less argument + // application because there's no ".init". + if (isa(ExprStack.back())) + argCount--; + return argCount; } @@ -680,12 +685,13 @@ namespace { } /// Trying to close the active existential, if there is one. - bool closeExistential(Expr *&result, bool force=false) { + bool closeExistential(Expr *&result, ConstraintLocatorBuilder locator, + bool force=false) { if (OpenedExistentials.empty()) return false; auto &record = OpenedExistentials.back(); - assert(record.Depth <= ExprStack.size() - 1); + assert(record.Depth <= ExprStack.size()); if (!force && record.Depth < ExprStack.size() - 1) return false; @@ -696,10 +702,14 @@ namespace { Type resultTy; resultTy = cs.getType(result); if (resultTy->hasOpenedExistential(record.Archetype)) { - Type erasedTy = resultTy->eraseOpenedExistential( - innerCS.DC->getParentModule(), - record.Archetype); - result = coerceToType(result, erasedTy, nullptr); + Type erasedTy = resultTy->eraseOpenedExistential(record.Archetype); + auto range = result->getSourceRange(); + result = coerceToType(result, erasedTy, locator); + // FIXME: Implement missing tuple-to-tuple conversion + if (result == nullptr) { + result = new (tc.Context) ErrorExpr(range); + result->setType(erasedTy); + } } // If the opaque value has an l-value access kind, then @@ -722,22 +732,6 @@ namespace { return true; } - /// Is the given function a constructor of a class or protocol? - /// Such functions are subject to DynamicSelf manipulations. - /// - /// We want to avoid taking the DynamicSelf paths for other - /// constructors for two reasons: - /// - it's an unnecessary cost - /// - optionality preservation has a problem with constructors on - /// optional types - static bool isPolymorphicConstructor(AbstractFunctionDecl *fn) { - if (!isa(fn)) - return false; - auto *parent = - fn->getParent()->getAsNominalTypeOrNominalTypeExtensionContext(); - return parent && (isa(parent) || isa(parent)); - } - /// \brief Build a new member reference with the given base and member. Expr *buildMemberRef(Expr *base, Type openedFullType, SourceLoc dotLoc, ValueDecl *member, DeclNameLoc memberLoc, @@ -776,12 +770,10 @@ namespace { } } - // Produce a reference to the member, the type of the container it - // resides in, and the type produced by the reference itself. - Type containerTy; + // Produce a reference to the member and the type produced by the + // reference itself. ConcreteDeclRef memberRef; Type refTy; - Type dynamicSelfFnType; if (member->getInterfaceType()->is() || openedFullType->hasTypeVariable()) { // We require substitutions. Figure out what they are. @@ -800,19 +792,31 @@ namespace { substitutions); memberRef = ConcreteDeclRef(context, member, substitutions); - - if (auto openedFullFnType = openedFullType->getAs()) { - auto openedBaseType = openedFullFnType->getInput() - ->getRValueInstanceType(); - containerTy = solution.simplifyType(tc, openedBaseType); - } } else { // No substitutions required; the declaration reference is simple. - containerTy = member->getDeclContext()->getDeclaredTypeOfContext(); memberRef = member; refTy = openedFullType; } + // If we're referring to the member of a module, it's just a simple + // reference. + if (baseTy->is()) { + assert(semantics == AccessSemantics::Ordinary && + "Direct property access doesn't make sense for this"); + auto ref = new (context) DeclRefExpr(memberRef, memberLoc, Implicit); + cs.setType(ref, refTy); + ref->setFunctionRefKind(functionRefKind); + return cs.cacheType(new (context) + DotSyntaxBaseIgnoredExpr(base, dotLoc, ref)); + } + + // Produce a reference to the type of the container the member + // resides in. + Type containerTy = + openedFullType->castTo() + ->getInput()->getRValueInstanceType(); + containerTy = solution.simplifyType(tc, containerTy); + // If we opened up an existential when referencing this member, update // the base accordingly. auto knownOpened = solution.OpenedExistentialTypes.find( @@ -828,60 +832,23 @@ namespace { // If this is a method whose result type is dynamic Self, or a // construction, replace the result type with the actual object type. - if (auto func = dyn_cast(member)) { - if ((isa(func) && - (cast(func)->hasDynamicSelf() || - (openedExistential && - cast(func)->hasArchetypeSelf()))) || - isPolymorphicConstructor(func)) { - refTy = refTy->replaceCovariantResultType(containerTy, - func->getNumParameterLists()); - dynamicSelfFnType = refTy->replaceCovariantResultType( - baseTy, - func->getNumParameterLists()); - - if (openedExistential) { - // Replace the covariant result type in the opened type. We need to - // handle dynamic member references, which wrap the function type - // in an optional. - OptionalTypeKind optKind; - if (auto optObject = openedType->getAnyOptionalObjectType(optKind)) - openedType = optObject; - openedType = openedType->replaceCovariantResultType( - baseTy, - func->getNumParameterLists()-1); - if (optKind != OptionalTypeKind::OTK_None) - openedType = OptionalType::get(optKind, openedType); + Type dynamicSelfFnType; + if (!member->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { + if (auto func = dyn_cast(member)) { + if ((isa(func) && + cast(func)->hasDynamicSelf()) || + (isa(func) && + containerTy->getClassOrBoundGenericClass())) { + refTy = refTy->replaceCovariantResultType( + containerTy, func->getNumParameterLists()); + if (!baseTy->isEqual(containerTy)) { + dynamicSelfFnType = refTy->replaceCovariantResultType( + baseTy, func->getNumParameterLists()); + } } - - // If the type after replacing DynamicSelf with the provided base - // type is no different, we don't need to perform a conversion here. - if (refTy->isEqual(dynamicSelfFnType)) - dynamicSelfFnType = nullptr; } } - // If we're referring to the member of a module, it's just a simple - // reference. - if (baseTy->is()) { - assert(semantics == AccessSemantics::Ordinary && - "Direct property access doesn't make sense for this"); - assert(!dynamicSelfFnType && "No reference type to convert to"); - auto ref = new (context) DeclRefExpr(memberRef, memberLoc, Implicit); - cs.setType(ref, refTy); - ref->setFunctionRefKind(functionRefKind); - return cs.cacheType(new (context) - DotSyntaxBaseIgnoredExpr(base, dotLoc, ref)); - } - - // Otherwise, we're referring to a member of a type. - Type selfTy; - if (isa(member->getDeclContext()) && - (baseTy->is() || baseTy->isExistentialType())) - selfTy = baseTy; - else - selfTy = containerTy; - // References to properties with accessors and storage usually go // through the accessors, but sometimes are direct. if (auto *VD = dyn_cast(member)) { @@ -895,6 +862,7 @@ namespace { // If the base is already an lvalue with the right base type, we can // pass it as an inout qualified type. + Type selfTy = containerTy; if (selfTy->isEqual(baseTy)) if (cs.getType(base)->is()) selfTy = InOutType::get(selfTy); @@ -904,7 +872,7 @@ namespace { } else { // Convert the base to an rvalue of the appropriate metatype. base = coerceToType(base, - MetatypeType::get(selfTy), + MetatypeType::get(containerTy), locator.withPathElement( ConstraintLocator::MemberRefBase)); if (!base) @@ -930,14 +898,12 @@ namespace { // existential. if (openedExistential && refType->hasOpenedExistential(knownOpened->second)) { - refType = refType->eraseOpenedExistential( - cs.DC->getParentModule(), - knownOpened->second); + refType = refType->eraseOpenedExistential(knownOpened->second); } cs.setType(ref, refType); - closeExistential(ref, /*force=*/openedExistential); + closeExistential(ref, locator, /*force=*/openedExistential); return ref; } @@ -964,7 +930,7 @@ namespace { // Skip the synthesized 'self' input type of the opened type. cs.setType(memberRefExpr, simplifyType(openedType)); Expr *result = memberRefExpr; - closeExistential(result); + closeExistential(result, locator); return result; } @@ -991,7 +957,7 @@ namespace { Expr *result = new (context) DotSyntaxBaseIgnoredExpr(base, dotLoc, ref); cs.cacheType(result); - closeExistential(result, /*force=*/openedExistential); + closeExistential(result, locator, /*force=*/openedExistential); return result; } else { assert((!baseIsInstance || member->isInstanceMember()) && @@ -1329,7 +1295,7 @@ namespace { isImplicit); cs.setType(subscriptExpr, resultTy); Expr *result = subscriptExpr; - closeExistential(result); + closeExistential(result, locator); return result; } @@ -1368,7 +1334,7 @@ namespace { subscriptExpr->setIsSuper(isSuper); Expr *result = subscriptExpr; - closeExistential(result); + closeExistential(result, locator); return result; } @@ -1390,7 +1356,7 @@ namespace { cs.setType(subscriptExpr, resultTy); subscriptExpr->setIsSuper(isSuper); Expr *result = subscriptExpr; - closeExistential(result); + closeExistential(result, locator); return result; } @@ -3512,6 +3478,10 @@ namespace { llvm_unreachable("Already type-checked"); } + Expr *visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *expr){ + llvm_unreachable("Already type-checked"); + } + Expr *visitEnumIsCaseExpr(EnumIsCaseExpr *expr) { // Should already be type-checked. return simplifyExprType(expr); @@ -4595,15 +4565,16 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType, // Handle existential coercions that implicitly look through ImplicitlyUnwrappedOptional. if (auto ty = cs.lookThroughImplicitlyUnwrappedOptionalType(fromType)) { - expr = coerceImplicitlyUnwrappedOptionalToValue(expr, ty, locator); + auto unwrappedExpr + = coerceImplicitlyUnwrappedOptionalToValue(expr, ty, locator); - fromType = cs.getType(expr); - assert(!fromType->is()); + auto unwrappedFromType = cs.getType(unwrappedExpr); + assert(!unwrappedFromType->is()); // FIXME: Hack. We shouldn't try to coerce existential when there is no // existential upcast to perform. - if (fromType->isEqual(toType)) - return expr; + if (unwrappedFromType->isEqual(toType)) + return unwrappedExpr; } Type fromInstanceType = fromType; @@ -5230,6 +5201,16 @@ ClosureExpr *ExprRewriter::coerceClosureExprFromNever(ClosureExpr *closureExpr) return closureExpr; } +// Look through sugar and DotSyntaxBaseIgnoredExprs. +static Expr * +getSemanticExprForDeclOrMemberRef(Expr *expr) { + auto semanticExpr = expr->getSemanticsProvidingExpr(); + while (auto ignoredBase = dyn_cast(semanticExpr)){ + semanticExpr = ignoredBase->getRHS()->getSemanticsProvidingExpr(); + } + return semanticExpr; +} + static void maybeDiagnoseUnsupportedFunctionConversion(ConstraintSystem &cs, Expr *expr, AnyFunctionType *toType) { @@ -5252,11 +5233,7 @@ maybeDiagnoseUnsupportedFunctionConversion(ConstraintSystem &cs, Expr *expr, // Can convert a decl ref to a global or local function that doesn't // capture context. Look through ignored bases too. // TODO: Look through static method applications to the type. - auto semanticExpr = expr->getSemanticsProvidingExpr(); - while (auto ignoredBase = dyn_cast(semanticExpr)){ - semanticExpr = ignoredBase->getRHS()->getSemanticsProvidingExpr(); - } - + auto semanticExpr = getSemanticExprForDeclOrMemberRef(expr); auto maybeDiagnoseFunctionRef = [&](FuncDecl *fn) { // TODO: We could allow static (or class final) functions too by // "capturing" the metatype in a thunk. @@ -5432,36 +5409,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, toTuple->getElementForScalarInit(), locator); } - case ConversionRestrictionKind::TupleToScalar: { - // If this was a single-element tuple expression, reach into that - // subexpression. - // FIXME: This is a hack to deal with @lvalue-ness issues. It loses - // source information. - if (auto fromTupleExpr = dyn_cast(expr)) { - if (fromTupleExpr->getNumElements() == 1) { - return coerceToType(fromTupleExpr->getElement(0), toType, - locator.withPathElement( - LocatorPathElt::getTupleElement(0))); - } - } - - // Extract the element. - auto fromTuple = fromType->castTo(); - expr = - cs.cacheType( - new (cs.getASTContext()) TupleElementExpr(expr, - expr->getLoc(), - 0, - expr->getLoc(), - fromTuple->getElementType(0))); - expr->setImplicit(true); - - // Coerce the element to the expected type. - return coerceToType(expr, toType, - locator.withPathElement( - LocatorPathElt::getTupleElement(0))); - } - case ConversionRestrictionKind::DeepEquality: llvm_unreachable("Equality handled above"); @@ -5905,7 +5852,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, auto toObjType = toType->getLValueOrInOutObjectType(); // Conversion to/from UnresolvedType (looking through @lvalue or inout). - if (fromObjType->is() || toObjType->is()) + if (fromObjType->hasUnresolvedType() || toObjType->hasUnresolvedType()) return cs.cacheType(new (tc.Context) UnresolvedTypeConversionExpr(expr, toType)); @@ -6330,13 +6277,86 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, TypeChecker &tc = cs.getTypeChecker(); auto fn = apply->getFn(); - + + auto finishApplyOfDeclWithSpecialTypeCheckingSemantics + = [&](ApplyExpr *apply, + ValueDecl *decl, + Type openedType) -> Expr* { + switch (cs.TC.getDeclTypeCheckingSemantics(decl)) { + case DeclTypeCheckingSemantics::TypeOf: { + // Resolve into a DynamicTypeExpr. + auto arg = apply->getArg(); + if (auto tuple = dyn_cast(arg)) + arg = tuple->getElements()[0]; + auto replacement = new (tc.Context) + DynamicTypeExpr(apply->getFn()->getLoc(), + apply->getArg()->getStartLoc(), + arg, + apply->getArg()->getEndLoc(), + Type()); + cs.setType(replacement, simplifyType(openedType)); + return replacement; + } + + case DeclTypeCheckingSemantics::WithoutActuallyEscaping: { + // Resolve into a MakeTemporarilyEscapingExpr. + auto arg = cast(apply->getArg()); + assert(arg->getNumElements() == 2 && "should have two arguments"); + auto nonescaping = arg->getElements()[0]; + auto body = arg->getElements()[1]; + auto bodyFnTy = body->getType()->castTo(); + auto escapableType = bodyFnTy->getInput(); + auto resultType = bodyFnTy->getResult(); + + // The body is immediately called, so is obviously noescape. + bodyFnTy = cast( + bodyFnTy->withExtInfo(bodyFnTy->getExtInfo().withNoEscape())); + body = coerceToType(body, bodyFnTy, locator); + assert(body && "can't make nonescaping?!"); + + auto escapable = new (tc.Context) + OpaqueValueExpr(apply->getFn()->getLoc(), Type()); + cs.setType(escapable, escapableType); + + auto callSubExpr = CallExpr::create(tc.Context, body, escapable, + {}, {}, + /*trailing closure*/ false, + /*implicit*/ true); + cs.setType(callSubExpr, resultType); + + auto replacement = new (tc.Context) + MakeTemporarilyEscapableExpr(apply->getFn()->getLoc(), + apply->getArg()->getStartLoc(), + nonescaping, + callSubExpr, + apply->getArg()->getEndLoc(), + escapable); + cs.setType(replacement, resultType); + return replacement; + } + + case DeclTypeCheckingSemantics::Normal: + return nullptr; + } + }; + // The function is always an rvalue. fn = cs.coerceToRValue(fn); assert(fn && "Rvalue conversion failed?"); if (!fn) return nullptr; + // Resolve applications of decls with special semantics. + if (auto declRef = + dyn_cast(getSemanticExprForDeclOrMemberRef(fn))) { + if (auto special = + finishApplyOfDeclWithSpecialTypeCheckingSemantics(apply, + declRef->getDecl(), + openedType)) { + return special; + } + } + // Handle applications that look through ImplicitlyUnwrappedOptional. if (auto fnTy = cs.lookThroughImplicitlyUnwrappedOptionalType(cs.getType(fn))) fn = coerceImplicitlyUnwrappedOptionalToValue(fn, fnTy, locator); @@ -6384,7 +6404,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, Expr *result = tc.substituteInputSugarTypeForResult(apply); // Try closing the existential, if there is one. - closeExistential(result); + closeExistential(result, locator); // If we have a covariant result type, perform the conversion now. if (covariantResultType) { diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 7484f04507cd2..e37867af1d9e5 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -1185,8 +1185,8 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, Type actualArgType, TypeSubstitutionMap &archetypesMap) { // Type visitor doesn't handle unresolved types. - if (paramType->hasUnresolvedType() || - actualArgType->hasUnresolvedType()) + if (isUnresolvedOrTypeVarType(paramType) || + isUnresolvedOrTypeVarType(actualArgType)) return false; class GenericVisitor : public TypeMatcher { @@ -1219,6 +1219,9 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, } }; + if (paramType->hasError()) + return false; + GenericVisitor visitor(dc, archetypesMap); return visitor.match(paramType, actualArgType); } @@ -1474,6 +1477,38 @@ CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, return { closeness, {}}; } +/// Rewrite any type parameters in the specified type with UnresolvedType. +static Type replaceTypeParametersWithUnresolved(Type ty) { + if (!ty) return ty; + + if (!ty->hasTypeParameter() && !ty->hasArchetype()) return ty; + + auto &ctx = ty->getASTContext(); + + return ty.transform([&](Type type) -> Type { + if (type->is() || + type->isTypeParameter()) + return ctx.TheUnresolvedType; + return type; + }); +} + +/// Rewrite any type variables & archetypes in the specified type with +/// UnresolvedType. +static Type replaceTypeVariablesWithUnresolved(Type ty) { + if (!ty) return ty; + + if (!ty->hasTypeVariable()) return ty; + + auto &ctx = ty->getASTContext(); + + return ty.transform([&](Type type) -> Type { + if (type->isTypeVariableOrMember()) + return ctx.TheUnresolvedType; + return type; + }); +} + void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, bool implicitDotSyntax) { fn = fn->getValueProvidingExpr(); @@ -1552,23 +1587,28 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, collectCalleeCandidates(AE->getFn(), /*implicitDotSyntax=*/AE->getMemberOperatorRef()); - // If this is a DotSyntaxCallExpr, then the callee is a method, and the - // argument list of this apply is the base being applied to the method. - // If we have a type for that, capture it so that we can calculate a - // substituted type, which resolves many generic arguments. - Type baseType; - if (isa(AE) && - !isUnresolvedOrTypeVarType(AE->getArg()->getType())) - baseType = AE->getArg()->getType()->getLValueOrInOutObjectType(); - // If we found a candidate list with a recursive walk, try adjust the curry // level for the applied subexpression in this call. if (!candidates.empty()) { + // If this is a DotSyntaxCallExpr, then the callee is a method, and the + // argument list of this apply is the base being applied to the method. + // If we have a type for that, capture it so that we can calculate a + // substituted type, which resolves many generic arguments. + Type baseType; + if (isa(AE) && + !isUnresolvedOrTypeVarType(AE->getArg()->getType())) + baseType = AE->getArg()->getType()->getLValueOrInOutObjectType(); + for (auto &C : candidates) { C.level += 1; + baseType = replaceTypeVariablesWithUnresolved(baseType); + // Compute a new substituted type if we have a base type to apply. if (baseType && C.level == 1 && C.getDecl()) { + baseType = baseType + ->getLValueOrInOutObjectType() + ->getRValueInstanceType(); C.entityType = baseType->getTypeOfMember(CS->DC->getParentModule(), C.getDecl(), nullptr); C.substituted = true; @@ -1755,22 +1795,19 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType, // it to get a simpler and more concrete type. // if (baseType) { - auto substType = baseType; + auto substType = replaceTypeVariablesWithUnresolved(baseType); + if (substType) + substType = substType + ->getLValueOrInOutObjectType() + ->getRValueInstanceType(); + // If this is a DeclViaUnwrappingOptional, then we're actually looking // through an optional to get the member, and baseType is an Optional or // Metatype. if (cand.getKind() == OverloadChoiceKind::DeclViaUnwrappedOptional) { - bool isMeta = false; - if (auto MTT = substType->getAs()) { - isMeta = true; - substType = MTT->getInstanceType(); - } - // Look through optional or IUO to get the underlying type the decl was // found in. substType = substType->getAnyOptionalObjectType(); - if (isMeta && substType) - substType = MetatypeType::get(substType); } else if (cand.getKind() != OverloadChoiceKind::Decl) { // Otherwise, if it is a remapping we can't handle, don't try to compute // a substitution. @@ -1984,12 +2021,16 @@ class FailureDiagnosis :public ASTVisitor{ /// This can return a new expression (for e.g. when a UnresolvedDeclRef gets /// resolved) and returns null when the subexpression fails to typecheck. /// - Expr *typeCheckChildIndependently(Expr *subExpr, Type convertType = Type(), - ContextualTypePurpose convertTypePurpose = CTP_Unused, - TCCOptions options = TCCOptions(), - ExprTypeCheckListener *listener = nullptr); - Expr *typeCheckChildIndependently(Expr *subExpr, TCCOptions options) { - return typeCheckChildIndependently(subExpr, Type(), CTP_Unused, options); + Expr *typeCheckChildIndependently( + Expr *subExpr, Type convertType = Type(), + ContextualTypePurpose convertTypePurpose = CTP_Unused, + TCCOptions options = TCCOptions(), + ExprTypeCheckListener *listener = nullptr, + bool allowFreeTypeVariables = true); + Expr *typeCheckChildIndependently(Expr *subExpr, TCCOptions options, + bool allowFreeTypeVariables = true) { + return typeCheckChildIndependently(subExpr, Type(), CTP_Unused, options, + nullptr, allowFreeTypeVariables); } Type getTypeOfTypeCheckedChildIndependently(Expr *subExpr, @@ -2288,8 +2329,8 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { anchor = typeCheckArbitrarySubExprIndependently(anchor, TCC_AllowLValue); if (!anchor) return true; - auto baseTy = anchor->getType(); - auto baseObjTy = baseTy->getRValueType(); + auto baseTy = anchor->getType()->getLValueOrInOutObjectType(); + auto baseObjTy = baseTy; // If the base type is an IUO, look through it. Odds are, the code is not // trying to find a member of it. @@ -2914,7 +2955,8 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ anchor = locator->getAnchor(); } - Type fromType = CS->simplifyType(constraint->getFirstType()); + Type fromType = CS->simplifyType(constraint->getFirstType()) + ->getWithoutImmediateLabel(); if (fromType->hasTypeVariable() && resolvedAnchorToExpr) { TCCOptions options; @@ -2931,7 +2973,8 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ } fromType = fromType->getRValueType(); - auto toType = CS->simplifyType(constraint->getSecondType()); + auto toType = CS->simplifyType(constraint->getSecondType()) + ->getWithoutImmediateLabel(); // Try to simplify irrelevant details of function types. For example, if // someone passes a "() -> Float" function to a "() throws -> Int" @@ -3060,7 +3103,8 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ // Due to migration reasons, types used to conform to BooleanType, which // contain a member var 'boolValue', now does not convert to Bool. This block // tries to add a specific diagnosis/fixit to explicitly invoke 'boolValue'. - if (toType->isBool()) { + if (toType->isBool() && + fromType->mayHaveMembers()) { auto LookupResult = CS->TC.lookupMember(CS->DC, fromType, DeclName(CS->TC.Context.getIdentifier("boolValue"))); if (!LookupResult.empty()) { @@ -3359,22 +3403,6 @@ static void eraseOpenedExistentials(Expr *&expr) { expr = expr->walk(ExistentialEraser()); } -/// Rewrite any type variables & archetypes in the specified type with -/// UnresolvedType. -static Type replaceArchetypesAndTypeVarsWithUnresolved(Type ty) { - if (!ty) return ty; - - auto &ctx = ty->getASTContext(); - - return ty.transform([&](Type type) -> Type { - if (type->isTypeVariableOrMember() || - type->is() || - type->isTypeParameter()) - return ctx.TheUnresolvedType; - return type; - }); -} - /// Unless we've already done this, retypecheck the specified subexpression on /// its own, without including any contextual constraints or parent expr /// nodes. This is more likely to succeed than type checking the original @@ -3382,12 +3410,11 @@ static Type replaceArchetypesAndTypeVarsWithUnresolved(Type ty) { /// /// This can return a new expression (for e.g. when a UnresolvedDeclRef gets /// resolved) and returns null when the subexpression fails to typecheck. -Expr *FailureDiagnosis:: -typeCheckChildIndependently(Expr *subExpr, Type convertType, - ContextualTypePurpose convertTypePurpose, - TCCOptions options, - ExprTypeCheckListener *listener) { - +Expr *FailureDiagnosis::typeCheckChildIndependently( + Expr *subExpr, Type convertType, ContextualTypePurpose convertTypePurpose, + TCCOptions options, ExprTypeCheckListener *listener, + bool allowFreeTypeVariables) { + // If this sub-expression is currently being diagnosed, refuse to recheck the // expression (which may lead to infinite recursion). If the client is // telling us that it knows what it is doing, then believe it. @@ -3408,9 +3435,8 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType, convertType = FT->getResult(); // Replace archetypes and type parameters with UnresolvedType. - if (convertType->hasTypeVariable() || convertType->hasArchetype() || - convertType->hasTypeParameter()) - convertType = replaceArchetypesAndTypeVarsWithUnresolved(convertType); + convertType = replaceTypeParametersWithUnresolved(convertType); + convertType = replaceTypeVariablesWithUnresolved(convertType); // If the conversion type contains no info, drop it. if (convertType->is() || @@ -3458,7 +3484,8 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType, // If there is no contextual type available, tell typeCheckExpression that it // is ok to produce an ambiguous result, it can just fill in holes with // UnresolvedType and we'll deal with it. - if (!convertType || options.contains(TCC_AllowUnresolvedTypeVariables)) + if ((!convertType || options.contains(TCC_AllowUnresolvedTypeVariables)) && + allowFreeTypeVariables) TCEOptions |= TypeCheckExprFlags::AllowUnresolvedTypeVariables; // If we're not passing down contextual type information this time, but the @@ -4290,6 +4317,59 @@ void ConstraintSystem::diagnoseAssignmentFailure(Expr *dest, Type destTy, diag::assignment_lhs_not_lvalue); } +//===----------------------------------------------------------------------===// +// Diagnose assigning variable to itself. +//===----------------------------------------------------------------------===// + +static Decl *findSimpleReferencedDecl(const Expr *E) { + if (auto *LE = dyn_cast(E)) + E = LE->getSubExpr(); + + if (auto *DRE = dyn_cast(E)) + return DRE->getDecl(); + + return nullptr; +} + +static std::pair findReferencedDecl(const Expr *E) { + E = E->getValueProvidingExpr(); + + if (auto *LE = dyn_cast(E)) + return findReferencedDecl(LE->getSubExpr()); + + if (auto *AE = dyn_cast(E)) + return findReferencedDecl(AE->getDest()); + + if (auto *D = findSimpleReferencedDecl(E)) + return std::make_pair(nullptr, D); + + if (auto *MRE = dyn_cast(E)) { + if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase())) + return std::make_pair(BaseDecl, MRE->getMember().getDecl()); + } + + return std::make_pair(nullptr, nullptr); +} + +bool TypeChecker::diagnoseSelfAssignment(const Expr *E) { + auto AE = dyn_cast(E); + if (!AE) + return false; + + auto LHSDecl = findReferencedDecl(AE->getDest()); + auto RHSDecl = findReferencedDecl(AE->getSrc()); + + if (LHSDecl.second && LHSDecl == RHSDecl) { + diagnose(AE->getLoc(), LHSDecl.first ? diag::self_assignment_prop + : diag::self_assignment_var) + .highlight(AE->getDest()->getSourceRange()) + .highlight(AE->getSrc()->getSourceRange()); + return true; + } + + return false; +} + static bool isSymmetricBinaryOperator(const CalleeCandidateInfo &CCI) { // If we don't have at least one known candidate, don't trigger. if (CCI.candidates.empty()) return false; @@ -4880,7 +4960,8 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, CallArgParam &arg = args[0]; auto resTy = candidate.getResultType()->lookThroughAllAnyOptionalTypes(); auto rawTy = isRawRepresentable(resTy, CCI.CS); - if (rawTy && resTy->getCanonicalType() == arg.Ty.getCanonicalTypeOrNull()) { + if (rawTy && arg.Ty && + resTy->getCanonicalType() == arg.Ty->getCanonicalType()) { auto getInnerExpr = [](Expr *E) -> Expr* { ParenExpr *parenE = dyn_cast(E); if (!parenE) @@ -6041,6 +6122,9 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) { return true; } + if (CS->TC.diagnoseSelfAssignment(assignExpr)) + return true; + // Type check the destination first, so we can coerce the source to it. auto destExpr = typeCheckChildIndependently(assignExpr->getDest(), TCC_AllowLValue); @@ -6048,13 +6132,21 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) { auto destType = destExpr->getType(); if (destType->is() || destType->hasTypeVariable()) { - // If we have no useful type information from the destination, just type + // Look closer into why destination has unresolved types since such + // means that destination has diagnosible structural problems, and it's + // better to diagnose destination (if possible) before moving on to + // the source of the assignment. + destExpr = typeCheckChildIndependently( + destExpr, TCC_AllowLValue | TCC_ForceRecheck, false); + if (!destExpr) + return true; + + // If re-checking destination didn't produce diagnostic, let's just type // check the source without contextual information. If it succeeds, then we // win, but if it fails, we'll have to diagnose this another way. return !typeCheckChildIndependently(assignExpr->getSrc()); } - - + // If the result type is a non-lvalue, then we are failing because it is // immutable and that's not a great thing to assign to. if (!destType->isLValueType()) { @@ -6337,9 +6429,15 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { llvm::SaveAndRestore SavedDC(CS->DC, CE); auto CTP = expectedResultType ? CTP_ClosureResult : CTP_Unused; - + + // Explicitly disallow to produce solutions with unresolved type variables, + // because there is no auxiliary logic which would handle that and it's + // better to allow failure diagnosis to run directly on the closure body. + // Note that presence of contextual type implicitly forbids such solutions, + // but it's not always reset. if (!typeCheckChildIndependently(CE->getSingleExpressionBody(), - expectedResultType, CTP)) + expectedResultType, CTP, TCCOptions(), + nullptr, false)) return true; } @@ -7190,25 +7288,56 @@ diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure) { llvm::SaveAndRestore SavedDC(CS->DC, closure); // Otherwise, we're ok to type check the subexpr. - Expr *returnedExpr = nullptr; - if (RS->hasResult()) - returnedExpr = - typeCheckChildIndependently(RS->getResult(), - TCC_AllowUnresolvedTypeVariables); + Type resultType; + if (RS->hasResult()) { + auto resultExpr = RS->getResult(); + ConcreteDeclRef decl = nullptr; + + // If return expression uses closure parameters, which have/are + // type variables, such means that we won't be be able to + // type-check result correctly and, unfornutately, + // we are going to leak type variables from the parent + // constraint system through declaration types. + bool hasUnresolvedParams = false; + resultExpr->forEachChildExpr([&](Expr *childExpr) -> Expr *{ + if (auto DRE = dyn_cast(resultExpr)) { + if (auto param = dyn_cast(DRE->getDecl())) { + auto paramType = param->getType(); + if (!paramType || paramType->hasTypeVariable()) { + hasUnresolvedParams = true; + return nullptr; + } + } + } + return childExpr; + }); + + if (hasUnresolvedParams) + continue; + + // Obtain type of the result expression without applying solutions, + // because otherwise this might result in leaking of type variables, + // since we are not reseting result statement and if expression is + // sucessfully type-checked its type cleanup is going to be disabled + // (we are allowing unresolved types), and as a side-effect it might + // also be transformed e.g. OverloadedDeclRefExpr -> DeclRefExpr. + auto type = CS->TC.getTypeOfExpressionWithoutApplying(resultExpr, + CS->DC, decl, FreeTypeVariableBinding::UnresolvedType); + if (type) + resultType = type.getValue(); + } // If we found a type, presuppose it was the intended result and insert a // fixit hint. - if (returnedExpr && returnedExpr->getType() && - !isUnresolvedOrTypeVarType(returnedExpr->getType())) { - - std::string resultType = returnedExpr->getType()->getString(); + if (resultType && !isUnresolvedOrTypeVarType(resultType)) { + std::string resultTypeStr = resultType->getString(); // If there is a location for an 'in' token, then the argument list was // specified somehow but no return type was. Insert a "-> ReturnType " // before the in token. if (closure->getInLoc().isValid()) { diagnose(closure->getLoc(), diag::cannot_infer_closure_result_type) - .fixItInsert(closure->getInLoc(), "-> " + resultType + " "); + .fixItInsert(closure->getInLoc(), "-> " + resultTypeStr + " "); return true; } @@ -7218,7 +7347,7 @@ diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure) { // // As such, we insert " () -> ReturnType in " right after the '{' that // starts the closure body. - auto insertString = " () -> " + resultType + " " + "in "; + auto insertString = " () -> " + resultTypeStr + " " + "in "; diagnose(closure->getLoc(), diag::cannot_infer_closure_result_type) .fixItInsertAfter(closure->getBody()->getLBraceLoc(), insertString); return true; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index e2805345275bd..1cb95c7dad1ff 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -71,6 +71,19 @@ static bool mergeRepresentativeEquivalenceClasses(ConstraintSystem &CS, auto rep2 = CS.getRepresentative(tyvar2); if (rep1 != rep2) { + auto fixedType2 = CS.getFixedType(rep2); + + // If the there exists fixed type associated with the second + // type variable, and we simply merge two types together it would + // mean that portion of the constraint graph previously associated + // with that (second) variable is going to be disconnected from its + // new equivalence class, which is going to lead to incorrect solutions, + // so we need to make sure to re-bind fixed to the new representative. + if (fixedType2) { + CS.addConstraint(ConstraintKind::Bind, fixedType2, rep1, + rep1->getImpl().getLocator()); + } + CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); return true; } @@ -137,7 +150,12 @@ namespace { // We'd like to look at the elements of arrays and dictionaries. isa(expr) || - isa(expr)) { + isa(expr) || + + // assignment expression can involve anonymous closure parameters + // as source and destination, so it's beneficial for diagnostics if + // we look at the assignment. + isa(expr)) { LinkedExprs.push_back(expr); return {false, expr}; } @@ -227,6 +245,11 @@ namespace { } } + if (auto FVE = dyn_cast(expr)) { + LTI.collectedTypes.insert(CS.getType(FVE).getPointer()); + return { false, expr }; + } + if (auto DRE = dyn_cast(expr)) { if (auto varDecl = dyn_cast(DRE->getDecl())) { if (varDecl->isAnonClosureParam()) { @@ -2588,7 +2611,7 @@ namespace { // Compute the type to which the source must be converted to allow // assignment to the destination. auto destTy = CS.computeAssignDestType(expr->getDest(), expr->getLoc()); - if (!destTy) + if (!destTy || destTy->getRValueType()->is()) return Type(); // The source must be convertible to the destination. @@ -2669,6 +2692,9 @@ namespace { Type visitOpenExistentialExpr(OpenExistentialExpr *expr) { llvm_unreachable("Already type-checked"); } + Type visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *expr) { + llvm_unreachable("Already type-checked"); + } Type visitEnumIsCaseExpr(EnumIsCaseExpr *expr) { // Should already be type-checked. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 697d5f4a68fd9..6157032f1d651 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -693,6 +693,7 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind, case ConstraintKind::Defaultable: case ConstraintKind::Disjunction: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::LiteralConformsTo: case ConstraintKind::OptionalObject: case ConstraintKind::SelfObjectOfProtocol: @@ -818,6 +819,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2, case ConstraintKind::Defaultable: case ConstraintKind::Disjunction: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::LiteralConformsTo: case ConstraintKind::OptionalObject: case ConstraintKind::SelfObjectOfProtocol: @@ -905,20 +907,6 @@ ConstraintSystem::matchScalarToTupleTypes(Type type1, TupleType *tuple2, locator.withPathElement(ConstraintLocator::ScalarToTuple)); } -ConstraintSystem::SolutionKind -ConstraintSystem::matchTupleToScalarTypes(TupleType *tuple1, Type type2, - ConstraintKind kind, TypeMatchOptions flags, - ConstraintLocatorBuilder locator) { - assert(tuple1->getNumElements() == 1 && "Wrong number of elements"); - assert(!tuple1->getElement(0).isVararg() && "Should not be variadic"); - - TypeMatchOptions subflags = getDefaultDecompositionOptions(flags); - return matchTypes(tuple1->getElementType(0), - type2, kind, subflags, - locator.withPathElement( - LocatorPathElt::getTupleElement(0))); -} - // Returns 'false' (i.e. no error) if it is legal to match functions with the // corresponding function type representations and the given match kind. static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1, @@ -945,6 +933,7 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1, case ConstraintKind::Defaultable: case ConstraintKind::Disjunction: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::LiteralConformsTo: case ConstraintKind::OptionalObject: case ConstraintKind::SelfObjectOfProtocol: @@ -1011,6 +1000,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, case ConstraintKind::Defaultable: case ConstraintKind::Disjunction: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::LiteralConformsTo: case ConstraintKind::OptionalObject: case ConstraintKind::SelfObjectOfProtocol: @@ -1437,6 +1427,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case ConstraintKind::Defaultable: case ConstraintKind::Disjunction: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::LiteralConformsTo: case ConstraintKind::OptionalObject: case ConstraintKind::SelfObjectOfProtocol: @@ -1684,15 +1675,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, } } - if (tuple1 && !tuplesWithMismatchedNames) { - // A single-element tuple can be a trivial subtype of a scalar. - if (tuple1->getNumElements() == 1 && - !tuple1->getElement(0).isVararg()) { - conversionsOrFixes.push_back( - ConversionRestrictionKind::TupleToScalar); - } - } - // Subclass-to-superclass conversion. if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass() && type2->getClassOrBoundGenericClass() && @@ -2004,18 +1986,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, // Allow '() -> T' to '() -> ()' and '() -> Never' to '() -> T' for closure // literals. - { - if (concrete && kind >= ConstraintKind::Subtype && - (type1->isUninhabited() || type2->isVoid())) { - SmallVector parts; - locator.getLocatorParts(parts); - - while (!parts.empty()) { - if (parts.back().getKind() == ConstraintLocator::ClosureResult) { - increaseScore(SK_FunctionConversion); - return SolutionKind::Solved; - } - parts.pop_back(); + if (auto elt = locator.last()) { + if (elt->getKind() == ConstraintLocator::ClosureResult) { + if (concrete && kind >= ConstraintKind::Subtype && + (type1->isUninhabited() || type2->isVoid())) { + increaseScore(SK_FunctionConversion); + return SolutionKind::Solved; } } } @@ -2668,9 +2644,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, return result; } - if (instanceTy->isTypeParameter()) - return MemberLookupResult(); - // Okay, start building up the result list. MemberLookupResult result; result.OverallResult = MemberLookupResult::HasResults; @@ -2700,7 +2673,12 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, result.ViableCandidates.push_back(OverloadChoice(baseTy, fieldIdx)); return result; } - + + if (auto *selfTy = instanceTy->getAs()) + instanceTy = selfTy->getSelfType(); + + if (!instanceTy->mayHaveMembers()) + return result; // If we have a simple name, determine whether there are argument // labels we can use to restrict the set of lookup results. @@ -2765,7 +2743,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, // extensions cannot yet define designated initializers. lookupOptions -= NameLookupFlags::PerformConformanceCheck; - LookupResult ctors = TC.lookupConstructors(DC, baseObjTy, lookupOptions); + LookupResult ctors = TC.lookupConstructors(DC, instanceTy, lookupOptions); if (!ctors) return result; // No result. @@ -2855,7 +2833,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, } // Look for members within the base. - LookupResult &lookup = lookupMember(baseObjTy, memberName); + LookupResult &lookup = lookupMember(instanceTy, memberName); // The set of directly accessible types, which is only used when // we're performing dynamic lookup into an existential type. @@ -3041,10 +3019,11 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, if (result.ViableCandidates.empty() && isMetatype && constraintKind == ConstraintKind::UnresolvedValueMember) { if (auto objectType = instanceTy->getAnyOptionalObjectType()) { - LookupResult &optionalLookup = lookupMember(MetatypeType::get(objectType), - memberName); - for (auto result : optionalLookup) - addChoice(result, /*bridged*/false, /*isUnwrappedOptional=*/true); + if (objectType->mayHaveMembers()) { + LookupResult &optionalLookup = lookupMember(objectType, memberName); + for (auto result : optionalLookup) + addChoice(result, /*bridged*/false, /*isUnwrappedOptional=*/true); + } } } @@ -3069,7 +3048,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, // This is only used for diagnostics, so always use KnownPrivate. lookupOptions |= NameLookupFlags::KnownPrivate; - auto lookup = TC.lookupMember(DC, baseObjTy->getCanonicalType(), + auto lookup = TC.lookupMember(DC, instanceTy, memberName, lookupOptions); for (auto cand : lookup) { // If the result is invalid, skip it. @@ -3485,6 +3464,60 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1, return SolutionKind::Error; } +ConstraintSystem::SolutionKind +ConstraintSystem::simplifyEscapableFunctionOfConstraint( + Type type1, Type type2, + TypeMatchOptions flags, + ConstraintLocatorBuilder locator) { + TypeMatchOptions subflags = getDefaultDecompositionOptions(flags); + + // Local function to form an unsolved result. + auto formUnsolved = [&] { + if (flags.contains(TMF_GenerateConstraints)) { + addUnsolvedConstraint( + Constraint::create(*this, ConstraintKind::EscapableFunctionOf, + type1, type2, + DeclName(), FunctionRefKind::Compound, + getConstraintLocator(locator))); + return SolutionKind::Solved; + } + + return SolutionKind::Unsolved; + }; + + + type2 = getFixedTypeRecursive(type2, flags, /*wantRValue=*/true); + if (auto fn2 = type2->getAs()) { + // We should have the noescape end of the relation. + if (!fn2->getExtInfo().isNoEscape()) + return SolutionKind::Error; + // Solve forward by binding the other type variable to the escapable + // variation of this type. + auto fn1 = fn2->withExtInfo(fn2->getExtInfo().withNoEscape(false)); + return matchTypes(type1, fn1, ConstraintKind::Bind, subflags, locator); + } + if (!type2->isTypeVariableOrMember()) + // We definitely don't have a function, so bail. + return SolutionKind::Error; + + type1 = getFixedTypeRecursive(type1, flags, /*wantRValue=*/true); + if (auto fn1 = type1->getAs()) { + // We should have the escaping end of the relation. + if (fn1->getExtInfo().isNoEscape()) + return SolutionKind::Error; + + // Solve backward by binding the other type variable to the noescape + // variation of this type. + auto fn2 = fn1->withExtInfo(fn1->getExtInfo().withNoEscape(true)); + return matchTypes(type2, fn2, ConstraintKind::Bind, subflags, locator); + } + if (!type1->isTypeVariableOrMember()) + // We definitely don't have a function, so bail. + return SolutionKind::Error; + + return formUnsolved(); +} + ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint( Type type1, @@ -3670,12 +3703,6 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( return matchScalarToTupleTypes(type1, type2->castTo(), matchKind, subflags, locator); - // for $< in { <, (T) $< U - case ConversionRestrictionKind::TupleToScalar: - return matchTupleToScalarTypes(type1->castTo(), type2, - matchKind, subflags, locator); - case ConversionRestrictionKind::DeepEquality: return matchDeepEqualityTypes(type1, type2, locator); @@ -3936,7 +3963,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( // T1 T1 getRValueType())) { + if (isAnyHashableType( + type1->getRValueType()->lookThroughAllAnyOptionalTypes())) { return SolutionKind::Error; } @@ -4114,6 +4142,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first, case ConstraintKind::DynamicTypeOf: return simplifyDynamicTypeOfConstraint(first, second, subflags, locator); + case ConstraintKind::EscapableFunctionOf: + return simplifyEscapableFunctionOfConstraint(first, second, + subflags, locator); + case ConstraintKind::ConformsTo: case ConstraintKind::LiteralConformsTo: case ConstraintKind::SelfObjectOfProtocol: @@ -4257,6 +4289,12 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { None, constraint.getLocator()); + case ConstraintKind::EscapableFunctionOf: + return simplifyEscapableFunctionOfConstraint(constraint.getFirstType(), + constraint.getSecondType(), + None, + constraint.getLocator()); + case ConstraintKind::BindOverload: resolveOverload(constraint.getLocator(), constraint.getFirstType(), constraint.getOverloadChoice()); diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 106d28a07cb6f..d2b26ade04a89 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -717,6 +717,7 @@ static bool shouldBindToValueType(Constraint *constraint) case ConstraintKind::OptionalObject: return false; case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::ValueMember: case ConstraintKind::UnresolvedValueMember: case ConstraintKind::Defaultable: @@ -846,6 +847,7 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs, continue; case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: // Constraints from which we can't do anything. // FIXME: Record this somehow? continue; @@ -1053,11 +1055,7 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs, type = funcTy->getResult(); } - if (auto tupleTy = type->getAs()) { - if (tupleTy->getNumElements() == 1 && - !tupleTy->getElement(0).isVararg()) - type = tupleTy->getElementType(0); - } + type = type->getWithoutImmediateLabel(); } // Don't deduce IUO types. diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index d3d79b648abd5..1e4d33cb18ef1 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -66,6 +66,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, case ConstraintKind::CheckedCast: case ConstraintKind::SelfObjectOfProtocol: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::OptionalObject: assert(!First.isNull()); assert(!Second.isNull()); @@ -162,6 +163,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const { case ConstraintKind::LiteralConformsTo: case ConstraintKind::CheckedCast: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::SelfObjectOfProtocol: case ConstraintKind::ApplicableFunction: case ConstraintKind::OptionalObject: @@ -238,6 +240,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { case ConstraintKind::SelfObjectOfProtocol: Out << " Self type of "; break; case ConstraintKind::ApplicableFunction: Out << " applicable fn "; break; case ConstraintKind::DynamicTypeOf: Out << " dynamicType type of "; break; + case ConstraintKind::EscapableFunctionOf: Out << " @escaping type of "; break; case ConstraintKind::OptionalObject: Out << " optional with object type "; break; case ConstraintKind::BindOverload: { @@ -344,8 +347,6 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) { return "[tuple-to-tuple]"; case ConversionRestrictionKind::ScalarToTuple: return "[scalar-to-tuple]"; - case ConversionRestrictionKind::TupleToScalar: - return "[tuple-to-scalar]"; case ConversionRestrictionKind::DeepEquality: return "[deep equality]"; case ConversionRestrictionKind::Superclass: @@ -467,6 +468,7 @@ gatherReferencedTypeVars(Constraint *constraint, case ConstraintKind::UnresolvedValueMember: case ConstraintKind::ValueMember: case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::OptionalObject: case ConstraintKind::Defaultable: constraint->getSecondType()->getTypeVariables(typeVars); diff --git a/lib/Sema/Constraint.h b/lib/Sema/Constraint.h index cf3c9762ed57f..5f6ad5e0cc3b1 100644 --- a/lib/Sema/Constraint.h +++ b/lib/Sema/Constraint.h @@ -123,6 +123,9 @@ enum class ConstraintKind : char { /// \brief The first type is an optional type whose object type is the second /// type, preserving lvalue-ness. OptionalObject, + /// \brief The first type is the same function type as the second type, but + /// made @escaping. + EscapableFunctionOf, }; /// \brief Classification of the different kinds of constraints. @@ -154,8 +157,6 @@ enum class ConversionRestrictionKind { TupleToTuple, /// Scalar-to-tuple conversion. ScalarToTuple, - /// Tuple-to-scalar conversion. - TupleToScalar, /// Deep equality comparison. DeepEquality, /// Subclass-to-superclass conversion. @@ -480,6 +481,7 @@ class Constraint final : public llvm::ilist_node, return ConstraintClassification::Member; case ConstraintKind::DynamicTypeOf: + case ConstraintKind::EscapableFunctionOf: case ConstraintKind::Defaultable: return ConstraintClassification::TypeProperty; diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 7dffed8dae275..9e67c7d44b88b 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -147,6 +147,8 @@ void ConstraintSystem::setMustBeMaterializableRecursive(Type type) "argument to setMustBeMaterializableRecursive may not be inherently " "non-materializable"); type = getFixedTypeRecursive(type, /*wantRValue=*/false); + type = type->lookThroughAllAnyOptionalTypes(); + if (auto typeVar = type->getAs()) { typeVar->getImpl().setMustBeMaterializable(getSavedBindings()); } else if (auto *tupleTy = type->getAs()) { @@ -212,10 +214,7 @@ LookupResult &ConstraintSystem::lookupMember(Type base, DeclName name) { result = std::move(lookup); // If we aren't performing dynamic lookup, we're done. - auto instanceTy = base->getRValueType(); - if (auto metaTy = instanceTy->getAs()) - instanceTy = metaTy->getInstanceType(); - auto protoTy = instanceTy->getAs(); + auto protoTy = base->getAs(); if (!*result || !protoTy || !protoTy->getDecl()->isSpecificProtocol( @@ -398,22 +397,26 @@ namespace { // Open up unbound generic types, turning them into bound generic // types with type variables for each parameter. if (auto unbound = type->getAs()) { - auto parentTy = unbound->getParent(); - if (parentTy) - parentTy = parentTy.transform(*this); - auto unboundDecl = unbound->getDecl(); if (unboundDecl->isInvalid()) return ErrorType::get(cs.getASTContext()); + auto parentTy = unbound->getParent(); + if (parentTy) { + parentTy = parentTy.transform(*this); + unbound = UnboundGenericType::get(unboundDecl, parentTy, + cs.getASTContext()); + } + // If the unbound decl hasn't been validated yet, we have a circular // dependency that isn't being diagnosed properly. if (!unboundDecl->getGenericSignature()) { cs.TC.diagnose(unboundDecl, diag::circular_reference); return ErrorType::get(type); } - - + + llvm::DenseMap unboundReplacements; + // Open up the generic type. cs.openGeneric(unboundDecl->getInnermostDeclContext(), unboundDecl->getDeclContext(), @@ -421,15 +424,15 @@ namespace { unboundDecl->getGenericRequirements(), /*skipProtocolSelfConstraint=*/false, locator, - replacements); + unboundReplacements); // Map the generic parameters to their corresponding type variables. llvm::SmallVector arguments; for (auto gp : unboundDecl->getInnermostGenericParamTypes()) { - assert(replacements.count(gp->getCanonicalType()) && + auto found = unboundReplacements.find(gp->getCanonicalType()); + assert(found != unboundReplacements.end() && "Missing generic parameter?"); - arguments.push_back(TypeLoc::withoutLoc( - replacements[gp->getCanonicalType()])); + arguments.push_back(TypeLoc::withoutLoc(found->second)); } // FIXME: For some reason we can end up with unbound->getDecl() @@ -551,6 +554,11 @@ Optional ConstraintSystem::isSetType(Type type) { } bool ConstraintSystem::isAnyHashableType(Type type) { + if (auto tv = type->getAs()) { + auto fixedType = getFixedType(tv); + return fixedType && isAnyHashableType(fixedType); + } + if (auto st = type->getAs()) { return st->getDecl() == TC.Context.getAnyHashableDecl(); } @@ -726,11 +734,16 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // If this is a method whose result type is dynamic Self, replace // DynamicSelf with the actual object type. - if (func->hasDynamicSelf()) { - Type selfTy = openedFnType->getInput()->getRValueInstanceType(); - openedType = openedType->replaceCovariantResultType( - selfTy, - func->getNumParameterLists()); + if (!func->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { + if (func->hasDynamicSelf()) { + Type selfTy = openedFnType->getInput()->getRValueInstanceType(); + openedType = openedType->replaceCovariantResultType( + selfTy, + func->getNumParameterLists()); + openedFnType = openedType->castTo(); + } + } else { + openedType = openedType->eraseDynamicSelfType(); openedFnType = openedType->castTo(); } @@ -747,8 +760,6 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, auto type = getTypeChecker().resolveTypeInContext(typeDecl, DC, TR_InExpression, isSpecialized); - if (!type) - return { nullptr, nullptr }; // Open the type. type = openType(type, locator, replacements); @@ -916,7 +927,10 @@ void ConstraintSystem::openGeneric( auto typeVar = createTypeVariable(locatorPtr, TVO_PrefersSubtypeBinding | TVO_MustBeMaterializable); - replacements[gp->getCanonicalType()] = typeVar; + auto result = replacements.insert( + std::make_pair(gp->getCanonicalType(), typeVar)); + assert(result.second); + (void) result; } ReplaceDependentTypes replaceDependentTypes(*this, locator, replacements); @@ -1038,50 +1052,13 @@ ConstraintSystem::getTypeOfMemberReference( // Handle associated type lookup as a special case, horribly. // FIXME: This is an awful hack. - if (auto assocType = dyn_cast(value)) { - // Error recovery path. - if (baseObjTy->isOpenedExistential()) { - Type memberTy = ErrorType::get(TC.Context); - auto openedType = FunctionType::get(baseObjTy, memberTy); - return { openedType, memberTy }; - } - + if (isa(value)) { // Refer to a member of the archetype directly. - if (auto archetype = baseObjTy->getAs()) { - Type memberTy = archetype->getNestedType(value->getName()); - if (!isTypeReference) - memberTy = MetatypeType::get(memberTy); - - auto openedType = FunctionType::get(baseObjTy, memberTy); - return { openedType, memberTy }; - } - - // If we have a nominal type that conforms to the protocol in which the - // associated type resides, use the witness. - if (!baseObjTy->isExistentialType() && - baseObjTy->getAnyNominal()) { - auto proto = cast(assocType->getDeclContext()); - if (auto conformance = - TC.conformsToProtocol(baseObjTy, proto, DC, - ConformanceCheckFlags::InExpression)) { - if (conformance->isConcrete()) { - auto memberTy = conformance->getConcrete()->getTypeWitness(assocType, - &TC) - .getReplacement(); - if (!isTypeReference) - memberTy = MetatypeType::get(memberTy); - - auto openedType = FunctionType::get(baseObjTy, memberTy); - return { openedType, memberTy }; - } - } - } + auto archetype = baseObjTy->castTo(); + Type memberTy = archetype->getNestedType(value->getName()); + if (!isTypeReference) + memberTy = MetatypeType::get(memberTy); - // FIXME: Totally bogus fallthrough. - Type memberTy = isTypeReference - ? assocType->getDeclaredInterfaceType() - : assocType->getInterfaceType(); - memberTy = assocType->getProtocol()->mapTypeIntoContext(memberTy); auto openedType = FunctionType::get(baseObjTy, memberTy); return { openedType, memberTy }; } @@ -1165,28 +1142,22 @@ ConstraintSystem::getTypeOfMemberReference( } } - // If this is a method whose result type has a dynamic Self return, replace - // DynamicSelf with the actual object type. - if (auto func = dyn_cast(value)) { - if (func->hasDynamicSelf() || - (baseObjTy->isExistentialType() && - func->hasArchetypeSelf())) { - openedType = openedType->replaceCovariantResultType( - baseObjTy, - func->getNumParameterLists()); + if (!outerDC->getAsProtocolOrProtocolExtensionContext()) { + if (auto func = dyn_cast(value)) { + if ((isa(func) && + cast(func)->hasDynamicSelf()) || + (isa(func) && + !baseObjTy->getAnyOptionalObjectType())) { + openedType = openedType->replaceCovariantResultType( + baseObjTy, + func->getNumParameterLists()); + } } - } - // If this is an initializer, replace the result type with the base - // object type. - else if (auto ctor = dyn_cast(value)) { - auto resultTy = baseObjTy; - if (ctor->getFailability() != OTK_None) - resultTy = OptionalType::get(ctor->getFailability(), resultTy); - - openedType = openedType->replaceCovariantResultType( - resultTy, - /*uncurryLevel=*/ 2, - /*preserveOptionality=*/ false); + } else { + // Protocol requirements returning Self have a dynamic Self return + // type. Erase the dynamic Self since it only comes into play during + // protocol conformance checking. + openedType = openedType->eraseDynamicSelfType(); } // If we are looking at a member of an existential, open the existential. @@ -1230,29 +1201,6 @@ ConstraintSystem::getTypeOfMemberReference( } type = FunctionType::get(fnType->getInput(), elementTy); - } else if (isa(outerDC) && - isa(value)) { - // When we have an associated type, the base type conforms to the - // given protocol, so use the type witness directly. - // FIXME: Diagnose existentials properly. - auto proto = cast(outerDC); - auto assocType = cast(value); - - type = openedFnType->getResult(); - if (baseOpenedTy->is()) { - // For an archetype, we substitute the base object for the base. - // FIXME: Feels like a total hack. - } else if (!baseOpenedTy->isExistentialType() && - !baseOpenedTy->is()) { - if (auto conformance = - TC.conformsToProtocol(baseOpenedTy, proto, DC, - ConformanceCheckFlags::InExpression)) { - if (conformance->isConcrete()) { - type = conformance->getConcrete()->getTypeWitness(assocType, &TC) - .getReplacement(); - } - } - } } else if (!value->isInstanceMember() || isInstance) { // For a constructor, enum element, static method, static property, // or an instance method referenced through an instance, we've consumed the @@ -1274,6 +1222,27 @@ ConstraintSystem::getTypeOfMemberReference( type = openedFnType->replaceSelfParameterType(baseObjTy); } + // When accessing members of an existential, replace the 'Self' type + // parameter with the existential type, since formally the access will + // operate on existentials and not type parameters. + if (!isDynamicResult && baseObjTy->isExistentialType()) { + auto selfTy = replacements[outerDC->getSelfInterfaceType() + ->getCanonicalType()]; + auto existentialTy = outerDC->getDeclaredTypeOfContext(); + + type = type.transform([&](Type t) -> Type { + if (auto *selfTy = t->getAs()) + t = selfTy->getSelfType(); + if (t->is()) + if (t->isEqual(selfTy)) + return existentialTy; + if (auto *metatypeTy = t->getAs()) + if (metatypeTy->getInstanceType()->isEqual(selfTy)) + return ExistentialMetatypeType::get(existentialTy); + return t; + }); + } + // If we opened up any type variables, record the replacements. recordOpenedTypes(locator, replacements); @@ -1319,23 +1288,105 @@ void ConstraintSystem::addOverloadSet(Type boundType, addDisjunctionConstraint(overloads, locator, ForgetChoice, favoredChoice); } +/// If we're resolving an overload set with a decl that has special type +/// checking semantics, set up the special-case type system and return true; +/// otherwise return false. +static bool +resolveOverloadForDeclWithSpecialTypeCheckingSemantics(ConstraintSystem &CS, + ConstraintLocator *locator, + Type boundType, + OverloadChoice choice, + Type &refType, + Type &openedFullType) { + assert(choice.getKind() == OverloadChoiceKind::Decl); + + switch (CS.TC.getDeclTypeCheckingSemantics(choice.getDecl())) { + case DeclTypeCheckingSemantics::Normal: + return false; + + case DeclTypeCheckingSemantics::TypeOf: { + // Proceed with a "DynamicType" operation. This produces an existential + // metatype from existentials, or a concrete metatype from non- + // existentials (as seen from the current abstraction level), which can't + // be expressed in the type system currently. + auto input = CS.createTypeVariable( + CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), 0); + auto output = CS.createTypeVariable( + CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult), 0); + + auto inputArg = TupleTypeElt(input, CS.getASTContext().getIdentifier("of")); + auto inputTuple = TupleType::get(inputArg, CS.getASTContext()); + + CS.addConstraint(ConstraintKind::DynamicTypeOf, output, input, + CS.getConstraintLocator(locator, ConstraintLocator::RvalueAdjustment)); + refType = FunctionType::get(inputTuple, output); + openedFullType = refType; + return true; + } + case DeclTypeCheckingSemantics::WithoutActuallyEscaping: { + // Proceed with a "WithoutActuallyEscaping" operation. The body closure + // receives a copy of the argument closure that is temporarily made + // @escaping. + auto noescapeClosure = CS.createTypeVariable( + CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), 0); + auto escapeClosure = CS.createTypeVariable( + CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), 0); + CS.addConstraint(ConstraintKind::EscapableFunctionOf, + escapeClosure, noescapeClosure, + CS.getConstraintLocator(locator, ConstraintLocator::RvalueAdjustment)); + auto result = CS.createTypeVariable( + CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult), 0); + auto bodyClosure = FunctionType::get( + ParenType::get(CS.getASTContext(), escapeClosure), result, + FunctionType::ExtInfo(FunctionType::Representation::Swift, + /*autoclosure*/ false, + /*noescape*/ true, + /*throws*/ true)); + TupleTypeElt argTupleElts[] = { + TupleTypeElt(noescapeClosure), + TupleTypeElt(bodyClosure, CS.getASTContext().getIdentifier("do")), + }; + + auto argTuple = TupleType::get(argTupleElts, CS.getASTContext()); + refType = FunctionType::get(argTuple, result, + FunctionType::ExtInfo(FunctionType::Representation::Swift, + /*autoclosure*/ false, + /*noescape*/ false, + /*throws*/ true)); + openedFullType = refType; + return true; + } + } +} + void ConstraintSystem::resolveOverload(ConstraintLocator *locator, Type boundType, OverloadChoice choice) { // Determine the type to which we'll bind the overload set's type. Type refType; Type openedFullType; - switch (choice.getKind()) { - case OverloadChoiceKind::DeclViaBridge: + switch (auto kind = choice.getKind()) { case OverloadChoiceKind::Decl: + // If we refer to a top-level decl with special type-checking semantics, + // handle it now. + if (resolveOverloadForDeclWithSpecialTypeCheckingSemantics( + *this, locator, boundType, choice, refType, openedFullType)) + break; + + SWIFT_FALLTHROUGH; + + case OverloadChoiceKind::DeclViaBridge: case OverloadChoiceKind::DeclViaDynamic: case OverloadChoiceKind::DeclViaUnwrappedOptional: case OverloadChoiceKind::TypeDecl: { + bool isTypeReference = choice.getKind() == OverloadChoiceKind::TypeDecl; bool isDynamicResult = choice.getKind() == OverloadChoiceKind::DeclViaDynamic; // Retrieve the type of a reference to the specific declaration choice. - if (choice.getBaseType()) { + if (auto baseTy = choice.getBaseType()) { + assert(!baseTy->hasTypeParameter()); + auto getDotBase = [](const Expr *E) -> const DeclRefExpr * { if (E == nullptr) return nullptr; switch (E->getKind()) { @@ -1354,7 +1405,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, auto anchor = locator ? locator->getAnchor() : nullptr; auto base = getDotBase(anchor); std::tie(openedFullType, refType) - = getTypeOfMemberReference(choice.getBaseType(), choice.getDecl(), + = getTypeOfMemberReference(baseTy, choice.getDecl(), isTypeReference, isDynamicResult, choice.getFunctionRefKind(), locator, base, nullptr); @@ -1414,7 +1465,6 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, } break; } - assert(!refType->hasTypeParameter() && "Cannot have a dependent type here"); // If we're binding to an init member, the 'throws' need to line up between @@ -1515,15 +1565,7 @@ Type ConstraintSystem::simplifyType(Type type) { if (newBase.getPointer() == depMemTy->getBase().getPointer()) return type; - Type lookupBaseType = newBase; - - // Look through an inout type. - if (auto inout = lookupBaseType->getAs()) - lookupBaseType = inout->getObjectType(); - - // Look through a metatype. - if (auto metatype = lookupBaseType->getAs()) - lookupBaseType = metatype->getInstanceType(); + Type lookupBaseType = newBase->getLValueOrInOutObjectType(); // If the new base is still something we can't handle, just build a // new dependent member type. @@ -1539,9 +1581,12 @@ Type ConstraintSystem::simplifyType(Type type) { auto assocType = depMemTy->getAssocType(); assert(depMemTy->getAssocType()); - auto result = lookupBaseType->getTypeOfMember( - DC->getParentModule(), assocType, &TC, - assocType->getDeclaredInterfaceType()); + if (!lookupBaseType->mayHaveMembers()) return type; + + auto result = assocType->getDeclaredInterfaceType() + .subst(DC->getParentModule(), + lookupBaseType->getContextSubstitutions( + assocType->getDeclContext())); // FIXME: Record failure somehow? if (!result) return type; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 69c5254dd7179..e79e4901f1a49 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -2007,15 +2007,6 @@ class ConstraintSystem { TypeMatchOptions flags, ConstraintLocatorBuilder locator); - /// \brief Subroutine of \c matchTypes(), which extracts a scalar value from - /// a single-element tuple type. - /// - /// \returns the result of performing the tuple-to-scalar conversion. - SolutionKind matchTupleToScalarTypes(TupleType *tuple1, Type type2, - ConstraintKind kind, - TypeMatchOptions flags, - ConstraintLocatorBuilder locator); - /// \brief Subroutine of \c matchTypes(), which matches up two function /// types. SolutionKind matchFunctionTypes(FunctionType *func1, FunctionType *func2, @@ -2194,6 +2185,12 @@ class ConstraintSystem { TypeMatchOptions flags, ConstraintLocatorBuilder locator); + /// \brief Attempt to simplify the given EscapableFunctionOf constraint. + SolutionKind simplifyEscapableFunctionOfConstraint( + Type type1, Type type2, + TypeMatchOptions flags, + ConstraintLocatorBuilder locator); + /// \brief Attempt to simplify the given defaultable constraint. SolutionKind simplifyDefaultableConstraint(Type first, Type second, TypeMatchOptions flags, diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index d98f637ede4cf..7b41864ac4183 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -132,7 +132,7 @@ static void deriveBodyEquatable_enum_eq(AbstractFunctionDecl *eqDecl) { auto aParam = args->get(0); auto bParam = args->get(1); - CanType boolTy = C.getBoolDecl()->getDeclaredType().getCanonicalTypeOrNull(); + auto boolTy = C.getBoolDecl()->getDeclaredType(); auto enumDecl = cast(aParam->getType()->getAnyNominal()); diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index d8cdf7ea8f9c3..1ef1b1562120e 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -38,52 +38,6 @@ static Expr *isImplicitPromotionToOptional(Expr *E) { return nullptr; } -//===----------------------------------------------------------------------===// -// Diagnose assigning variable to itself. -//===----------------------------------------------------------------------===// - -static Decl *findSimpleReferencedDecl(const Expr *E) { - if (auto *LE = dyn_cast(E)) - E = LE->getSubExpr(); - - if (auto *DRE = dyn_cast(E)) - return DRE->getDecl(); - - return nullptr; -} - -static std::pair findReferencedDecl(const Expr *E) { - if (auto *LE = dyn_cast(E)) - E = LE->getSubExpr(); - - if (auto *D = findSimpleReferencedDecl(E)) - return std::make_pair(nullptr, D); - - if (auto *MRE = dyn_cast(E)) { - if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase())) - return std::make_pair(BaseDecl, MRE->getMember().getDecl()); - } - - return std::make_pair(nullptr, nullptr); -} - -/// Diagnose assigning variable to itself. -static void diagSelfAssignment(TypeChecker &TC, const Expr *E) { - auto *AE = dyn_cast(E); - if (!AE) - return; - - auto LHSDecl = findReferencedDecl(AE->getDest()); - auto RHSDecl = findReferencedDecl(AE->getSrc()); - if (LHSDecl.second && LHSDecl == RHSDecl) { - TC.diagnose(AE->getLoc(), LHSDecl.first ? diag::self_assignment_prop - : diag::self_assignment_var) - .highlight(AE->getDest()->getSourceRange()) - .highlight(AE->getSrc()->getSourceRange()); - } -} - - /// Diagnose syntactic restrictions of expressions. /// /// - Module values may only occur as part of qualification. @@ -258,6 +212,9 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // Verify warn_unqualified_access uses. checkUnqualifiedAccessUse(DRE); + + // Verify that special decls are eliminated. + checkForDeclWithSpecialTypeCheckingSemantics(DRE); } if (auto *MRE = dyn_cast(Base)) { if (isa(MRE->getMember().getDecl())) @@ -273,6 +230,12 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, AcceptableInOutExprs.insert(IOE); } + // Check decl refs in withoutActuallyEscaping blocks. + if (auto MakeEsc = dyn_cast(E)) { + if (auto DRE = + dyn_cast(MakeEsc->getNonescapingClosureValue())) + checkNoEscapeParameterUse(DRE, MakeEsc); + } // Check function calls, looking through implicit conversions on the // function and inspecting the arguments directly. @@ -365,7 +328,13 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // Diagnose 'self.init' or 'super.init' nested in another expression. if (auto *rebindSelfExpr = dyn_cast(E)) { - if (!Parent.isNull() || !IsExprStmt) { + bool inDefer = false; + auto *innerDecl = DC->getInnermostDeclarationDeclContext(); + if (auto *FD = dyn_cast_or_null(innerDecl)) { + inDefer = FD->isDeferBody(); + } + + if (!Parent.isNull() || !IsExprStmt || inDefer) { bool isChainToSuper; (void)rebindSelfExpr->getCalledConstructor(isChainToSuper); TC.diagnose(E->getLoc(), diag::init_delegation_nested, @@ -478,8 +447,11 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // The only valid use of the noescape parameter is an immediate call, // either as the callee or as an argument (in which case, the typechecker - // validates that the noescape bit didn't get stripped off). - if (ParentExpr && isa(ParentExpr)) // param() + // validates that the noescape bit didn't get stripped off), or as + // a special case, in the binding of a withoutActuallyEscaping block. + if (ParentExpr + && (isa(ParentExpr) // param() + || isa(ParentExpr))) return; TC.diagnose(DRE->getStartLoc(), diag::invalid_noescape_use, @@ -547,14 +519,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // Add fix-it to insert '()', only if this is a metatype of // non-existential type and has any initializers. + auto eTy = E->getType(); bool isExistential = false; - if (auto metaTy = E->getType()->getAs()) - isExistential = metaTy->getInstanceType()->isAnyExistentialType(); - if (!isExistential && - !TC.lookupConstructors(const_cast(DC), - E->getType()).empty()) { - TC.diagnose(E->getEndLoc(), diag::add_parens_to_type) - .fixItInsertAfter(E->getEndLoc(), "()"); + if (auto metaTy = E->getType()->getAs()) { + auto instanceTy = metaTy->getInstanceType(); + isExistential = instanceTy->isExistentialType(); + if (!isExistential && + instanceTy->mayHaveMembers() && + !TC.lookupConstructors(const_cast(DC), + instanceTy).empty()) { + TC.diagnose(E->getEndLoc(), diag::add_parens_to_type) + .fixItInsertAfter(E->getEndLoc(), "()"); + } } // Add fix-it to insert ".self". @@ -639,6 +615,17 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, } } + 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 + // special-case behavior in a closure someday... + if (TC.getDeclTypeCheckingSemantics(DRE->getDecl()) + != DeclTypeCheckingSemantics::Normal) { + TC.diagnose(DRE->getLoc(), diag::unsupported_special_decl_ref, + DRE->getDecl()->getName()); + } + } + /// Return true if this is 'nil' type checked as an Optional. This looks /// like this: /// (call_expr implicit type='Int?' @@ -3335,7 +3322,8 @@ class ObjCSelectorWalker : public ASTWalker { auto nominal = method->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext(); auto result = TC.lookupMember(const_cast(DC), - nominal->getInterfaceType(), lookupName, + nominal->getDeclaredInterfaceType(), + lookupName, (defaultMemberLookupOptions | NameLookupFlags::KnownPrivate)); @@ -3802,7 +3790,7 @@ static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E, void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E, const DeclContext *DC, bool isExprStmt) { - diagSelfAssignment(TC, E); + TC.diagnoseSelfAssignment(E); diagSyntacticUseRestrictions(TC, E, DC, isExprStmt); diagRecursivePropertyAccess(TC, E, DC); diagnoseImplicitSelfUseInClosure(TC, E, DC); diff --git a/lib/Sema/OverloadChoice.h b/lib/Sema/OverloadChoice.h index cc3b2f0532911..2acba780cb600 100644 --- a/lib/Sema/OverloadChoice.h +++ b/lib/Sema/OverloadChoice.h @@ -89,7 +89,7 @@ class OverloadChoice { llvm::PointerIntPair BaseAndBits; /// \brief Either the declaration pointer (if the low bit is clear) or the - /// overload choice kind shifted by 1 with the low bit set. + /// overload choice kind shifted two bits with the low bit set. uintptr_t DeclOrKind; /// The kind of function reference. @@ -105,6 +105,7 @@ class OverloadChoice { FunctionRefKind functionRefKind) : BaseAndBits(base, isSpecialized ? IsSpecializedBit : 0), TheFunctionRefKind(functionRefKind) { + assert(!base || !base->hasTypeParameter()); assert((reinterpret_cast(value) & (uintptr_t)0x03) == 0 && "Badly aligned decl"); @@ -115,6 +116,7 @@ class OverloadChoice { FunctionRefKind functionRefKind) : BaseAndBits(base, isSpecialized ? IsSpecializedBit : 0), TheFunctionRefKind(functionRefKind) { + assert(!base || !base->hasTypeParameter()); assert((reinterpret_cast(type) & (uintptr_t)0x03) == 0 && "Badly aligned decl"); DeclOrKind = reinterpret_cast(type) | 0x01; @@ -125,6 +127,7 @@ class OverloadChoice { DeclOrKind((uintptr_t)kind << 2 | (uintptr_t)0x03), TheFunctionRefKind(FunctionRefKind::Unapplied) { assert(base && "Must have a base type for overload choice"); + assert(!base->hasTypeParameter()); assert(kind != OverloadChoiceKind::Decl && kind != OverloadChoiceKind::DeclViaDynamic && kind != OverloadChoiceKind::TypeDecl && diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index e4136a55d13f0..aaa371b7e5ce9 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1152,14 +1152,13 @@ void AttributeChecker::checkApplicationMainAttribute(DeclAttribute *attr, ProtocolDecl *ApplicationDelegateProto = nullptr; if (KitModule) { auto lookupOptions = defaultUnqualifiedLookupOptions; - lookupOptions |= NameLookupFlags::OnlyTypes; lookupOptions |= NameLookupFlags::KnownPrivate; - auto lookup = TC.lookupUnqualified(KitModule, Id_ApplicationDelegate, - SourceLoc(), - lookupOptions); - ApplicationDelegateProto = dyn_cast_or_null( - lookup.getSingleTypeResult()); + auto lookup = TC.lookupUnqualifiedType(KitModule, Id_ApplicationDelegate, + SourceLoc(), + lookupOptions); + if (lookup.size() == 1) + ApplicationDelegateProto = dyn_cast(lookup[0]); } if (!ApplicationDelegateProto || diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 4ed76ac745dd0..3428a476ea562 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -49,9 +49,20 @@ class FindCapturedVars : public ASTWalker { DynamicSelfCaptureLoc(DynamicSelfCaptureLoc), DynamicSelf(DynamicSelf), AFR(AFR) { - if (auto AFD = AFR.getAbstractFunctionDecl()) - CaptureLoc = AFD->getLoc(); - else { + if (auto AFD = AFR.getAbstractFunctionDecl()) { + if (auto *FD = dyn_cast(AFD)) { + if (FD->isDeferBody()) { + // HACK: Defer statements generate implicit FuncDecls, and hence do + // not have valid source locations. Instead, use the location of + // the body. + CaptureLoc = FD->getBody()->getLBraceLoc(); + } else { + CaptureLoc = AFD->getLoc(); + } + } else { + CaptureLoc = AFD->getLoc(); + } + } else { auto ACE = AFR.getAbstractClosureExpr(); if (auto closure = dyn_cast(ACE)) CaptureLoc = closure->getInLoc(); @@ -658,7 +669,7 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { AFR.getBody()->walk(finder); unsigned inoutCount = 0; - for (auto C: Captures) { + for (auto C : Captures) { if (auto PD = dyn_cast(C.getDecl())) if (PD->hasType()) if (auto type = PD->getType()) @@ -668,12 +679,12 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { if (inoutCount > 0) { if (auto e = AFR.getAbstractFunctionDecl()) { - for (auto returnOccurrence: getEscapingFunctionAsReturnValue(e)) { + for (auto returnOccurrence : getEscapingFunctionAsReturnValue(e)) { diagnose(returnOccurrence->getReturnLoc(), diag::nested_function_escaping_inout_capture); } auto occurrences = getEscapingFunctionAsArgument(e); - for (auto occurrence: occurrences) { + for (auto occurrence : occurrences) { diagnose(occurrence->getLoc(), diag::nested_function_with_implicit_capture_argument, inoutCount > 1); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 633ab2076c66a..e1fd79aa63fc2 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2048,17 +2048,17 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) { // types of existentials. // // We will diagnose it later. - if (!sequenceType->isExistentialType()) { + if (!sequenceType->isExistentialType() && + (sequenceType->mayHaveMembers() || + sequenceType->isTypeVariableOrMember())) { ASTContext &ctx = tc.Context; auto iteratorAssocType = cast( sequenceProto->lookupDirect(ctx.Id_Iterator).front()); - iteratorType = sequenceType->getTypeOfMember( - cs.DC->getParentModule(), - iteratorAssocType, - &tc, - iteratorAssocType->getDeclaredInterfaceType()); + iteratorType = iteratorAssocType->getDeclaredInterfaceType() + .subst(cs.DC->getParentModule(), + sequenceType->getContextSubstitutions(sequenceProto)); if (iteratorType) { auto iteratorProto = @@ -2147,7 +2147,7 @@ Type ConstraintSystem::computeAssignDestType(Expr *dest, SourceLoc equalLoc) { } Type destTy = simplifyType(getType(dest)); - if (destTy->hasError() || destTy->getRValueType()->is()) + if (destTy->hasError()) return Type(); // If we have already resolved a concrete lvalue destination type, return it. @@ -2159,8 +2159,10 @@ Type ConstraintSystem::computeAssignDestType(Expr *dest, SourceLoc equalLoc) { // @lvalue T, where T is a fresh type variable that will be the object type of // this particular expression type. if (auto typeVar = dyn_cast(destTy.getPointer())) { + // Newly allocated type should be explicitly materializable, + // it's invalid to use non-materializable types as assignment destination. auto objectTv = createTypeVariable(getConstraintLocator(dest), - /*options=*/0); + TVO_MustBeMaterializable); auto refTv = LValueType::get(objectTv); addConstraint(ConstraintKind::Bind, typeVar, refTv, getConstraintLocator(dest)); @@ -2926,9 +2928,10 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, llvm_unreachable("suppressing diagnostics"); case CheckedCastContextKind::ForcedCast: { + std::string extraFromOptionalsStr(extraFromOptionals, '!'); auto diag = diagnose(diagLoc, diag::downcast_same_type, origFromType, origToType, - std::string(extraFromOptionals, '!'), + extraFromOptionalsStr, isBridged); diag.highlight(diagFromRange); diag.highlight(diagToRange); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 7f30f7710b163..1d82bf30828bf 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1136,19 +1136,18 @@ static void recordSelfContextType(AbstractFunctionDecl *func) { namespace { class AccessScopeChecker { - ASTContext &Context; const SourceFile *File; TypeChecker::TypeAccessScopeCacheMap &Cache; protected: - Optional Scope; + ASTContext &Context; + Optional Scope = AccessScope::getPublic(); AccessScopeChecker(const DeclContext *useDC, decltype(TypeChecker::TypeAccessScopeCache) &caches) - : Context(useDC->getASTContext()), - File(useDC->getParentSourceFile()), + : File(useDC->getParentSourceFile()), Cache(caches[File]), - Scope(AccessScope::getPublic()) {} + Context(File->getASTContext()) {} bool visitDecl(ValueDecl *VD, bool isInParameter = false) { if (!VD || isa(VD)) @@ -1211,6 +1210,17 @@ class TypeReprAccessScopeChecker : private ASTWalker, AccessScopeChecker { bool walkToTypeReprPre(TypeRepr *TR) override { if (auto CITR = dyn_cast(TR)) { + // In Swift 3, components other than the last one were not properly + // checked for availability. + // FIXME: We should try to downgrade these errors to warnings, not just + // skip diagnosing them. + if (Context.LangOpts.isSwiftVersion3()) { + const TypeRepr *parent = Parent.getAsTypeRepr(); + if (auto *compound = dyn_cast_or_null(parent)) + if (compound->Components.back() != CITR) + return true; + } + return visitDecl(CITR->getBoundDecl(), isParamParent(Parent.getAsTypeRepr())); } @@ -2488,11 +2498,11 @@ static void inferObjCName(TypeChecker &tc, ValueDecl *decl) { if (requirementObjCName) { if (attr) const_cast(attr)->setName(*requirementObjCName, - /*implicitName=*/true); + /*implicit=*/true); else decl->getAttrs().add( ObjCAttr::create(tc.Context, *requirementObjCName, - /*isNameImplicit=*/true)); + /*implicitName=*/true)); } } @@ -2891,7 +2901,7 @@ static void checkVarBehavior(VarDecl *decl, TypeChecker &TC) { auto behaviorSelf = conformance->getType(); auto behaviorInterfaceSelf = conformance->getInterfaceType(); auto behaviorProto = conformance->getProtocol(); - auto behaviorProtoTy = ProtocolType::get(behaviorProto, TC.Context); + auto behaviorProtoTy = behaviorProto->getDeclaredType(); // Treat any inherited protocols as constraints on `Self`, and gather // conformances from the containing type. @@ -3547,7 +3557,7 @@ class DeclChecker : public DeclVisitor { } } - if (IsSecondPass && !IsFirstPass) { + if (!IsFirstPass) { TC.checkUnsupportedProtocolType(decl); if (auto nominal = dyn_cast(decl)) { TC.checkDeclCircularity(nominal); @@ -3922,14 +3932,14 @@ class DeclChecker : public DeclVisitor { TC.validateDecl(assocType); } - bool checkUnsupportedNestedGeneric(NominalTypeDecl *NTD) { + void checkUnsupportedNestedGeneric(NominalTypeDecl *NTD) { // We don't support protocols outside the top level of a file. if (isa(NTD) && !NTD->getParent()->isModuleScopeContext()) { TC.diagnose(NTD->getLoc(), diag::unsupported_nested_protocol, NTD->getName()); - return true; + return; } // We don't support nested types in generics yet. @@ -3947,8 +3957,6 @@ class DeclChecker : public DeclVisitor { NTD->getName(), proto->getName()); } - NTD->setInvalid(); - return true; } if (DC->isLocalContext() && DC->isGenericContext()) { @@ -3958,11 +3966,9 @@ class DeclChecker : public DeclVisitor { diag::unsupported_type_nested_in_generic_function, NTD->getName(), AFD->getName()); - return true; } } } - return false; } void visitEnumDecl(EnumDecl *ED) { @@ -5337,7 +5343,6 @@ class DeclChecker : public DeclVisitor { // one. auto attempt = OverrideCheckingAttempt::PerfectMatch; SmallVector matches; - auto superclassMetaTy = MetatypeType::get(superclass); DeclName name = decl->getFullName(); bool hadExactMatch = false; LookupResult members; @@ -5381,7 +5386,7 @@ class DeclChecker : public DeclVisitor { lookupOptions -= NameLookupFlags::ProtocolMembers; lookupOptions -= NameLookupFlags::PerformConformanceCheck; - members = TC.lookupMember(decl->getDeclContext(), superclassMetaTy, + members = TC.lookupMember(decl->getDeclContext(), superclass, name, lookupOptions); } diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckError.cpp index b9e8ae86e54a6..d21d57b076153 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckError.cpp @@ -1396,7 +1396,14 @@ class CheckErrorCoverage : public ErrorHandlingWalker { classification.getResult() == ThrowingKind::Throws); } - return ShouldRecurse; + // If current apply expression did not type-check, don't attempt + // walking inside of it. This accounts for the fact that we don't + // erase types without type variables to enable better code complication, + // so DeclRefExpr(s) or ApplyExpr with DeclRefExpr as function contained + // inside would have their types preserved, which makes classification + // incorrect. + auto type = E->getType(); + return !type || type->hasError() ? ShouldNotRecurse : ShouldRecurse; } ShouldRecurse_t checkIfConfig(IfConfigStmt *S) { diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index 9ec8fbf6004a2..2d93936d91d60 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -654,6 +654,9 @@ static Type lookupDefaultLiteralType(TypeChecker &TC, DeclContext *dc, return Type(); TC.validateDecl(TD); + if (TD->isInvalid()) + return Type(); + if (auto *NTD = dyn_cast(TD)) return NTD->getDeclaredType(); return cast(TD)->getDeclaredInterfaceType(); diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp index f2e0351d8e216..cedc21b176fb2 100644 --- a/lib/Sema/TypeCheckExprObjC.cpp +++ b/lib/Sema/TypeCheckExprObjC.cpp @@ -330,8 +330,8 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, Type newType; if (lookupType && !lookupType->isAnyObject()) { - newType = lookupType->getTypeOfMember(dc->getParentModule(), type, - this); + newType = lookupType->getTypeOfMember(dc->getParentModule(), type, this, + type->getDeclaredInterfaceType()); } else { newType = type->getDeclaredInterfaceType(); } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index b38e1d4f967cd..365578a2de7fb 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -104,16 +104,8 @@ Type GenericTypeToArchetypeResolver::resolveTypeOfContext(DeclContext *dc) { } Type GenericTypeToArchetypeResolver::resolveTypeOfDecl(TypeDecl *decl) { - auto *dc = decl->getDeclContext(); - - // Hack for 'out of context' GenericTypeParamDecls when resolving - // a generic typealias - if (auto *paramDecl = dyn_cast(decl)) { - return dc->mapTypeIntoContext(paramDecl->getDeclaredInterfaceType()); - } - return GenericEnvironment::mapTypeIntoContext( - dc->getParentModule(), GenericEnv, + decl->getDeclContext()->getParentModule(), GenericEnv, decl->getDeclaredInterfaceType()); } @@ -189,6 +181,7 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType( // If the nested type comes from a type alias, use either the alias's // concrete type, or resolve its components down to another dependent member. if (auto alias = nestedPA->getTypeAliasDecl()) { + assert(!alias->getGenericParams() && "Generic typealias in protocol"); ref->setValue(alias); return TC.substMemberTypeWithBase(DC->getParentModule(), alias, baseTy); } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 40978ef9e0e01..547d418366eff 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -99,10 +99,6 @@ namespace { /// \param foundInType The type through which we found the /// declaration. void add(ValueDecl *found, ValueDecl *base, Type foundInType) { - // If we only want types, AST name lookup should not yield anything else. - assert(!Options.contains(NameLookupFlags::OnlyTypes) || - isa(found)); - ConformanceCheckOptions conformanceOptions; if (Options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; @@ -181,7 +177,7 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, - options.contains(NameLookupFlags::OnlyTypes), + /*OnlyTypes=*/false, options.contains(NameLookupFlags::ProtocolMembers), options.contains(NameLookupFlags::IgnoreAccessibility)); @@ -214,9 +210,50 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, return result; } +SmallVector +TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclName name, + SourceLoc loc, + NameLookupOptions options) { + SmallVector decls; + + // Try lookup without ProtocolMembers first. + UnqualifiedLookup lookup( + name, dc, this, + options.contains(NameLookupFlags::KnownPrivate), + loc, + /*OnlyTypes=*/true, + /*ProtocolMembers=*/false, + options.contains(NameLookupFlags::IgnoreAccessibility)); + for (auto found : lookup.Results) + decls.push_back(cast(found.getValueDecl())); + + if (decls.empty() && + options.contains(NameLookupFlags::ProtocolMembers)) { + // Try again, this time with protocol members. + // + // FIXME: Fix the problem where if NominalTypeDecl::getAllProtocols() + // is called too early, we start resolving extensions -- even those + // which do provide conformances. + UnqualifiedLookup lookup( + name, dc, this, + options.contains(NameLookupFlags::KnownPrivate), + loc, + /*OnlyTypes=*/true, + /*ProtocolMembers=*/true, + options.contains(NameLookupFlags::IgnoreAccessibility)); + + for (auto found : lookup.Results) + decls.push_back(cast(found.getValueDecl())); + } + + return decls; +} + LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { + assert(type->mayHaveMembers()); + LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) @@ -225,19 +262,8 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, subOptions |= NL_DynamicLookup; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; - if (options.contains(NameLookupFlags::OnlyTypes)) - subOptions |= NL_OnlyTypes; - - // Dig out the type that we'll actually be looking into, and determine - // whether it is a nominal type. - Type lookupType = type; - if (auto lvalueType = lookupType->getAs()) { - lookupType = lvalueType->getObjectType(); - } - if (auto metaType = lookupType->getAs()) { - lookupType = metaType->getInstanceType(); - } - NominalTypeDecl *nominalLookupType = lookupType->getAnyNominal(); + + NominalTypeDecl *nominalLookupType = type->getAnyNominal(); if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; @@ -246,9 +272,6 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; - // We can't have tuple types here; they need to be handled elsewhere. - assert(!type->is()); - // Local function that performs lookup. auto doLookup = [&]() { result.clear(); @@ -259,7 +282,7 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, dc->lookupQualified(type, name, subOptions, this, lookupResults); for (auto found : lookupResults) { - builder.add(found, nominalLookupType, lookupType); + builder.add(found, nominalLookupType, type); } }; @@ -291,13 +314,6 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, NameLookupOptions options) { LookupTypeResult result; - // Structural types do not have member types. - if (!type->is() && - !type->isExistentialType() && - !type->getAnyNominal() && - !type->is()) - return result; - // Look for members with the given name. SmallVector decls; NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; @@ -332,7 +348,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, if (type->isExistentialType() && (isa(typeDecl) || isa(typeDecl))) { - auto memberType = typeDecl->getInterfaceType()->getRValueInstanceType(); + auto memberType = typeDecl->getDeclaredInterfaceType(); if (memberType->hasTypeParameter()) { // If we haven't seen this type result yet, add it to the result set. @@ -347,27 +363,18 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, // record it later for conformance checking; we might find a more // direct typealias with the same name later. if (auto assocType = dyn_cast(typeDecl)) { - if (!type->is()) { + if (!type->is() && + !type->isTypeParameter()) { inferredAssociatedTypes.push_back(assocType); continue; } } - - // We are looking up an associated type of an archetype, or a - // protocol typealias or an archetype or concrete type. - // - // Proceed with the usual path below. } // Substitute the base into the member's type. auto memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type); - // FIXME: It is not clear why this substitution can fail, but the - // standard library won't build without this check. - if (!memberType) - continue; - // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); @@ -386,7 +393,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, auto *protocol = cast(assocType->getDeclContext()); auto conformance = conformsToProtocol(type, protocol, dc, conformanceOptions); - if (!conformance || conformance->isAbstract()) { + if (!conformance) { // FIXME: This is an error path. Should we try to recover? continue; } diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index f35d79d0fffa9..f3d09c9685903 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -767,7 +767,10 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC, // If the param is not a 'let' and it is not an 'inout'. // It must be a 'var'. Provide helpful diagnostics like a shadow copy // in the function body to fix the 'var' attribute. - if (!decl->isLet() && (Ty.isNull() || !Ty->is()) && !hadError) { + if (!decl->isLet() && + !decl->isImplicit() && + (Ty.isNull() || !Ty->is()) && + !hadError) { auto func = dyn_cast_or_null(DC); diagnoseAndMigrateVarParameterToBody(decl, func, TC); decl->setInvalid(); @@ -1116,7 +1119,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, if (NP->isImplicit()) { // If the whole pattern is implicit, the user didn't write it. // Assume the compiler knows what it's doing. - } else if (diagTy->getCanonicalType() == Context.TheEmptyTupleType) { + } else if (diagTy->isEqual(Context.TheEmptyTupleType)) { shouldRequireType = true; } else if (auto MTT = diagTy->getAs()) { if (auto protoTy = MTT->getInstanceType()->getAs()) { @@ -1221,8 +1224,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, case PatternKind::Expr: { assert(cast(P)->isResolved() && "coercing unresolved expr pattern!"); - if (type.getCanonicalTypeOrNull().getAnyNominal() == - Context.getBoolDecl()) { + if (type->getAnyNominal() == Context.getBoolDecl()) { // The type is Bool. // Check if the pattern is a Bool literal auto EP = cast(P); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index cbfcdabc015dc..34b3647614d00 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1081,7 +1081,8 @@ RequirementEnvironment::RequirementEnvironment( switch (reqReq.getKind()) { case RequirementKind::Conformance: { // Substitute the constrained types. - auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap); + auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap, + SubstFlags::UseErrorType); if (!first->isTypeParameter()) break; builder.addRequirement(Requirement(RequirementKind::Conformance, @@ -1092,8 +1093,10 @@ RequirementEnvironment::RequirementEnvironment( case RequirementKind::Superclass: { // Substitute the constrained types. - auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap); - auto second = reqReq.getSecondType().subst(reqToSyntheticEnvMap); + auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap, + SubstFlags::UseErrorType); + auto second = reqReq.getSecondType().subst(reqToSyntheticEnvMap, + SubstFlags::UseErrorType); if (!first->isTypeParameter()) break; @@ -1105,8 +1108,10 @@ RequirementEnvironment::RequirementEnvironment( case RequirementKind::SameType: { // Substitute the constrained types. - auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap); - auto second = reqReq.getSecondType().subst(reqToSyntheticEnvMap); + auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap, + SubstFlags::UseErrorType); + auto second = reqReq.getSecondType().subst(reqToSyntheticEnvMap, + SubstFlags::UseErrorType); // FIXME: We really want to check hasTypeParameter here, but the // ArchetypeBuilder isn't ready for that. @@ -1222,7 +1227,7 @@ matchWitness(TypeChecker &tc, std::tie(openedFullWitnessType, openWitnessType) = cs->getTypeOfReference(witness, /*isTypeReference=*/false, - /*isDynamicResult=*/false, + /*isSpecialized=*/false, FunctionRefKind::DoubleApply, witnessLocator, /*base=*/nullptr); @@ -2100,33 +2105,26 @@ diagnoseMatch(Module *module, NormalProtocolConformance *conformance, /// type. static Substitution getArchetypeSubstitution(TypeChecker &tc, DeclContext *dc, - ArchetypeType *archetype, + ArrayRef protocols, Type replacement) { - Type resultReplacement = replacement; - assert(!resultReplacement->isTypeParameter() && "Can't be dependent"); + assert(!replacement->isTypeParameter() && "Can't be dependent"); SmallVector conformances; - bool isError = - replacement->hasError() || replacement->getCanonicalType()->hasError(); - assert((archetype != nullptr || isError) && - "Should have built archetypes already"); - - // FIXME: Turn the nullptr check into an assertion - if (archetype != nullptr) { - for (auto proto : archetype->getConformsTo()) { - auto conformance = tc.conformsToProtocol(replacement, proto, dc, None); - assert((conformance || isError) && - "Conformance should already have been verified"); - (void)isError; - if (conformance) - conformances.push_back(*conformance); - else - conformances.push_back(ProtocolConformanceRef(proto)); - } + bool isError = replacement->hasError(); + + for (auto proto : protocols) { + auto conformance = tc.conformsToProtocol(replacement, proto, dc, None); + assert((conformance || isError) && + "Conformance should already have been verified"); + (void)isError; + if (conformance) + conformances.push_back(*conformance); + else + conformances.push_back(ProtocolConformanceRef(proto)); } return Substitution{ - resultReplacement, + replacement, tc.Context.AllocateCopy(conformances), }; } @@ -2293,14 +2291,11 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType, } // Record the type witness. - auto *archetype = Conformance->getProtocol()->mapTypeIntoContext( - assocType->getDeclaredInterfaceType()) - ->getAs(); - if (archetype) - Conformance->setTypeWitness( - assocType, - getArchetypeSubstitution(TC, DC, archetype, type), - typeDecl); + auto protocols = assocType->getConformingProtocols(); + Conformance->setTypeWitness( + assocType, + getArchetypeSubstitution(TC, DC, protocols, type), + typeDecl); } /// Generates a note for a protocol requirement for which no witness was found @@ -2828,6 +2823,18 @@ static CheckTypeWitnessResult checkTypeWitness(TypeChecker &tc, DeclContext *dc, for (auto reqProto : assocType->getConformingProtocols()) { if (!tc.conformsToProtocol(type, reqProto, dc, None)) return reqProto; + + // FIXME: Why is conformsToProtocol() not enough? The stdlib doesn't + // build unless we fail here while inferring an associated type + // somewhere. + if (type->isSpecialized()) { + auto substitutions = type->gatherAllSubstitutions( + dc->getParentModule(), &tc); + for (auto sub : substitutions) { + if (sub.getReplacement()->hasError()) + return reqProto; + } + } } // Success! @@ -2839,7 +2846,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( AssociatedTypeDecl *assocType) { // Look for a member type with the same name as the associated type. auto candidates = TC.lookupMemberType(DC, Adoptee, assocType->getName(), - /*lookupOptions=*/None); + /*lookup=*/None); // If there aren't any candidates, we're done. if (!candidates) { @@ -3405,6 +3412,7 @@ void ConformanceChecker::resolveTypeWitnesses() { // Local function that folds dependent member types with non-dependent // bases into actual member references. std::function foldDependentMemberTypes; + llvm::DenseSet recursionCheck; foldDependentMemberTypes = [&](Type type) -> Type { if (auto depMemTy = type->getAs()) { auto baseTy = depMemTy->getBase().transform(foldDependentMemberTypes); @@ -3415,6 +3423,11 @@ void ConformanceChecker::resolveTypeWitnesses() { if (!assocType) return nullptr; + if (!recursionCheck.insert(assocType).second) + return nullptr; + + SWIFT_DEFER { recursionCheck.erase(assocType); }; + // Try to substitute into the base type. if (Type result = depMemTy->substBaseType(DC->getParentModule(), baseTy)){ return result; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 41215a2e79ed0..a542949bbf724 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -134,12 +134,11 @@ static Type getObjectiveCNominalType(TypeChecker &TC, NameLookupOptions lookupOptions = defaultMemberLookupOptions | - NameLookupFlags::KnownPrivate | - NameLookupFlags::OnlyTypes; - if (auto result = TC.lookupMember(dc, ModuleType::get(module), TypeName, - lookupOptions)) { - for (auto decl : result) { - if (auto nominal = dyn_cast(decl.Decl)) { + NameLookupFlags::KnownPrivate; + if (auto result = TC.lookupMemberType(dc, ModuleType::get(module), TypeName, + lookupOptions)) { + for (auto pair : result) { + if (auto nominal = dyn_cast(pair.first)) { cache = nominal->getDeclaredType(); return cache; } @@ -199,7 +198,7 @@ void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) { // // FIXME: UnqualifiedLookup already has this information; it needs to be // plumbed through. -static std::tuple +static std::tuple findDeclContextForType(TypeChecker &TC, TypeDecl *typeDecl, DeclContext *fromDC, @@ -256,8 +255,8 @@ findDeclContextForType(TypeChecker &TC, if (!parentDC->isTypeContext()) continue; - llvm::SmallPtrSet visited; - llvm::SmallVector stack; + llvm::SmallPtrSet visited; + llvm::SmallVector stack; // Start with the type of the current context. auto fromNominal = parentDC->getAsNominalTypeOrNominalTypeExtensionContext(); @@ -265,7 +264,7 @@ findDeclContextForType(TypeChecker &TC, return std::make_tuple(nullptr, nullptr, false); // Break circularity. - auto pushDecl = [&](const NominalTypeDecl *nominal) -> void { + auto pushDecl = [&](NominalTypeDecl *nominal) -> void { if (visited.insert(nominal).second) stack.push_back(nominal); }; @@ -332,20 +331,14 @@ Type TypeChecker::resolveTypeInContext( DeclContext *fromDC, TypeResolutionOptions options, bool isSpecialized, - GenericTypeResolver *resolver, - UnsatisfiedDependency *unsatisfiedDependency) { + GenericTypeResolver *resolver) { GenericTypeToArchetypeResolver defaultResolver(fromDC); if (!resolver) resolver = &defaultResolver; - // If we have a callback to report dependencies, do so. - if (unsatisfiedDependency && - (*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl))) - return Type(); - // FIXME: foundDC and foundNominal should come from UnqualifiedLookup DeclContext *foundDC; - const NominalTypeDecl *foundNominal; + NominalTypeDecl *foundNominal; bool valid; std::tie(foundDC, foundNominal, valid) = findDeclContextForType(*this, typeDecl, fromDC, options); @@ -371,7 +364,10 @@ Type TypeChecker::resolveTypeInContext( } } - if (!foundNominal) { + bool hasDependentType = typeDecl->getDeclaredInterfaceType() + ->hasTypeParameter(); + + if (!foundNominal || !hasDependentType) { // If we found a generic parameter, map to the archetype if there is one. if (auto genericParam = dyn_cast(typeDecl)) { return resolver->resolveGenericTypeParamType( @@ -395,15 +391,10 @@ Type TypeChecker::resolveTypeInContext( if (auto *nominalDecl = dyn_cast(typeDecl)) return nominalDecl->getDeclaredType(); - assert(isa(typeDecl)); + assert(!hasDependentType); return typeDecl->getDeclaredInterfaceType(); } - bool hasDependentType = typeDecl->getDeclaredInterfaceType() - ->hasTypeParameter(); - if (!hasDependentType) - return typeDecl->getDeclaredInterfaceType(); - // Now let's get the base type. Type selfType; @@ -415,6 +406,8 @@ Type TypeChecker::resolveTypeInContext( !isa(foundNominal)) selfType = foundNominal->getDeclaredType(); // Otherwise, just use the type of the context we're looking at. + else if (isa(typeDecl)) + selfType = resolver->resolveTypeOfDecl(foundNominal); else selfType = resolver->resolveTypeOfContext(foundDC); @@ -430,12 +423,6 @@ Type TypeChecker::resolveTypeInContext( selfType, assocType); } - // For type members of a base class, make sure we use the right - // derived class as the parent type. - if (auto *ownerClass = typeDecl->getDeclContext() - ->getAsClassOrClassExtensionContext()) - selfType = selfType->getSuperclassForDecl(ownerClass, this); - // Finally, substitute the base type into the member type. return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, selfType); @@ -605,37 +592,26 @@ Type TypeChecker::applyUnboundGenericArguments( // If we're completing a generic TypeAlias, then we map the types provided // onto the underlying type. if (auto *TAD = dyn_cast(decl)) { - auto signature = TAD->getGenericSignature(); - TypeSubstitutionMap subs; + + // The type should look like SomeNominal.Alias. + + // Get the substitutions for outer generic parameters from the parent + // type. + auto *unboundType = type->castTo(); + if (auto parentType = unboundType->getParent()) + subs = parentType->getContextSubstitutions(TAD->getDeclContext()); + + // Get the substitutions for the inner parameters. + auto signature = TAD->getGenericSignature(); for (unsigned i = 0, e = genericArgs.size(); i < e; i++) { auto t = signature->getInnermostGenericParams()[i]; subs[t->getCanonicalType()->castTo()] = genericArgs[i].getType(); } - if (auto outerSig = TAD->getDeclContext()->getGenericSignatureOfContext()) { - for (auto outerParam : outerSig->getGenericParams()) { - subs[outerParam->getCanonicalType()->castTo()] = - resolver->resolveTypeOfDecl(outerParam->getDecl()); - } - } - - // FIXME: Change callers to pass the right type in for generic typealiases - if (type->is() || isa(type.getPointer())) - type = TAD->getDeclaredInterfaceType(); - - // When resolving a generic typealias with a base type, we have a partially - // substituted type by now. Put the archetypes in the substitution map so that - // the subst() call leaves them alone. - // - // FIXME: Combine base type substitution step with applying generic arguments - // to avoid this gross hack. - type.visit([&](Type t) { - if (auto *archetype = t->getAs()) - subs[archetype] = archetype; - }); - + // Apply substitutions to the interface type of the typealias. + type = TAD->getDeclaredInterfaceType(); return type.subst(dc->getParentModule(), subs, SubstFlags::UseErrorType); } @@ -726,13 +702,7 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. Type type = - TC.resolveTypeInContext(typeDecl, dc, options, generic, resolver, - unsatisfiedDependency); - - // FIXME: Defensive check that shouldn't be needed, but prevents a - // huge number of crashes on ill-formed code. - if (!type) - return ErrorType::get(TC.Context); + TC.resolveTypeInContext(typeDecl, dc, options, generic, resolver); if (type->is() && !generic && !options.contains(TR_AllowUnboundGenerics) && @@ -741,10 +711,6 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, return ErrorType::get(TC.Context); } - // If we found a generic parameter, try to resolve it. - if (auto genericParam = type->getAs()) - type = resolver->resolveGenericTypeParamType(genericParam); - if (generic && !options.contains(TR_ResolveStructure)) { // Apply the generic arguments to the type. type = TC.applyGenericArguments(type, typeDecl, loc, dc, generic, @@ -808,20 +774,19 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::KnownPrivate; relookupOptions |= NameLookupFlags::IgnoreAccessibility; - relookupOptions |= NameLookupFlags::OnlyTypes; - LookupResult inaccessibleResults = - tc.lookupUnqualified(lookupDC, comp->getIdentifier(), comp->getIdLoc(), - relookupOptions); - if (inaccessibleResults) { + auto inaccessibleResults = + tc.lookupUnqualifiedType(lookupDC, comp->getIdentifier(), comp->getIdLoc(), + relookupOptions); + if (!inaccessibleResults.empty()) { // FIXME: What if the unviable candidates have different levels of access? - auto first = cast(inaccessibleResults.front().Decl); + auto first = cast(inaccessibleResults.front()); tc.diagnose(comp->getIdLoc(), diag::candidate_inaccessible, comp->getIdentifier(), first->getFormalAccess()); // FIXME: If any of the candidates (usually just one) are in the same // module we could offer a fix-it. for (auto lookupResult : inaccessibleResults) - tc.diagnose(lookupResult.Decl, diag::type_declared_here); + tc.diagnose(lookupResult, diag::type_declared_here); // Don't try to recover here; we'll get more access-related diagnostics // downstream if we do. @@ -864,6 +829,12 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, } // Qualified lookup case. + if (!parentType->mayHaveMembers()) { + tc.diagnose(comp->getIdLoc(), diag::invalid_member_type, + comp->getIdentifier(), parentType) + .highlight(parentRange); + return ErrorType::get(tc.Context); + } // Try ignoring access control. NameLookupOptions relookupOptions = lookupOptions; @@ -916,7 +887,6 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, NameLookupOptions memberLookupOptions = lookupOptions; memberLookupOptions |= NameLookupFlags::IgnoreAccessibility; memberLookupOptions |= NameLookupFlags::KnownPrivate; - memberLookupOptions -= NameLookupFlags::OnlyTypes; memberLookup = tc.lookupMember(dc, parentType, comp->getIdentifier(), memberLookupOptions); @@ -1059,21 +1029,18 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, return nullptr; NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions; - lookupOptions |= NameLookupFlags::OnlyTypes; if (options.contains(TR_KnownNonCascadingDependency)) lookupOptions |= NameLookupFlags::KnownPrivate; - // FIXME: Eliminate this once we can handle finding protocol members - // in resolveTypeInContext. - lookupOptions -= NameLookupFlags::ProtocolMembers; - LookupResult globals = TC.lookupUnqualified(lookupDC, comp->getIdentifier(), - comp->getIdLoc(), lookupOptions); + auto globals = TC.lookupUnqualifiedType(lookupDC, + comp->getIdentifier(), + comp->getIdLoc(), + lookupOptions); // Process the names we found. Type current; TypeDecl *currentDecl = nullptr; bool isAmbiguous = false; - for (const auto &result : globals) { - auto typeDecl = cast(result.Decl); + for (const auto &typeDecl : globals) { // If necessary, add delayed members to the declaration. if (auto nomDecl = dyn_cast(typeDecl)) { @@ -1111,8 +1078,8 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, TC.diagnose(comp->getIdLoc(), diag::ambiguous_type_base, comp->getIdentifier()) .highlight(comp->getIdLoc()); - for (auto result : globals) { - TC.diagnose(result.Decl, diag::found_candidate); + for (auto typeDecl : globals) { + TC.diagnose(typeDecl, diag::found_candidate); } } @@ -1188,59 +1155,26 @@ static Type resolveNestedIdentTypeComponent( // Short-circuiting. if (comp->isInvalid()) return ErrorType::get(TC.Context); + // If the parent is a type parameter, the member is a dependent member, + // and we skip much of the work below. + if (parentTy->isTypeParameter()) { + auto memberType = resolver->resolveDependentMemberType(parentTy, DC, + parentRange, comp); + assert(memberType && "Received null dependent member type"); + return memberType; + } + // Phase 2: If a declaration has already been bound, use it. if (ValueDecl *decl = comp->getBoundDecl()) { auto *typeDecl = cast(decl); - auto *assocType = dyn_cast(typeDecl); - - Type memberType; - - if (parentTy->isTypeParameter()) { - // If the parent is a type parameter, the member is a dependent member. - - // FIXME: We either have an associated type here or a member of - // some member of the superclass bound (or its superclasses), - // which should allow us to skip much of the work in - // resolveDependentMemberType. - - // Try to resolve the dependent member type to a specific associated - // type. - memberType = resolver->resolveDependentMemberType(parentTy, DC, - parentRange, comp); - assert(memberType && "Received null dependent member type"); - return memberType; - } - - if (assocType && !parentTy->is()) { - assert(!parentTy->isExistentialType()); - - // Find the conformance and dig out the type witness. - ConformanceCheckOptions conformanceOptions; - if (options.contains(TR_InExpression)) - conformanceOptions |= ConformanceCheckFlags::InExpression; - - auto *protocol = assocType->getProtocol(); - auto conformance = TC.conformsToProtocol(parentTy, protocol, DC, - conformanceOptions); - if (!conformance || conformance->isAbstract()) { - return ErrorType::get(TC.Context); - } - - // FIXME: Establish that we need a type witness. - auto memberType = - conformance->getConcrete()->getTypeWitness(assocType, &TC) - .getReplacement(); - - // Diagnose the bad reference if we need to. - if (memberType->hasError()) - maybeDiagnoseBadConformanceRef(assocType, conformance->getConcrete()); - - return memberType; - } // Otherwise, simply substitute the parent type into the member. - memberType = TC.substMemberTypeWithBase(DC->getParentModule(), typeDecl, - parentTy); + auto memberType = TC.substMemberTypeWithBase(DC->getParentModule(), + typeDecl, parentTy); + + // Diagnose the bad reference if we need to. + if (typeDecl && isa(typeDecl) && memberType->hasError()) + maybeDiagnoseBadConformanceRef(cast(typeDecl), nullptr); // Propagate failure. if (!memberType || memberType->hasError()) return memberType; @@ -1261,17 +1195,6 @@ static Type resolveNestedIdentTypeComponent( // Phase 1: Find and bind the component decl. - // If the parent is a dependent type, the member is a dependent member. - if (parentTy->isTypeParameter()) { - // Try to resolve the dependent member type to a specific associated - // type. - Type memberType = resolver->resolveDependentMemberType(parentTy, DC, - parentRange, - comp); - assert(memberType && "Received null dependent member type"); - return memberType; - } - // Look for member types with the given name. bool isKnownNonCascading = options.contains(TR_KnownNonCascadingDependency); if (!isKnownNonCascading && options.contains(TR_InExpression)) { @@ -1303,8 +1226,10 @@ static Type resolveNestedIdentTypeComponent( if (options.contains(TR_ExtensionBinding) || options.contains(TR_InheritanceClause)) lookupOptions -= NameLookupFlags::ProtocolMembers; - auto memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(), - lookupOptions); + LookupTypeResult memberTypes; + if (parentTy->mayHaveMembers()) + memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(), + lookupOptions); // Name lookup was ambiguous. Complain. // FIXME: Could try to apply generic arguments first, and see whether @@ -1417,12 +1342,21 @@ static Type resolveIdentTypeComponent( static bool diagnoseAvailability(IdentTypeRepr *IdType, DeclContext *DC, TypeChecker &TC, bool AllowPotentiallyUnavailableProtocol) { - for (auto comp : IdType->getComponentRange()) { + auto componentRange = IdType->getComponentRange(); + for (auto comp : componentRange) { if (auto typeDecl = dyn_cast_or_null(comp->getBoundDecl())) { + // In Swift 3, components other than the last one were not properly + // checked for availability. + // FIXME: We should try to downgrade these errors to warnings, not just + // skip diagnosing them. + if (TC.getLangOpts().isSwiftVersion3() && comp != componentRange.back()) + continue; + if (diagnoseDeclAvailability(typeDecl, TC, DC, comp->getIdLoc(), AllowPotentiallyUnavailableProtocol, - false)) + /*SignalOnPotentialUnavailability*/false)) { return true; + } } } @@ -2266,12 +2200,13 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, ArrayRef params; params = genericSig->getGenericParams(); - if (repr->getGenericArguments().size() != params.size()) { + if (repr->getGenericArguments().size() + != genericSig->getAllDependentTypes().size()) { TC.diagnose(repr->getLoc(), diag::sil_box_arg_mismatch); return ErrorType::get(Context); } - for (unsigned i : indices(repr->getGenericArguments())) { + for (unsigned i : indices(params)) { auto argTy = resolveType(repr->getGenericArguments()[i], options); genericArgMap.insert({params[i], argTy->getCanonicalType()}); } @@ -2943,38 +2878,50 @@ Type TypeResolver::buildProtocolType( } Type TypeChecker::substMemberTypeWithBase(Module *module, - const TypeDecl *member, + TypeDecl *member, Type baseTy) { + // For type members of a base class, make sure we use the right + // derived class as the parent type. + if (auto *ownerClass = member->getDeclContext() + ->getAsClassOrClassExtensionContext()) { + if (auto *archetypeTy = baseTy->getAs()) + baseTy = archetypeTy->getSuperclass(); + baseTy = baseTy->getSuperclassForDecl(ownerClass, this); + } + + auto parentTy = baseTy; + if (baseTy->is()) + parentTy = Type(); + // The declared interface type for a generic type will have the type // arguments; strip them off. if (auto *nominalDecl = dyn_cast(member)) { - auto memberType = nominalDecl->getDeclaredType(); - assert(memberType); - - if (baseTy->is()) - return memberType; - - if (baseTy->getAnyNominal() || - baseTy->is()) { - if (auto *unboundGenericType = memberType->getAs()) { - return UnboundGenericType::get( - unboundGenericType->getDecl(), baseTy, - unboundGenericType->getASTContext()); - } else if (auto *nominalType = memberType->getAs()) { - return NominalType::get( - nominalType->getDecl(), baseTy, - nominalType->getASTContext()); - } - llvm_unreachable("Not a nominal type?"); + if (!isa(nominalDecl) && + nominalDecl->getGenericParams()) { + return UnboundGenericType::get( + nominalDecl, parentTy, + nominalDecl->getASTContext()); + } else { + return NominalType::get( + nominalDecl, parentTy, + nominalDecl->getASTContext()); } + } - return memberType; - } else { - auto memberType = member->getDeclaredInterfaceType(); - memberType = baseTy->getTypeOfMember(module, member, this, memberType); - assert(memberType); - return memberType; + if (auto *aliasDecl = dyn_cast(member)) { + if (aliasDecl->getGenericParams()) { + return UnboundGenericType::get( + aliasDecl, parentTy, + aliasDecl->getASTContext()); + } } + + auto memberType = member->getDeclaredInterfaceType(); + if (!parentTy) + return memberType; + + auto subs = parentTy->getContextSubstitutions(member->getDeclContext()); + return memberType.subst(module, subs, SubstFlags::UseErrorType); } Type TypeChecker::getSuperClassOf(Type type) { @@ -3323,9 +3270,10 @@ bool TypeChecker::isRepresentableInObjC( } if (auto FD = dyn_cast(AFD)) { - Type ResultType = FD->getResultInterfaceType(); + Type ResultType = FD->mapTypeIntoContext(FD->getResultInterfaceType()); if (!ResultType->hasError() && !ResultType->isVoid() && + !ResultType->isUninhabited() && !ResultType->isRepresentableIn(ForeignLanguage::ObjectiveC, const_cast(FD))) { if (Diagnose) { @@ -3467,6 +3415,17 @@ bool TypeChecker::isRepresentableInObjC( if (!foundErrorParameterIndex) { auto *paramList = AFD->getParameterLists().back(); errorParameterIndex = paramList->size(); + + // Note: the errorParameterIndex is actually a SIL function + // parameter index, which means tuples are exploded. Normally + // tuple types cannot be bridged to Objective-C, except for + // one special case -- a constructor with a single named parameter + // 'foo' of tuple type becomes a zero-argument selector named + // 'initFoo'. + if (auto *CD = dyn_cast(AFD)) + if (CD->isObjCZeroParameterWithLongSelector()) + errorParameterIndex--; + while (errorParameterIndex > 0) { // Skip over trailing closures. auto type = paramList->get(errorParameterIndex - 1)->getType(); @@ -3586,11 +3545,7 @@ bool TypeChecker::isRepresentableInObjC(const SubscriptDecl *SD, return false; // Figure out the type of the indices. - Type IndicesType = SD->getIndicesInterfaceType(); - if (auto TupleTy = IndicesType->getAs()) { - if (TupleTy->getNumElements() == 1 && !TupleTy->getElement(0).isVararg()) - IndicesType = TupleTy->getElementType(0); - } + Type IndicesType = SD->getIndicesInterfaceType()->getWithoutImmediateLabel(); if (IndicesType->hasError()) return false; @@ -3742,18 +3697,12 @@ class UnsupportedProtocolVisitor : public TypeReprVisitor, public ASTWalker { TypeChecker &TC; - bool recurseIntoSubstatements; + bool checkStatements; bool hitTopStmt; public: - UnsupportedProtocolVisitor(TypeChecker &tc) : TC(tc) { - recurseIntoSubstatements = true; - hitTopStmt = false; - } - - void setRecurseIntoSubstatements(bool recurse) { - recurseIntoSubstatements = recurse; - } + UnsupportedProtocolVisitor(TypeChecker &tc, bool checkStatements) + : TC(tc), checkStatements(checkStatements), hitTopStmt(false) { } bool walkToTypeReprPre(TypeRepr *T) override { if (T->isInvalid()) @@ -3769,14 +3718,16 @@ class UnsupportedProtocolVisitor } std::pair walkToStmtPre(Stmt *S) override { - if (recurseIntoSubstatements) { - return { true, S }; - } else if (hitTopStmt) { - return { false, S }; - } else { + if (checkStatements && !hitTopStmt) { hitTopStmt = true; return { true, S }; } + + return { false, S }; + } + + bool walkToDeclPre(Decl *D) override { + return !checkStatements; } void visitIdentTypeRepr(IdentTypeRepr *T) { @@ -3833,7 +3784,7 @@ void TypeChecker::checkUnsupportedProtocolType(Decl *decl) { if (isa(decl)) return; - UnsupportedProtocolVisitor visitor(*this); + UnsupportedProtocolVisitor visitor(*this, /*checkStatements=*/false); decl->walk(visitor); } @@ -3841,10 +3792,6 @@ void TypeChecker::checkUnsupportedProtocolType(Stmt *stmt) { if (!stmt) return; - UnsupportedProtocolVisitor visitor(*this); - - // This method will already be called for all individual statements, so don't repeat - // that checking by walking into any statement inside this one. - visitor.setRecurseIntoSubstatements(false); + UnsupportedProtocolVisitor visitor(*this, /*checkStatements=*/true); stmt->walk(visitor); } diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 5a1ae1e7dd337..1cd9e59892151 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -326,9 +326,11 @@ static void bindExtensionDecl(ExtensionDecl *ED, TypeChecker &TC) { // Hack to allow extending a generic typealias. if (auto *unboundGeneric = extendedType->getAs()) { if (auto *aliasDecl = dyn_cast(unboundGeneric->getDecl())) { - extendedType = aliasDecl->getDeclaredInterfaceType()->getAnyNominal() - ->getDeclaredType(); - ED->getExtendedTypeLoc().setType(extendedType); + auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); + if (extendedNominal) { + extendedType = extendedNominal->getDeclaredType(); + ED->getExtendedTypeLoc().setType(extendedType); + } } } @@ -771,15 +773,18 @@ static Optional getTypeOfCompletionContextExpr( return None; } - CanType originalType = parsedExpr->getType().getCanonicalTypeOrNull(); + Type originalType = parsedExpr->getType(); if (auto T = TC.getTypeOfExpressionWithoutApplying(parsedExpr, DC, referencedDecl, FreeTypeVariableBinding::GenericParameters)) return T; // Try to recover if we've made any progress. - if (parsedExpr && !isa(parsedExpr) && parsedExpr->getType() && + if (parsedExpr && + !isa(parsedExpr) && + parsedExpr->getType() && !parsedExpr->getType()->hasError() && - parsedExpr->getType().getCanonicalTypeOrNull() != originalType) { + (originalType.isNull() || + !parsedExpr->getType()->isEqual(originalType))) { return parsedExpr->getType(); } @@ -2328,3 +2333,15 @@ void TypeChecker::checkForForbiddenPrefix(StringRef Name) { llvm::report_fatal_error(Msg); } } + +DeclTypeCheckingSemantics +TypeChecker::getDeclTypeCheckingSemantics(ValueDecl *decl) { + // Check for a @_semantics attribute. + if (auto semantics = decl->getAttrs().getAttribute()) { + if (semantics->Value.equals("typechecker.type(of:)")) + return DeclTypeCheckingSemantics::TypeOf; + if (semantics->Value.equals("typechecker.withoutActuallyEscaping(_:do:)")) + return DeclTypeCheckingSemantics::WithoutActuallyEscaping; + } + return DeclTypeCheckingSemantics::Normal; +} diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index ecffa9659d76e..368fa5a07e3c4 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -55,6 +55,20 @@ namespace constraints { typedef llvm::DenseMap> ConformanceMap; +/// Special-case type checking semantics for certain declarations. +enum class DeclTypeCheckingSemantics { + /// A normal declaration. + Normal, + + /// The type(of:) declaration, which performs a "dynamic type" operation, + /// with different behavior for existential and non-existential arguments. + TypeOf, + + /// The withoutActuallyEscaping(_:do:) declaration, which makes a nonescaping + /// closure temporarily escapable. + WithoutActuallyEscaping, +}; + /// The result of name lookup. class LookupResult { public: @@ -232,11 +246,9 @@ enum class NameLookupFlags { /// Whether to perform 'dynamic' name lookup that finds @objc /// members of any class or protocol. DynamicLookup = 0x08, - /// Whether we're only looking for types. - OnlyTypes = 0x10, /// Whether to ignore access control for this lookup, allowing inaccessible /// results to be returned. - IgnoreAccessibility = 0x20, + IgnoreAccessibility = 0x10, }; /// A set of options that control name lookup. @@ -811,14 +823,11 @@ class TypeChecker final : public LazyResolver { /// \param isSpecialized Whether this type is immediately specialized. /// \param resolver The resolver for generic types. /// - /// \returns the resolved type, or emits a diagnostic and returns null if the - /// type cannot be resolved. + /// \returns the resolved type. Type resolveTypeInContext(TypeDecl *typeDecl, DeclContext *fromDC, TypeResolutionOptions options, bool isSpecialized, - GenericTypeResolver *resolver = nullptr, - UnsatisfiedDependency *unsatisfiedDependency - = nullptr); + GenericTypeResolver *resolver = nullptr); /// Apply generic arguments to the given type. /// @@ -877,7 +886,7 @@ class TypeChecker final : public LazyResolver { /// \param member The member whose type projection is being computed. /// \param baseTy The base type that will be substituted for the 'Self' of the /// member. - Type substMemberTypeWithBase(Module *module, const TypeDecl *member, Type baseTy); + Type substMemberTypeWithBase(Module *module, TypeDecl *member, Type baseTy); /// \brief Retrieve the superclass type of the given type, or a null type if /// the type has no supertype. @@ -1705,6 +1714,18 @@ class TypeChecker final : public LazyResolver { NameLookupOptions options = defaultUnqualifiedLookupOptions); + /// Perform unqualified type lookup at the given source location + /// within a particular declaration context. + /// + /// \param dc The declaration context in which to perform name lookup. + /// \param name The name of the entity to look for. + /// \param loc The source location at which name lookup occurs. + /// \param options Options that control name lookup. + SmallVector + lookupUnqualifiedType(DeclContext *dc, DeclName name, SourceLoc loc, + NameLookupOptions options + = defaultUnqualifiedLookupOptions); + /// \brief Lookup a member in the given type. /// /// \param dc The context that needs the member. @@ -2016,6 +2037,9 @@ class TypeChecker final : public LazyResolver { VarDecl *getSelfForInitDelegationInConstructor(DeclContext *DC, UnresolvedDotExpr *ctorRef); + /// Diagnose assigning variable to itself. + bool diagnoseSelfAssignment(const Expr *E); + /// When referencing a class initializer, check that the base expression is /// either a static metatype or that the initializer is 'required'. bool @@ -2060,6 +2084,10 @@ class TypeChecker final : public LazyResolver { void noteTypoCorrection(DeclName name, DeclNameLoc nameLoc, const LookupResult::Result &suggestion); + + /// Check if the given decl has a @_semantics attribute that gives it + /// special case type-checking behavior. + DeclTypeCheckingSemantics getDeclTypeCheckingSemantics(ValueDecl *decl); }; /// \brief RAII object that cleans up the given expression if not explicitly diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index af8f3d1411d40..6ffa17e879a95 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -269,6 +269,15 @@ static bool skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) { #endif } +void ModuleFile::finishPendingActions() { + while (!DelayedGenericEnvironments.empty()) { + // Force completion of the last generic environment. + auto genericEnvDC = DelayedGenericEnvironments.back(); + DelayedGenericEnvironments.pop_back(); + (void)genericEnvDC->getGenericEnvironmentOfContext(); + } +} + /// Translate from the serialization DefaultArgumentKind enumerators, which are /// guaranteed to be stable, to the AST ones. static Optional @@ -926,11 +935,14 @@ void ModuleFile::configureGenericEnvironment( if (auto genericSig = sigOrEnv.dyn_cast()) { if (auto type = genericDecl.dyn_cast()) { type->setLazyGenericEnvironment(this, genericSig, envID); + DelayedGenericEnvironments.push_back(type); } else if (auto func = genericDecl.dyn_cast()) { func->setLazyGenericEnvironment(this, genericSig, envID); + DelayedGenericEnvironments.push_back(func); } else { auto ext = genericDecl.get(); ext->setLazyGenericEnvironment(this, genericSig, envID); + DelayedGenericEnvironments.push_back(ext); } return; @@ -2125,6 +2137,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { PrivateDiscriminatorRAII privateDiscriminatorRAII{*this, declOrOffset}; LocalDiscriminatorRAII localDiscriminatorRAII(declOrOffset); + DeserializingEntityRAII deserializingEntity(*this); // Local function that handles the "inherited" list for a type. auto handleInherited @@ -2465,7 +2478,8 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { declOrOffset = assocType; assocType->computeType(); - assocType->setAccessibility(cast(DC)->getFormalAccess()); + Accessibility parentAccess = cast(DC)->getFormalAccess(); + assocType->setAccessibility(std::max(parentAccess,Accessibility::Internal)); if (isImplicit) assocType->setImplicit(); @@ -3994,13 +4008,13 @@ Type ModuleFile::getType(TypeID TID) { SmallVector genericArgs; if (auto sig = layout->getGenericSignature()) { - if (args.size() != sig->getGenericParams().size()) { + if (args.size() != sig->getAllDependentTypes().size()) { error(); return nullptr; } TypeSubstitutionMap mappings; - for (unsigned i : indices(args)) { + for (unsigned i : indices(sig->getGenericParams())) { mappings[sig->getGenericParams()[i]] = getType(args[i])->getCanonicalType(); } diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 9de56c50fea30..89ea84763f5fc 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2217,11 +2217,9 @@ void Serializer::writeDecl(const Decl *D) { addIdentifierRef(discriminator)); } } - } - if (auto *VD = dyn_cast(D)) { - if (VD->getDeclContext()->isLocalContext()) { - auto discriminator = VD->getLocalDiscriminator(); + if (value->getDeclContext()->isLocalContext()) { + auto discriminator = value->getLocalDiscriminator(); auto abbrCode = DeclTypeAbbrCodes[LocalDiscriminatorLayout::Code]; LocalDiscriminatorLayout::emitRecord(Out, ScratchRecord, abbrCode, discriminator); diff --git a/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift index 12f63b15611ad..8b2be8f462b59 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift @@ -608,6 +608,19 @@ self.test("\(testNamePrefix).append(contentsOf:)/semantics") { } } +self.test("\(testNamePrefix).OperatorPlusEquals") { + for test in appendContentsOfTests { + var c = makeWrappedCollection(test.collection) + let newElements = + MinimalCollection(elements: test.newElements.map(wrapValue)) + c += newElements + expectEqualSequence( + test.expected, + c.map { extractValue($0).value }, + stackTrace: SourceLocStack().with(test.loc)) + } +} + //===----------------------------------------------------------------------===// // insert() //===----------------------------------------------------------------------===// diff --git a/stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift.gyb index 4e9d58f980140..7d104853f0aa4 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift.gyb +++ b/stdlib/private/StdlibCollectionUnittest/CheckSequenceInstance.swift.gyb @@ -86,16 +86,16 @@ public func checkSequence< _ = sequence._preprocessingPass { () -> Void in var count = 0 for _ in sequence { count += 1 } - let buf = UnsafeMutablePointer.allocate(capacity: count) - let end = sequence._copyContents(initializing: buf) - expectTrue(end == buf + count, "_copyContents returned the wrong value") - var j = expected.startIndex - for i in 0..<(end - buf) { - expectTrue(sameValue(expected[j], buf[i])) - j = expected.index(after: j) - } - buf.deinitialize(count: end - buf) - buf.deallocate(capacity: count) + let ptr = UnsafeMutablePointer.allocate(capacity: count) + let buf = UnsafeMutableBufferPointer(start: ptr, count: count) + var (remainders,writtenUpTo) = sequence._copyContents(initializing: buf) + expectTrue(remainders.next() == nil, + "_copyContents returned unwritten elements") + expectTrue(writtenUpTo == buf.endIndex, + "_copyContents failed to use entire buffer") + expectEqualSequence(expected, buf, ${trace}, sameValue: sameValue) + ptr.deinitialize(count: count) + ptr.deallocate(capacity: count) } // Test `_copyToContiguousArray()` if we can do so diff --git a/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift b/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift index a124428409b7f..4a5aebb428487 100644 --- a/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift @@ -460,11 +460,11 @@ public let enumerateTests = [ public let filterTests = [ FilterTest( [], [], - { (x: Int) -> Bool in expectUnreachable(); return true }), + { _ -> Bool in expectUnreachable(); return true }), - FilterTest([], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in false }), + FilterTest([], [ 0, 30, 10, 90 ], { _ -> Bool in false }), FilterTest( - [ 0, 30, 10, 90 ], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in true } + [ 0, 30, 10, 90 ], [ 0, 30, 10, 90 ], { _ -> Bool in true } ), FilterTest( [ 0, 30, 90 ], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in x % 3 == 0 } @@ -572,7 +572,7 @@ public let flatMapTests = [ FlatMapTest( expected: [], sequence: [], - transform: { (x: Int) -> [Int32] in + transform: { _ -> [Int32] in expectUnreachable() return [ 0xffff ] }), @@ -580,15 +580,15 @@ public let flatMapTests = [ FlatMapTest( expected: [], sequence: [ 1 ], - transform: { (x: Int) -> [Int32] in [] }), + transform: { _ -> [Int32] in [] }), FlatMapTest( expected: [], sequence: [ 1, 2 ], - transform: { (x: Int) -> [Int32] in [] }), + transform: { _ -> [Int32] in [] }), FlatMapTest( expected: [], sequence: [ 1, 2, 3 ], - transform: { (x: Int) -> [Int32] in [] }), + transform: { _ -> [Int32] in [] }), FlatMapTest( expected: [ 101 ], @@ -659,11 +659,11 @@ public let flatMapTests = [ public let flatMapToOptionalTests = [ FlatMapToOptionalTest( [], [], - { (x: Int) -> Int32? in expectUnreachable(); return 0xffff }), + { _ -> Int32? in expectUnreachable(); return 0xffff }), - FlatMapToOptionalTest([], [ 1 ], { (x: Int) -> Int32? in nil }), - FlatMapToOptionalTest([], [ 1, 2 ], { (x: Int) -> Int32? in nil }), - FlatMapToOptionalTest([], [ 1, 2, 3 ], { (x: Int) -> Int32? in nil }), + FlatMapToOptionalTest([], [ 1 ], { _ -> Int32? in nil }), + FlatMapToOptionalTest([], [ 1, 2 ], { _ -> Int32? in nil }), + FlatMapToOptionalTest([], [ 1, 2, 3 ], { _ -> Int32? in nil }), FlatMapToOptionalTest( [ 1 ], [ 1 ], @@ -788,7 +788,7 @@ public let lexicographicallyPrecedesTests = [ public let mapTests = [ MapTest( [], [], - { (x: Int) -> Int32 in expectUnreachable(); return 0xffff }), + { _ -> Int32 in expectUnreachable(); return 0xffff }), MapTest([ 101 ], [ 1 ], { (x: Int) -> Int32 in x + 100 }), MapTest([ 101, 102 ], [ 1, 2 ], { (x: Int) -> Int32 in x + 100 }), @@ -1941,7 +1941,7 @@ self.test("\(testNamePrefix)._preprocessingPass/semantics") { var result: OpaqueValue? do { result = try s._preprocessingPass { - (sequence) -> OpaqueValue in + _ -> OpaqueValue in wasInvoked = true throw TestError.error2 } diff --git a/stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift.gyb b/stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift.gyb index 8e6024c149718..dbb745b3efbe7 100644 --- a/stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift.gyb +++ b/stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift.gyb @@ -215,7 +215,7 @@ public struct ${Self}< public typealias Iterator = LoggingIterator - public func makeIterator() -> LoggingIterator { + public func makeIterator() -> Iterator { Log.makeIterator[selfType] += 1 return LoggingIterator(wrapping: base.makeIterator()) } @@ -321,10 +321,11 @@ public struct ${Self}< /// Copy a Sequence into an array. public func _copyContents( - initializing ptr: UnsafeMutablePointer - ) -> UnsafeMutablePointer { + initializing buffer: UnsafeMutableBufferPointer + ) -> (Iterator,UnsafeMutableBufferPointer.Index) { Log._copyContents[selfType] += 1 - return base._copyContents(initializing: ptr) + let (it,idx) = base._copyContents(initializing: buffer) + return (Iterator(wrapping: it),idx) } % if Kind in ['Collection', 'MutableCollection', 'RangeReplaceableCollection']: diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index a1ac473cf4bca..3eef7b5c1cc41 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -432,7 +432,7 @@ func _masterThreadOneTrial( sharedState.raceData.removeAll(keepingCapacity: true) - sharedState.raceData.append(contentsOf: (0..( sharedState.workerStates.removeAll(keepingCapacity: true) sharedState.workerStates.append(contentsOf: (0..() // Shuffle the data so that threads process it in different order. @@ -678,7 +678,7 @@ public func consumeCPU(units amountOfWork: Int) { } internal struct ClosureBasedRaceTest : RaceTestWithPerTrialData { - static var thread: () -> () = {} + static var thread: () -> Void = {} class RaceData {} typealias ThreadLocalData = Void @@ -703,7 +703,7 @@ public func runRaceTest( trials: Int, timeoutInSeconds: Int? = nil, threads: Int? = nil, - invoking body: @escaping () -> () + invoking body: @escaping () -> Void ) { ClosureBasedRaceTest.thread = body runRaceTest(ClosureBasedRaceTest.self, trials: trials, @@ -714,7 +714,7 @@ public func runRaceTest( operations: Int, timeoutInSeconds: Int? = nil, threads: Int? = nil, - invoking body: @escaping () -> () + invoking body: @escaping () -> Void ) { ClosureBasedRaceTest.thread = body runRaceTest(ClosureBasedRaceTest.self, operations: operations, diff --git a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift index 97eccddaf3d27..80c2b4b85073e 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift @@ -267,10 +267,10 @@ public func posixWaitpid(_ pid: pid_t) -> ProcessTerminationStatus { if waitpid(pid, &status, 0) < 0 { preconditionFailure("waitpid() failed") } - if (WIFEXITED(status)) { + if WIFEXITED(status) { return .exit(Int(WEXITSTATUS(status))) } - if (WIFSIGNALED(status)) { + if WIFSIGNALED(status) { return .signal(Int(WTERMSIG(status))) } preconditionFailure("did not understand what happened to child process") diff --git a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift index f6666c2030f57..511309d169d94 100644 --- a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift +++ b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift @@ -394,22 +394,22 @@ public func reflect(error: T) { /// Wraps a thick function with arity 0. struct ThickFunction0 { - var function: () -> () + var function: () -> Void } /// Wraps a thick function with arity 1. struct ThickFunction1 { - var function: (Int) -> () + var function: (Int) -> Void } /// Wraps a thick function with arity 2. struct ThickFunction2 { - var function: (Int, String) -> () + var function: (Int, String) -> Void } /// Wraps a thick function with arity 3. struct ThickFunction3 { - var function: (Int, String, AnyObject?) -> () + var function: (Int, String, AnyObject?) -> Void } struct ThickFunctionParts { @@ -419,7 +419,7 @@ struct ThickFunctionParts { /// Reflect a closure context. The given function must be a Swift-native /// @convention(thick) function value. -public func reflect(function: @escaping () -> ()) { +public func reflect(function: @escaping () -> Void) { let fn = UnsafeMutablePointer.allocate( capacity: MemoryLayout.size) fn.initialize(to: ThickFunction0(function: function)) @@ -434,7 +434,7 @@ public func reflect(function: @escaping () -> ()) { /// Reflect a closure context. The given function must be a Swift-native /// @convention(thick) function value. -public func reflect(function: @escaping (Int) -> ()) { +public func reflect(function: @escaping (Int) -> Void) { let fn = UnsafeMutablePointer.allocate( capacity: MemoryLayout.size) @@ -450,7 +450,7 @@ public func reflect(function: @escaping (Int) -> ()) { /// Reflect a closure context. The given function must be a Swift-native /// @convention(thick) function value. -public func reflect(function: @escaping (Int, String) -> ()) { +public func reflect(function: @escaping (Int, String) -> Void) { let fn = UnsafeMutablePointer.allocate( capacity: MemoryLayout.size) fn.initialize(to: ThickFunction2(function: function)) @@ -465,7 +465,7 @@ public func reflect(function: @escaping (Int, String) -> ()) { /// Reflect a closure context. The given function must be a Swift-native /// @convention(thick) function value. -public func reflect(function: @escaping (Int, String, AnyObject?) -> ()) { +public func reflect(function: @escaping (Int, String, AnyObject?) -> Void) { let fn = UnsafeMutablePointer.allocate( capacity: MemoryLayout.size) fn.initialize(to: ThickFunction3(function: function)) diff --git a/stdlib/public/SDK/Dispatch/Block.swift b/stdlib/public/SDK/Dispatch/Block.swift index 691e95ed18535..4ae98c5ab9250 100644 --- a/stdlib/public/SDK/Dispatch/Block.swift +++ b/stdlib/public/SDK/Dispatch/Block.swift @@ -38,7 +38,7 @@ public struct DispatchWorkItemFlags : OptionSet, RawRepresentable { public class DispatchWorkItem { internal var _block: _DispatchBlock - public init(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @escaping @convention(block) () -> ()) { + public init(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], block: @escaping @convention(block) () -> Void) { _block = _swift_dispatch_block_create_with_qos_class( __dispatch_block_flags_t(rawValue: flags.rawValue), qos.qosClass.rawValue, Int32(qos.relativePriority), block) @@ -46,7 +46,7 @@ public class DispatchWorkItem { // Used by DispatchQueue.synchronously to provide a path through // dispatch_block_t, as we know the lifetime of the block in question. - internal init(flags: DispatchWorkItemFlags = [], noescapeBlock: () -> ()) { + internal init(flags: DispatchWorkItemFlags = [], noescapeBlock: () -> Void) { _block = _swift_dispatch_block_create_noescape( __dispatch_block_flags_t(rawValue: flags.rawValue), noescapeBlock) } diff --git a/stdlib/public/SDK/Dispatch/Data.swift b/stdlib/public/SDK/Dispatch/Data.swift index b32132c0bc0a4..2cf9f1b74f956 100644 --- a/stdlib/public/SDK/Dispatch/Data.swift +++ b/stdlib/public/SDK/Dispatch/Data.swift @@ -121,7 +121,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: CountableRange) { var copiedCount = 0 - __dispatch_data_apply(__wrapped) { (data: __DispatchData, offset: Int, ptr: UnsafeRawPointer, size: Int) in + __dispatch_data_apply(__wrapped) { (_, _, ptr: UnsafeRawPointer, size: Int) in let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size) memcpy(pointer + copiedCount, ptr, limit) copiedCount += limit diff --git a/stdlib/public/SDK/Dispatch/Dispatch.swift b/stdlib/public/SDK/Dispatch/Dispatch.swift index 9ad6b646b256c..4479c9313a7a6 100644 --- a/stdlib/public/SDK/Dispatch/Dispatch.swift +++ b/stdlib/public/SDK/Dispatch/Dispatch.swift @@ -130,7 +130,7 @@ public enum DispatchTimeoutResult { /// dispatch_group public extension DispatchGroup { - public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute work: @escaping @convention(block) () -> ()) { + public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute work: @escaping @convention(block) () -> Void) { if #available(OSX 10.10, iOS 8.0, *), qos != .unspecified || !flags.isEmpty { let item = DispatchWorkItem(qos: qos, flags: flags, block: work) _swift_dispatch_group_notify(self, queue, item._block) diff --git a/stdlib/public/SDK/Dispatch/Queue.swift b/stdlib/public/SDK/Dispatch/Queue.swift index 7862823873fb5..d2cb15acd48ce 100644 --- a/stdlib/public/SDK/Dispatch/Queue.swift +++ b/stdlib/public/SDK/Dispatch/Queue.swift @@ -221,12 +221,12 @@ public extension DispatchQueue { } } - private func _syncBarrier(block: () -> ()) { + private func _syncBarrier(block: () -> Void) { __dispatch_barrier_sync(self, block) } private func _syncHelper( - fn: (() -> ()) -> (), + fn: (() -> Void) -> Void, execute work: () throws -> T, rescue: ((Error) throws -> (T))) rethrows -> T { @@ -248,7 +248,7 @@ public extension DispatchQueue { @available(OSX 10.10, iOS 8.0, *) private func _syncHelper( - fn: (DispatchWorkItem) -> (), + fn: (DispatchWorkItem) -> Void, flags: DispatchWorkItemFlags, execute work: () throws -> T, rescue: ((Error) throws -> (T))) rethrows -> T diff --git a/stdlib/public/SDK/Foundation/Boxing.swift b/stdlib/public/SDK/Foundation/Boxing.swift index 4e126bc2dd0d3..a4ead27e6299d 100644 --- a/stdlib/public/SDK/Foundation/Boxing.swift +++ b/stdlib/public/SDK/Foundation/Boxing.swift @@ -157,7 +157,7 @@ extension _MutablePairBoxing { let unmanagedHandle = Unmanaged.passUnretained(_wrapped) let wrapper = unmanagedHandle._withUnsafeGuaranteedRef { $0.__wrapped } - switch (wrapper) { + switch wrapper { case .Immutable(let i): return try i._withUnsafeGuaranteedRef { return try whatToDo($0) @@ -185,14 +185,14 @@ extension _MutablePairBoxing { let wrapper = _unmanagedHandle._withUnsafeGuaranteedRef { $0.__wrapped } // This check is done twice because: Value kept live for too long causing uniqueness check to fail - switch (wrapper) { + switch wrapper { case .Immutable(_): break case .Mutable(_): unique = isKnownUniquelyReferenced(&_wrapped) } - switch (wrapper) { + switch wrapper { case .Immutable(let i): // We need to become mutable; by creating a new instance we also become unique let copy = Unmanaged.passRetained(i._withUnsafeGuaranteedRef { diff --git a/stdlib/public/SDK/Foundation/Calendar.swift b/stdlib/public/SDK/Foundation/Calendar.swift index 9408d019d6cf7..357ec4c70e800 100644 --- a/stdlib/public/SDK/Foundation/Calendar.swift +++ b/stdlib/public/SDK/Foundation/Calendar.swift @@ -1077,9 +1077,9 @@ public struct Calendar : Hashable, Equatable, ReferenceConvertible, _MutableBoxi extension Calendar : CustomDebugStringConvertible, CustomStringConvertible, CustomReflectable { private var _kindDescription : String { - if (self == Calendar.autoupdatingCurrent) { + if self == Calendar.autoupdatingCurrent { return "autoupdatingCurrent" - } else if (self == Calendar.current) { + } else if self == Calendar.current { return "current" } else { return "fixed" diff --git a/stdlib/public/SDK/Foundation/CharacterSet.swift b/stdlib/public/SDK/Foundation/CharacterSet.swift index 5319f922b1f86..851e6c78b7302 100644 --- a/stdlib/public/SDK/Foundation/CharacterSet.swift +++ b/stdlib/public/SDK/Foundation/CharacterSet.swift @@ -509,7 +509,7 @@ extension _SwiftNSCharacterSet { @objc(hasMemberInPlane:) func hasMember(inPlane plane: UInt8) -> Bool { - return _mapUnmanaged {$0.hasMemberInPlane(plane) } + return _mapUnmanaged { $0.hasMemberInPlane(plane) } } @objc(characterIsMember:) diff --git a/stdlib/public/SDK/Foundation/Data.swift b/stdlib/public/SDK/Foundation/Data.swift index 6eba0fa95910c..3718bda84ae3f 100644 --- a/stdlib/public/SDK/Foundation/Data.swift +++ b/stdlib/public/SDK/Foundation/Data.swift @@ -20,11 +20,11 @@ import Glibc import CoreFoundation -internal func __NSDataInvokeDeallocatorUnmap(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void { +internal func __NSDataInvokeDeallocatorUnmap(_ mem: UnsafeMutableRawPointer, _ length: Int) { munmap(mem, length) } -internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void { +internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) { free(mem) } @@ -33,13 +33,13 @@ internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ le @_exported import Foundation // Clang module @_silgen_name("__NSDataInvokeDeallocatorVM") -internal func __NSDataInvokeDeallocatorVM(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void +internal func __NSDataInvokeDeallocatorVM(_ mem: UnsafeMutableRawPointer, _ length: Int) @_silgen_name("__NSDataInvokeDeallocatorUnmap") -internal func __NSDataInvokeDeallocatorUnmap(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void +internal func __NSDataInvokeDeallocatorUnmap(_ mem: UnsafeMutableRawPointer, _ length: Int) @_silgen_name("__NSDataInvokeDeallocatorFree") -internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void +internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) @_silgen_name("_NSWriteDataToFile_Swift") internal func _NSWriteDataToFile_Swift(url: NSURL, data: NSData, options: UInt, error: NSErrorPointer) -> Bool @@ -48,7 +48,7 @@ internal func _NSWriteDataToFile_Swift(url: NSURL, data: NSData, options: UInt, public final class _DataStorage { public enum Backing { - // A mirror of the Objective-C implementation that is suitable to inline in Swift + // A mirror of the objective-c implementation that is suitable to inline in swift case swift // these two storage points for immutable and mutable data are reserved for references that are returned by "known" @@ -59,8 +59,8 @@ public final class _DataStorage { case immutable(NSData) // This will most often (perhaps always) be NSConcreteData case mutable(NSMutableData) // This will often (perhaps always) be NSConcreteMutableData - // These are reserved for foreign sources where neither Swift nor Foundation are fully certain whom they belong - // to from an object inheritance standpoint, this means that all bets are off and the values of bytes, mutableBytes, + // These are reserved for foregin sources where neither Swift nor Foundation are fully certain whom they belong + // to from a object inheritance standpoint, this means that all bets are off and the values of bytes, mutableBytes, // and length cannot be cached. This also means that all methods are expected to dynamically dispatch out to the // backing reference. case customReference(NSData) // tracks data references that are only known to be immutable @@ -91,7 +91,7 @@ public final class _DataStorage { num -= pages } if num > 0 { - memmove(dest, source!, num) + memmove(dest, source, num) } } @@ -103,7 +103,7 @@ public final class _DataStorage { public var _length: Int public var _capacity: Int public var _needToZero: Bool - public var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)? = nil + public var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)? public var _backing: Backing = .swift public var bytes: UnsafeRawPointer? { @@ -233,8 +233,8 @@ public final class _DataStorage { newBytes = _DataStorage.allocate(newCapacity, allocateCleared) if newBytes == nil { /* Try again with minimum length */ - allocateCleared = clear && _DataStorage.shouldAllocateCleared(newLength); - newBytes = _DataStorage.allocate(newLength, allocateCleared); + allocateCleared = clear && _DataStorage.shouldAllocateCleared(newLength) + newBytes = _DataStorage.allocate(newLength, allocateCleared) } } else { let tryCalloc = (origLength == 0 || (newLength / origLength) >= 4) @@ -304,9 +304,9 @@ public final class _DataStorage { let newLength = length if _capacity < newLength || _bytes == nil { _grow(newLength, true) - } else if (origLength < newLength && _needToZero) { + } else if origLength < newLength && _needToZero { memset(_bytes! + origLength, 0, newLength - origLength) - } else if (newLength < origLength) { + } else if newLength < origLength { _needToZero = true } _length = newLength @@ -382,7 +382,7 @@ public final class _DataStorage { @inline(__always) public func append(_ otherData: Data) { - otherData.enumerateBytes { (buffer: UnsafeBufferPointer, location: Data.Index, stop: inout Bool) in + otherData.enumerateBytes { (buffer: UnsafeBufferPointer, _, _) in append(buffer.baseAddress!, length: buffer.count) } } @@ -500,7 +500,7 @@ public final class _DataStorage { } if replacementLength != 0 { if replacementBytes != nil { - memmove(mutableBytes! + start, replacementBytes!, replacementLength) + memmove(mutableBytes! + start, replacementBytes, replacementLength) } else { memset(mutableBytes! + start, 0, replacementLength) } @@ -580,7 +580,7 @@ public final class _DataStorage { public init(length: Int) { precondition(length < _DataStorage.maxSize) var capacity = (length < 1024 * 1024 * 1024) ? length + (length >> 2) : length - if (_DataStorage.vmOpsThreshold <= capacity) { + if _DataStorage.vmOpsThreshold <= capacity { capacity = NSRoundUpToMultipleOfPageSize(capacity) } @@ -596,7 +596,7 @@ public final class _DataStorage { public init(capacity capacity_: Int) { var capacity = capacity_ precondition(capacity < _DataStorage.maxSize) - if (_DataStorage.vmOpsThreshold <= capacity) { + if _DataStorage.vmOpsThreshold <= capacity { capacity = NSRoundUpToMultipleOfPageSize(capacity) } _length = 0 @@ -620,7 +620,7 @@ public final class _DataStorage { _DataStorage.move(_bytes!, bytes, length) } else { var capacity = length - if (_DataStorage.vmOpsThreshold <= capacity) { + if _DataStorage.vmOpsThreshold <= capacity { capacity = NSRoundUpToMultipleOfPageSize(capacity) } _length = length @@ -659,7 +659,7 @@ public final class _DataStorage { } } else { var capacity = length - if (_DataStorage.vmOpsThreshold <= capacity) { + if _DataStorage.vmOpsThreshold <= capacity { capacity = NSRoundUpToMultipleOfPageSize(capacity) } _length = length @@ -759,7 +759,7 @@ public final class _DataStorage { return d case .customMutableReference(let d): // Because this is returning an object that may be mutated in the future it needs to create a copy to prevent - // any further mutations out from under the receiver + // any further mutations out from under the reciever return d.copy() as! NSData } } @@ -822,10 +822,7 @@ public final class _DataStorage { if lhs.bytes == rhs.bytes { return true } - if length1 > 0 { - return memcmp(lhs._bytes!, rhs._bytes!, length1) == 0 - } - return true + return memcmp(lhs._bytes, rhs._bytes, length1) == 0 } } @@ -868,7 +865,7 @@ internal class _NSSwiftData : NSData { override var bytes: UnsafeRawPointer { // NSData's byte pointer methods are not annotated for nullability correctly // (but assume non-null by the wrapping macro guards). This placeholder value - // is to work-around this bug. Any indirection to the underlying bytes of an NSData + // is to work-around this bug. Any indirection to the underlying bytes of a NSData // with a length of zero would have been a programmer error anyhow so the actual // return value here is not needed to be an allocated value. This is specifically // needed to live like this to be source compatible with Swift3. Beyond that point @@ -910,8 +907,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl public typealias Index = Int public typealias Indices = CountableRange - - @_versioned + internal var _backing : _DataStorage // A standard or custom deallocator for `Data`. @@ -935,7 +931,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl /// A custom deallocator. case custom((UnsafeMutableRawPointer, Int) -> Void) - fileprivate var _deallocator : ((UnsafeMutableRawPointer, Int) -> Void) { + fileprivate var _deallocator : ((UnsafeMutableRawPointer, Int) -> Void)? { #if DEPLOYMENT_RUNTIME_SWIFT switch self { case .unmap: @@ -943,7 +939,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl case .free: return { __NSDataInvokeDeallocatorFree($0, $1) } case .none: - return { _, _ in } + return nil case .custom(let b): return { (ptr, len) in b(ptr, len) @@ -958,7 +954,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl case .free: return { __NSDataInvokeDeallocatorFree($0, $1) } case .none: - return { _, _ in } + return nil case .custom(let b): return { (ptr, len) in b(ptr, len) @@ -1425,11 +1421,11 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl // In the future, if we keep the malloced pointer and count inside this struct/ref instead of deferring to NSData, we may be able to do this more efficiently. self.count = resultCount } - + let shift = resultCount - currentCount let start = subrange.lowerBound - self.withUnsafeMutableBytes { (bytes : UnsafeMutablePointer) -> () in + self.withUnsafeMutableBytes { (bytes : UnsafeMutablePointer) -> Void in if shift != 0 { let destination = bytes + start + replacementCount let source = bytes + start + subrangeCount @@ -1437,7 +1433,11 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl } if replacementCount != 0 { - newElements._copyContents(initializing: bytes + start) + let buf = UnsafeMutableBufferPointer(start: bytes + start, + count: replacementCount) + var (it,idx) = newElements._copyContents(initializing: buf) + precondition(it.next() == nil && idx == buf.endIndex, + "newElements iterator returned different count to newElements.count") } } } @@ -1642,10 +1642,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl if backing1.bytes == backing2.bytes { return true } - if length1 > 0 { - return memcmp(backing1.bytes!, backing2.bytes!, length1) == 0 - } - return true + return memcmp(backing1.bytes, backing2.bytes, length1) == 0 } } diff --git a/stdlib/public/SDK/Foundation/FileManager.swift b/stdlib/public/SDK/Foundation/FileManager.swift index 45987159f96c9..a4b24adf1b815 100644 --- a/stdlib/public/SDK/Foundation/FileManager.swift +++ b/stdlib/public/SDK/Foundation/FileManager.swift @@ -56,7 +56,7 @@ extension FileManager { @available(OSX 10.6, iOS 4.0, *) public func enumerator(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = [], errorHandler handler: ((URL, Error) -> Bool)? = nil) -> FileManager.DirectoryEnumerator? { return NS_Swift_NSFileManager_enumeratorAt_includingPropertiesForKeys_options_errorHandler(self, url as NSURL, keys as NSArray?, mask, { (url, error) in - var errorResult = true; + var errorResult = true if let h = handler { errorResult = h(url as URL, error) } diff --git a/stdlib/public/SDK/Foundation/Locale.swift b/stdlib/public/SDK/Foundation/Locale.swift index 614ad42ecbe55..4dbe924a805e8 100644 --- a/stdlib/public/SDK/Foundation/Locale.swift +++ b/stdlib/public/SDK/Foundation/Locale.swift @@ -435,9 +435,9 @@ public struct Locale : Hashable, Equatable, ReferenceConvertible { extension Locale : CustomDebugStringConvertible, CustomStringConvertible, CustomReflectable { private var _kindDescription : String { - if (self == Locale.autoupdatingCurrent) { + if self == Locale.autoupdatingCurrent { return "autoupdatingCurrent" - } else if (self == Locale.current) { + } else if self == Locale.current { return "current" } else { return "fixed" diff --git a/stdlib/public/SDK/Foundation/NSDictionary.swift b/stdlib/public/SDK/Foundation/NSDictionary.swift index fa81153d276e9..7dfb9fb990c38 100644 --- a/stdlib/public/SDK/Foundation/NSDictionary.swift +++ b/stdlib/public/SDK/Foundation/NSDictionary.swift @@ -82,9 +82,7 @@ extension Dictionary : _ObjectiveCBridgeable { // `Dictionary` where either `Key` or `Value` is a value type // may not be backed by an NSDictionary. var builder = _DictionaryBuilder(count: d.count) - d.enumerateKeysAndObjects({ - (anyKey: Any, anyValue: Any, - stop: UnsafeMutablePointer) in + d.enumerateKeysAndObjects({ (anyKey: Any, anyValue: Any, _) in let anyObjectKey = anyKey as AnyObject let anyObjectValue = anyValue as AnyObject builder.add( @@ -130,9 +128,7 @@ extension Dictionary : _ObjectiveCBridgeable { // `Dictionary` where either `Key` or `Value` is a value type // may not be backed by an NSDictionary. var builder = _DictionaryBuilder(count: d!.count) - d!.enumerateKeysAndObjects({ - (anyKey: Any, anyValue: Any, - stop: UnsafeMutablePointer) in + d!.enumerateKeysAndObjects({ (anyKey: Any, anyValue: Any, _) in builder.add( key: Swift._forceBridgeFromObjectiveC(anyKey as AnyObject, Key.self), value: Swift._forceBridgeFromObjectiveC(anyValue as AnyObject, Value.self)) diff --git a/stdlib/public/SDK/Foundation/NSSet.swift b/stdlib/public/SDK/Foundation/NSSet.swift index 5f26ec70e14f3..6759a99fa85e9 100644 --- a/stdlib/public/SDK/Foundation/NSSet.swift +++ b/stdlib/public/SDK/Foundation/NSSet.swift @@ -76,8 +76,7 @@ extension Set : _ObjectiveCBridgeable { // `Set` where `Element` is a value type may not be backed by // an NSSet. var builder = _SetBuilder(count: s.count) - s.enumerateObjects({ - (anyMember: Any, stop: UnsafeMutablePointer) in + s.enumerateObjects({ (anyMember: Any, _) in builder.add(member: Swift._forceBridgeFromObjectiveC( anyMember as AnyObject, Element.self)) }) @@ -116,8 +115,7 @@ extension Set : _ObjectiveCBridgeable { // `Set` where `Element` is a value type may not be backed by // an NSSet. var builder = _SetBuilder(count: s!.count) - s!.enumerateObjects({ - (anyMember: Any, stop: UnsafeMutablePointer) in + s!.enumerateObjects({ (anyMember: Any, _) in builder.add(member: Swift._forceBridgeFromObjectiveC( anyMember as AnyObject, Element.self)) }) diff --git a/stdlib/public/SDK/Foundation/NSStringAPI.swift b/stdlib/public/SDK/Foundation/NSStringAPI.swift index d8150ef21f845..f59d03bbffc28 100644 --- a/stdlib/public/SDK/Foundation/NSStringAPI.swift +++ b/stdlib/public/SDK/Foundation/NSStringAPI.swift @@ -468,7 +468,7 @@ extension String { /// Enumerates all the lines in a string. public func enumerateLines( - invoking body: @escaping (_ line: String, _ stop: inout Bool) -> () + invoking body: @escaping (_ line: String, _ stop: inout Bool) -> Void ) { _ns.enumerateLines { (line: String, stop: UnsafeMutablePointer) @@ -501,7 +501,7 @@ extension String { options opts: NSLinguisticTagger.Options = [], orthography: NSOrthography? = nil, invoking body: - (String, Range, Range, inout Bool) -> () + (String, Range, Range, inout Bool) -> Void ) { _ns.enumerateLinguisticTags( in: _toNSRange(range), @@ -536,7 +536,7 @@ extension String { _ body: @escaping ( _ substring: String?, _ substringRange: Range, _ enclosingRange: Range, inout Bool - ) -> () + ) -> Void ) { _ns.enumerateSubstrings(in: _toNSRange(range), options: opts) { var stop_ = false @@ -1736,7 +1736,7 @@ extension String { options opts: NSLinguisticTagger.Options, orthography: NSOrthography?, _ body: - (String, Range, Range, inout Bool) -> () + (String, Range, Range, inout Bool) -> Void ) { fatalError("unavailable function can't be called") } @@ -1748,7 +1748,7 @@ extension String { _ body: ( _ substring: String?, _ substringRange: Range, _ enclosingRange: Range, inout Bool - ) -> () + ) -> Void ) { fatalError("unavailable function can't be called") } diff --git a/stdlib/public/SDK/Foundation/TimeZone.swift b/stdlib/public/SDK/Foundation/TimeZone.swift index 151c7e2dceb4e..135026c2870f6 100644 --- a/stdlib/public/SDK/Foundation/TimeZone.swift +++ b/stdlib/public/SDK/Foundation/TimeZone.swift @@ -223,9 +223,9 @@ public struct TimeZone : Hashable, Equatable, ReferenceConvertible { extension TimeZone : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable { private var _kindDescription : String { - if (self == TimeZone.autoupdatingCurrent) { + if self == TimeZone.autoupdatingCurrent { return "autoupdatingCurrent" - } else if (self == TimeZone.current) { + } else if self == TimeZone.current { return "current" } else { return "fixed" diff --git a/stdlib/public/SDK/Foundation/URLComponents.swift b/stdlib/public/SDK/Foundation/URLComponents.swift index 99f488f290474..427ad8555a746 100644 --- a/stdlib/public/SDK/Foundation/URLComponents.swift +++ b/stdlib/public/SDK/Foundation/URLComponents.swift @@ -219,7 +219,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfUser: Range? { - return _toStringRange(_handle.map { $0.rangeOfUser}) + return _toStringRange(_handle.map { $0.rangeOfUser }) } /// Returns the character range of the password in the string returned by `var string`. @@ -228,7 +228,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfPassword: Range? { - return _toStringRange(_handle.map { $0.rangeOfPassword}) + return _toStringRange(_handle.map { $0.rangeOfPassword }) } /// Returns the character range of the host in the string returned by `var string`. @@ -237,7 +237,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfHost: Range? { - return _toStringRange(_handle.map { $0.rangeOfHost}) + return _toStringRange(_handle.map { $0.rangeOfHost }) } /// Returns the character range of the port in the string returned by `var string`. @@ -246,7 +246,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfPort: Range? { - return _toStringRange(_handle.map { $0.rangeOfPort}) + return _toStringRange(_handle.map { $0.rangeOfPort }) } /// Returns the character range of the path in the string returned by `var string`. @@ -255,7 +255,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfPath: Range? { - return _toStringRange(_handle.map { $0.rangeOfPath}) + return _toStringRange(_handle.map { $0.rangeOfPath }) } /// Returns the character range of the query in the string returned by `var string`. @@ -264,7 +264,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfQuery: Range? { - return _toStringRange(_handle.map { $0.rangeOfQuery}) + return _toStringRange(_handle.map { $0.rangeOfQuery }) } /// Returns the character range of the fragment in the string returned by `var string`. @@ -273,7 +273,7 @@ public struct URLComponents : ReferenceConvertible, Hashable, Equatable, _Mutabl /// - note: Zero length components are legal. For example, the URL string "scheme://:@/?#" has a zero length user, password, host, query and fragment; the URL strings "scheme:" and "" both have a zero length path. @available(OSX 10.11, iOS 9.0, *) public var rangeOfFragment: Range? { - return _toStringRange(_handle.map { $0.rangeOfFragment}) + return _toStringRange(_handle.map { $0.rangeOfFragment }) } /// Returns an array of query items for this `URLComponents`, in the order in which they appear in the original query string. diff --git a/stdlib/public/SDK/OpenCL/OpenCL.swift b/stdlib/public/SDK/OpenCL/OpenCL.swift index 5edacacca6cd7..c40baa0dfd6a5 100644 --- a/stdlib/public/SDK/OpenCL/OpenCL.swift +++ b/stdlib/public/SDK/OpenCL/OpenCL.swift @@ -20,5 +20,5 @@ public func clSetKernelArgsListAPPLE( // cl_uint arg_indx, // size_t arg_size, // const void *arg_value, - return withVaList(args) { clSetKernelArgsVaListAPPLE(kernel, uint, $0) } + return withVaList(args) { clSetKernelArgsVaListAPPLE(kernel, uint, $0) } } diff --git a/stdlib/public/SDK/UIKit/UIKit.swift b/stdlib/public/SDK/UIKit/UIKit.swift index 8f8db803fe94e..a11e9989c39c5 100644 --- a/stdlib/public/SDK/UIKit/UIKit.swift +++ b/stdlib/public/SDK/UIKit/UIKit.swift @@ -74,7 +74,7 @@ public extension UIDeviceOrientation { } var isValidInterfaceOrientation: Bool { - switch (self) { + switch self { case .portrait, .portraitUpsideDown, .landscapeLeft, .landscapeRight: return true default: diff --git a/stdlib/public/SDK/XCTest/XCTest.swift b/stdlib/public/SDK/XCTest/XCTest.swift index aadbfdccb2657..45b75f89d59c5 100644 --- a/stdlib/public/SDK/XCTest/XCTest.swift +++ b/stdlib/public/SDK/XCTest/XCTest.swift @@ -18,7 +18,7 @@ import _SwiftXCTestOverlayShims // --- Failure Formatting --- /// Register the failure, expected or unexpected, of the current test case. -func _XCTRegisterFailure(_ expected: Bool, _ condition: String, _ message: @autoclosure () -> String, _ file: StaticString, _ line: UInt) -> Void { +func _XCTRegisterFailure(_ expected: Bool, _ condition: String, _ message: @autoclosure () -> String, _ file: StaticString, _ line: UInt) { // Call the real _XCTFailureHandler. let test = _XCTCurrentTestCase() _XCTPreformattedFailureHandler(test, expected, file.description, line, condition, message()) @@ -82,13 +82,13 @@ func _XCTRunThrowableBlock(_ block: () throws -> Void) -> _XCTThrowableBlockResu // --- Supported Assertions --- -public func XCTFail(_ message: String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTFail(_ message: String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.fail _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, "" as NSString), message, file, line) } -public func XCTAssertNil(_ expression: @autoclosure () throws -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNil(_ expression: @autoclosure () throws -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.`nil` // evaluate the expression exactly once @@ -127,7 +127,7 @@ public func XCTAssertNil(_ expression: @autoclosure () throws -> Any?, _ message } } -public func XCTAssertNotNil(_ expression: @autoclosure () throws -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotNil(_ expression: @autoclosure () throws -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notNil // evaluate the expression exactly once @@ -166,12 +166,12 @@ public func XCTAssertNotNil(_ expression: @autoclosure () throws -> Any?, _ mess } } -public func XCTAssert(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssert(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { // XCTAssert is just a cover for XCTAssertTrue. XCTAssertTrue(expression, message, file: file, line: line) } -public func XCTAssertTrue(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertTrue(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.`true` // evaluate the expression exactly once @@ -202,7 +202,7 @@ public func XCTAssertTrue(_ expression: @autoclosure () throws -> Bool, _ messag } } -public func XCTAssertFalse(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertFalse(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.`false` // evaluate the expression exactly once @@ -233,7 +233,7 @@ public func XCTAssertFalse(_ expression: @autoclosure () throws -> Bool, _ messa } } -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equal // evaluate each expression exactly once @@ -271,7 +271,7 @@ public func XCTAssertEqual(_ expression1: @autoclosure () throws } } -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqual(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equal // evaluate each expression exactly once @@ -312,7 +312,7 @@ public func XCTAssertEqual(_ expression1: @autoclosure () throws // Array // Dictionary -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> ArraySlice, _ expression2: @autoclosure () throws -> ArraySlice, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqual(_ expression1: @autoclosure () throws -> ArraySlice, _ expression2: @autoclosure () throws -> ArraySlice, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equal // evaluate each expression exactly once @@ -350,7 +350,7 @@ public func XCTAssertEqual(_ expression1: @autoclosure () throws } } -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> ContiguousArray, _ expression2: @autoclosure () throws -> ContiguousArray, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqual(_ expression1: @autoclosure () throws -> ContiguousArray, _ expression2: @autoclosure () throws -> ContiguousArray, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equal // evaluate each expression exactly once @@ -388,7 +388,7 @@ public func XCTAssertEqual(_ expression1: @autoclosure () throws } } -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> [T], _ expression2: @autoclosure () throws -> [T], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqual(_ expression1: @autoclosure () throws -> [T], _ expression2: @autoclosure () throws -> [T], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equal // evaluate each expression exactly once @@ -426,7 +426,7 @@ public func XCTAssertEqual(_ expression1: @autoclosure () throws } } -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> [T: U], _ expression2: @autoclosure () throws -> [T: U], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqual(_ expression1: @autoclosure () throws -> [T: U], _ expression2: @autoclosure () throws -> [T: U], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equal // evaluate each expression exactly once @@ -464,7 +464,7 @@ public func XCTAssertEqual(_ expression1: @autoclosure () thro } } -public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqual // evaluate each expression exactly once @@ -502,7 +502,7 @@ public func XCTAssertNotEqual(_ expression1: @autoclosure () thro } } -public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqual // evaluate each expression exactly once @@ -543,7 +543,7 @@ public func XCTAssertNotEqual(_ expression1: @autoclosure () thro // Array // Dictionary -public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> ContiguousArray, _ expression2: @autoclosure () throws -> ContiguousArray, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> ContiguousArray, _ expression2: @autoclosure () throws -> ContiguousArray, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqual // evaluate each expression exactly once @@ -581,7 +581,7 @@ public func XCTAssertNotEqual(_ expression1: @autoclosure () thro } } -public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> ArraySlice, _ expression2: @autoclosure () throws -> ArraySlice, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> ArraySlice, _ expression2: @autoclosure () throws -> ArraySlice, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqual // evaluate each expression exactly once @@ -619,7 +619,7 @@ public func XCTAssertNotEqual(_ expression1: @autoclosure () thro } } -public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> [T], _ expression2: @autoclosure () throws -> [T], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> [T], _ expression2: @autoclosure () throws -> [T], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqual // evaluate each expression exactly once @@ -657,7 +657,7 @@ public func XCTAssertNotEqual(_ expression1: @autoclosure () thro } } -public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> [T: U], _ expression2: @autoclosure () throws -> [T: U], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqual(_ expression1: @autoclosure () throws -> [T: U], _ expression2: @autoclosure () throws -> [T: U], _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqual // evaluate each expression exactly once @@ -710,7 +710,7 @@ func _XCTCheckEqualWithAccuracy_CGFloat(_ value1: CGFloat, _ value2: CGFloat, _ && (abs(value1 - value2) <= accuracy) } -public func XCTAssertEqualWithAccuracy(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertEqualWithAccuracy(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.equalWithAccuracy // evaluate each expression exactly once @@ -781,7 +781,7 @@ func _XCTCheckNotEqualWithAccuracy_CGFloat(_ value1: CGFloat, _ value2: CGFloat, || (abs(value1 - value2) > accuracy) } -public func XCTAssertNotEqualWithAccuracy(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNotEqualWithAccuracy(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.notEqualWithAccuracy // evaluate each expression exactly once @@ -837,7 +837,7 @@ public func XCTAssertNotEqualWithAccuracy(_ expression1: @aut } } -public func XCTAssertGreaterThan(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertGreaterThan(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.greaterThan // evaluate each expression exactly once @@ -914,7 +914,7 @@ public func XCTAssertGreaterThanOrEqual(_ expression1: @autoclos } } -public func XCTAssertLessThan(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertLessThan(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.lessThan // evaluate each expression exactly once @@ -991,7 +991,7 @@ public func XCTAssertLessThanOrEqual(_ expression1: @autoclosure } } -public func XCTAssertThrowsError(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line, _ errorHandler: (_ error: Error) -> Void = { _ in }) -> Void { +public func XCTAssertThrowsError(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line, _ errorHandler: (_ error: Error) -> Void = { _ in }) { // evaluate expression exactly once var caughtErrorOptional: Error? @@ -1025,37 +1025,37 @@ public func XCTAssertThrowsError(_ expression: @autoclosure () throws -> T, _ #if XCTEST_ENABLE_EXCEPTION_ASSERTIONS // --- Currently-Unsupported Assertions --- -public func XCTAssertThrows(_ expression: @autoclosure () -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertThrows(_ expression: @autoclosure () -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.assertion_Throws // FIXME: Unsupported } -public func XCTAssertThrowsSpecific(_ expression: @autoclosure () -> Any?, _ exception: Any, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertThrowsSpecific(_ expression: @autoclosure () -> Any?, _ exception: Any, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.assertion_ThrowsSpecific // FIXME: Unsupported } -public func XCTAssertThrowsSpecificNamed(_ expression: @autoclosure () -> Any?, _ exception: Any, _ name: String, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertThrowsSpecificNamed(_ expression: @autoclosure () -> Any?, _ exception: Any, _ name: String, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.assertion_ThrowsSpecificNamed // FIXME: Unsupported } -public func XCTAssertNoThrow(_ expression: @autoclosure () -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNoThrow(_ expression: @autoclosure () -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.assertion_NoThrow // FIXME: Unsupported } -public func XCTAssertNoThrowSpecific(_ expression: @autoclosure () -> Any?, _ exception: Any, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNoThrowSpecific(_ expression: @autoclosure () -> Any?, _ exception: Any, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.assertion_NoThrowSpecific // FIXME: Unsupported } -public func XCTAssertNoThrowSpecificNamed(_ expression: @autoclosure () -> Any?, _ exception: Any, _ name: String, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Void { +public func XCTAssertNoThrowSpecificNamed(_ expression: @autoclosure () -> Any?, _ exception: Any, _ name: String, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { let assertionType = _XCTAssertionType.assertion_NoThrowSpecificNamed // FIXME: Unsupported diff --git a/stdlib/public/core/ArrayType.swift b/stdlib/public/core/ArrayType.swift index f7e6ea897d1de..0cbcf5d1a7afe 100644 --- a/stdlib/public/core/ArrayType.swift +++ b/stdlib/public/core/ArrayType.swift @@ -43,10 +43,6 @@ internal protocol _ArrayProtocol /// - Complexity: O(`self.count`). mutating func reserveCapacity(_ minimumCapacity: Int) - /// Operator form of `append(contentsOf:)`. - static func += (lhs: inout Self, rhs: S) - where S.Iterator.Element == Iterator.Element - /// Insert `newElement` at index `i`. /// /// Invalidates all indices with respect to `self`. diff --git a/stdlib/public/core/Arrays.swift.gyb b/stdlib/public/core/Arrays.swift.gyb index 48d51838f4e51..9937e80cc66a9 100644 --- a/stdlib/public/core/Arrays.swift.gyb +++ b/stdlib/public/core/Arrays.swift.gyb @@ -578,10 +578,11 @@ public struct ${Self} /// value, so it succeeds. /// /// let numbers = [10, 20, 30, 40, 50] - /// let i = numbers.index(numbers.startIndex, - /// offsetBy: 4, - /// limitedBy: numbers.endIndex) - /// print(numbers[i]) + /// if let i = numbers.index(numbers.startIndex, + /// offsetBy: 4, + /// limitedBy: numbers.endIndex) { + /// print(numbers[i]) + /// } /// // Prints "50" /// /// The next example attempts to retrieve an index ten positions from @@ -1343,7 +1344,7 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol { /// Adds the elements of a sequence to the end of the array. /// - /// Use this method to append the elements of a sequence to the end of an + /// Use this method to append the elements of a sequence to the end of this /// array. This example appends the elements of a `Range` instance /// to an array of integers. /// @@ -1357,53 +1358,40 @@ extension ${Self} : RangeReplaceableCollection, _ArrayProtocol { /// - Complexity: O(*n*), where *n* is the length of the resulting array. public mutating func append(contentsOf newElements: S) where S.Iterator.Element == Element { - let oldCount = self.count - let capacity = self.capacity - let newCount = oldCount + newElements.underestimatedCount - - if newCount > capacity { - self.reserveCapacity( - Swift.max(newCount, _growArrayCapacity(capacity))) - } - _buffer._arrayAppendSequence(newElements) - } - - // An overload of `append(contentsOf:)` that uses the += that is optimized for - // collections. - // FIXME(ABI)#13 (Performance): remove this entrypoint. The overload for `Sequence` should be - // made optimal for this case, too. - /// Adds the elements of a collection to the end of the array. - /// - /// Use this method to append the elements of a collection to the end of this - /// array. This example appends the elements of a `Range` instance - /// to an array of integers. - /// - /// var numbers = [1, 2, 3, 4, 5] - /// numbers.append(contentsOf: 10...15) - /// print(numbers) - /// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]" - /// - /// - Parameter newElements: The elements to append to the array. - /// - /// - Complexity: O(*n*), where *n* is the length of the resulting array. - public mutating func append(contentsOf newElements: C) - where C.Iterator.Element == Element { - let newElementsCount = numericCast(newElements.count) as Int + let newElementsCount = newElements.underestimatedCount let oldCount = self.count - let capacity = self.capacity + let oldCapacity = self.capacity let newCount = oldCount + newElementsCount // Ensure uniqueness, mutability, and sufficient storage. Note that // for consistency, we need unique self even if newElements is empty. self.reserveCapacity( - newCount > capacity ? - Swift.max(newCount, _growArrayCapacity(capacity)) + newCount > oldCapacity ? + Swift.max(newCount, _growArrayCapacity(oldCapacity)) : newCount) - (self._buffer.firstElementAddress + oldCount).initialize(from: newElements) - self._buffer.count = newCount + let startNewElements = _buffer.firstElementAddress + oldCount + let buf = UnsafeMutableBufferPointer( + start: startNewElements, + count: self.capacity - oldCount) + + let (remainder,writtenUpTo) = buf.initialize(from: newElements) + + // trap on underflow from the sequence's underestimate: + let writtenCount = buf.distance(from: buf.startIndex, to: writtenUpTo) + _precondition(newElementsCount <= writtenCount, + "newElements.underestimatedCount was an overestimate") + // can't check for overflow as sequences can underestimate + + _buffer.count += writtenCount + + if writtenUpTo == buf.endIndex { + // there may be elements that didn't fit in the existing buffer, + // append them in slow sequence-only mode + _buffer._arrayAppendSequence(IteratorSequence(remainder)) + } } %if Self == 'ArraySlice': @@ -1696,23 +1684,34 @@ extension ${Self} { return try body(&inoutBufferPointer) } - @discardableResult public func _copyContents( - initializing ptr: UnsafeMutablePointer - ) -> UnsafeMutablePointer { - if let s = self._baseAddressIfContiguous { - let count = self.count - ptr.initialize(from: s, count: count) + initializing buffer: UnsafeMutableBufferPointer + ) -> (Iterator,UnsafeMutableBufferPointer.Index) { + + guard !self.isEmpty else { return (makeIterator(),buffer.startIndex) } + + // It is not OK for there to be no pointer/not enough space, as this is + // a precondition and Array never lies about its count. + guard var p = buffer.baseAddress + else { _preconditionFailure("Attempt to copy contents into nil buffer pointer") } + _precondition(self.count <= buffer.count, + "Insufficient space allocated to copy array contents") + + if let s = _baseAddressIfContiguous { + p.initialize(from: s, count: self.count) + // Need a _fixLifetime bracketing the _baseAddressIfContiguous getter + // and all uses of the pointer it returns: _fixLifetime(self._owner) - return ptr + count } else { - var p = ptr for x in self { p.initialize(to: x) p += 1 } - return p } + + var it = IndexingIterator(_elements: self) + it._position = endIndex + return (it,buffer.index(buffer.startIndex, offsetBy: self.count)) } } %end @@ -1838,54 +1837,6 @@ extension ${Self} { } } } - -// FIXME(ABI)#16 : remove this entrypoint. The functionality should be provided by -// a `+=` operator on `RangeReplaceableCollection`. -/// Appends the elements of a sequence to ${a_Self}. -/// -/// Use this operator to append the elements of a sequence to the end of -/// ${a_Self} with same `Element` type. This example appends -/// the elements of a `Range` instance to an array of integers. -/// -/// var numbers = [1, 2, 3, 4, 5] -/// numbers += 10...15 -/// print(numbers) -/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]" -/// -/// - Parameters: -/// - lhs: The array to append to. -/// - rhs: A collection or finite sequence. -/// -/// - Complexity: O(*n*), where *n* is the length of the resulting array. -public func += < - S : Sequence ->(lhs: inout ${Self}, rhs: S) { - lhs.append(contentsOf: rhs) -} - -// FIXME(ABI)#17 : remove this entrypoint. The functionality should be provided by -// a `+=` operator on `RangeReplaceableCollection`. -/// Appends the elements of a collection to ${a_Self}. -/// -/// Use this operator to append the elements of a collection to the end of -/// ${a_Self} with same `Element` type. This example appends -/// the elements of a `Range` instance to an array of integers. -/// -/// var numbers = [1, 2, 3, 4, 5] -/// numbers += 10...15 -/// print(numbers) -/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]" -/// -/// - Parameters: -/// - lhs: The array to append to. -/// - rhs: A collection. -/// -/// - Complexity: O(*n*), where *n* is the length of the resulting array. -public func += < - C : Collection ->(lhs: inout ${Self}, rhs: C) { - lhs.append(contentsOf: rhs) -} % end //===--- generic helpers --------------------------------------------------===// diff --git a/stdlib/public/core/Builtin.swift b/stdlib/public/core/Builtin.swift index 90bc5c815f146..a7814592c8934 100644 --- a/stdlib/public/core/Builtin.swift +++ b/stdlib/public/core/Builtin.swift @@ -606,3 +606,131 @@ internal func _unsafeDowncastToAnyObject(fromAny any: Any) -> AnyObject { return any as! AnyObject #endif } + +// Game the SIL diagnostic pipeline by inlining this into the transparent +// definitions below after the stdlib's diagnostic passes run, so that the +// `staticReport`s don't fire while building the standard library, but do +// fire if they ever show up in code that uses the standard library. +@inline(__always) +public // internal with availability +func _trueAfterDiagnostics() -> Builtin.Int1 { + return true._value +} + +/// Returns the dynamic type of a value. +/// +/// - Parameter of: The value to take the dynamic type of. +/// - Returns: The dynamic type, which will be a value of metatype type. +/// +/// - Remark: If the parameter is statically of a protocol or protocol +/// composition type, the result will be an *existential metatype* +/// (`P.Type` for a protocol `P`), and will represent the type of the value +/// inside the existential container with the same protocol conformances +/// as the value. Otherwise, the result will be a *concrete metatype* +/// (`T.Type` for a non-protocol type `T`, or `P.Protocol` for a protocol +/// `P`). Normally, this will do what you mean, but one wart to be aware +/// of is when you use `type(of:)` in a generic context with a type +/// parameter bound to a protocol type: +/// +/// ``` +/// func foo(x: T) -> T.Type { +/// return type(of: x) +/// } +/// protocol P {} +/// func bar(x: P) { +/// foo(x: x) // Call foo with T == P +/// } +/// ``` +/// +/// since the call to `type(of:)` inside `foo` only sees `T` as a concrete +/// type, foo will end up returning `P.self` instead of the dynamic type +/// inside `x`. This can be worked around by writing `type(of: x as Any)` +/// to get the dynamic type inside `x` as an `Any.Type`. +@_transparent +@_semantics("typechecker.type(of:)") +public func type(of: Type) -> Metatype { + // This implementation is never used, since calls to `Swift.type(of:)` are + // resolved as a special case by the type checker. + Builtin.staticReport(_trueAfterDiagnostics(), true._value, + ("internal consistency error: 'type(of:)' operation failed to resolve" + as StaticString).utf8Start._rawValue) + Builtin.unreachable() +} + +/// Allows a nonescaping closure to temporarily be used as if it were +/// allowed to escape. +/// +/// This is useful when you need to pass a closure to an API that can't +/// statically guarantee the closure won't escape when used in a way that +/// won't allow it to escape in practice, such as in a lazy collection +/// view: +/// +/// ``` +/// func allValues(in array: [Int], matchPredicate: (Int) -> Bool) -> Bool { +/// // Error because `lazy.filter` may escape the closure if the `lazy` +/// // collection is persisted; however, in this case, we discard the +/// // lazy collection immediately before returning. +/// return array.lazy.filter { !matchPredicate($0) }.isEmpty +/// } +/// ``` +/// +/// or with `async`: +/// +/// ``` +/// func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void, +/// on queue: DispatchQueue) { +/// // Error: `async` normally escapes the closure, but in this case +/// // we explicitly barrier before the closure would escape +/// queue.async(f) +/// queue.async(g) +/// queue.sync(flags: .barrier) {} +/// } +/// ``` +/// +/// `withoutActuallyEscaping` provides a temporarily-escapable copy of the +/// closure that can be used in these situations: +/// +/// ``` +/// func allValues(in array: [Int], matchPredicate: (Int) -> Bool) -> Bool { +/// return withoutActuallyEscaping(matchPredicate) { escapablePredicate in +/// array.lazy.filter { !escapableMatchPredicate($0) }.isEmpty +/// } +/// } +/// +/// func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void, +/// on queue: DispatchQueue) { +/// withoutActuallyEscaping(f) { escapableF in +/// withoutActuallyEscaping(g) { escapableG in +/// queue.async(escapableF) +/// queue.async(escapableG) +/// queue.sync(flags: .barrier) {} +/// } +/// } +/// } +/// ``` +/// +/// - Parameter closure: A non-escaping closure value that will be made +/// escapable for the duration of the execution of the `do` block. +/// - Parameter do: A code block that will be immediately executed, receiving +/// an escapable copy of `closure` as an argument. +/// - Returns: the forwarded return value from the `do` block. +/// - Remark: It is undefined behavior for the escapable closure to be stored, +/// referenced, or executed after `withoutActuallyEscaping` returns. A +/// future version of Swift will introduce a dynamic check to trap if +/// the escapable closure is still referenced at the point +/// `withoutActuallyEscaping` returns. +@_transparent +@_semantics("typechecker.withoutActuallyEscaping(_:do:)") +public func withoutActuallyEscaping( + _ closure: ClosureType, + do: (_ escapingClosure: ClosureType) throws -> ResultType +) rethrows -> ResultType { + // This implementation is never used, since calls to + // `Swift.withoutActuallyEscaping(_:do:)` are resolved as a special case by + // the type checker. + Builtin.staticReport(_trueAfterDiagnostics(), true._value, + ("internal consistency error: 'withoutActuallyEscaping(_:do:)' operation failed to resolve" + as StaticString).utf8Start._rawValue) + Builtin.unreachable() +} + diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift index e4032605cb8dd..8cbb68ca584bc 100644 --- a/stdlib/public/core/ContiguousArrayBuffer.swift +++ b/stdlib/public/core/ContiguousArrayBuffer.swift @@ -477,9 +477,11 @@ internal func += ( let oldCount = lhs.count let newCount = oldCount + numericCast(rhs.count) + let buf: UnsafeMutableBufferPointer + if _fastPath(newCount <= lhs.capacity) { + buf = UnsafeMutableBufferPointer(start: lhs.firstElementAddress + oldCount, count: numericCast(rhs.count)) lhs.count = newCount - (lhs.firstElementAddress + oldCount).initialize(from: rhs) } else { var newLHS = _ContiguousArrayBuffer( @@ -490,8 +492,14 @@ internal func += ( from: lhs.firstElementAddress, count: oldCount) lhs.count = 0 swap(&lhs, &newLHS) - (lhs.firstElementAddress + oldCount).initialize(from: rhs) + buf = UnsafeMutableBufferPointer(start: lhs.firstElementAddress + oldCount, count: numericCast(rhs.count)) } + + var (remainders,writtenUpTo) = buf.initialize(from: rhs) + + // ensure that exactly rhs.count elements were written + _precondition(remainders.next() == nil, "rhs underreported its count") + _precondition(writtenUpTo == buf.endIndex, "rhs overreported its count") } extension _ContiguousArrayBuffer : RandomAccessCollection { diff --git a/stdlib/public/core/ExistentialCollection.swift.gyb b/stdlib/public/core/ExistentialCollection.swift.gyb index 0d7059769dd7d..0efc09ec2e894 100644 --- a/stdlib/public/core/ExistentialCollection.swift.gyb +++ b/stdlib/public/core/ExistentialCollection.swift.gyb @@ -192,8 +192,8 @@ internal class _AnyRandomAccessCollectionBox _abstract() } - internal func __copyContents(initializing ptr: UnsafeMutablePointer) - -> UnsafeMutablePointer { + internal func __copyContents(initializing buf: UnsafeMutableBufferPointer) + -> (AnyIterator,UnsafeMutableBufferPointer.Index) { _abstract() } @@ -387,9 +387,10 @@ internal final class _${Kind}Box : _Any${Kind}Box ContiguousArray { return _base._copyToContiguousArray() } - internal override func __copyContents(initializing ptr: UnsafeMutablePointer) - -> UnsafeMutablePointer { - return _base._copyContents(initializing: ptr) + internal override func __copyContents(initializing buf: UnsafeMutableBufferPointer) + -> (AnyIterator,UnsafeMutableBufferPointer.Index) { + let (it,idx) = _base._copyContents(initializing: buf) + return (AnyIterator(it),idx) } internal override func _drop( while predicate: (Element) throws -> Bool @@ -588,6 +589,8 @@ public struct AnySequence : Sequence { self.init(_ClosureBasedSequence(makeUnderlyingIterator)) } + public typealias Iterator = AnyIterator + internal init(_box: _AnySequenceBox) { self._box = _box } @@ -602,7 +605,7 @@ extension Any${Kind} { % else: /// Returns an iterator over the elements of this collection. % end - public func makeIterator() -> AnyIterator { + public func makeIterator() -> Iterator { return _box._makeIterator() } @@ -683,9 +686,10 @@ extension Any${Kind} { return self._box.__copyToContiguousArray() } - public func _copyContents(initializing ptr: UnsafeMutablePointer) - -> UnsafeMutablePointer { - return _box.__copyContents(initializing: ptr) + public func _copyContents(initializing buf: UnsafeMutableBufferPointer) + -> (AnyIterator,UnsafeMutableBufferPointer.Index) { + let (it,idx) = _box.__copyContents(initializing: buf) + return (AnyIterator(it),idx) } } % end @@ -808,6 +812,8 @@ public struct ${Self} // public typealias Indices // = Default${Traversal.replace('Forward', '')}Indices<${Self}> + public typealias Iterator = AnyIterator + internal init(_box: _${Self}Box) { self._box = _box } diff --git a/stdlib/public/core/LazyCollection.swift.gyb b/stdlib/public/core/LazyCollection.swift.gyb index 04e6e6506e210..be4027176595c 100644 --- a/stdlib/public/core/LazyCollection.swift.gyb +++ b/stdlib/public/core/LazyCollection.swift.gyb @@ -75,11 +75,13 @@ public struct ${Self} : LazyCollectionProtocol { /// Forward implementations to the base collection, to pick up any /// optimizations it might implement. extension ${Self} : Sequence { + + public typealias Iterator = Base.Iterator /// Returns an iterator over the elements of this sequence. /// /// - Complexity: O(1). - public func makeIterator() -> Base.Iterator { + public func makeIterator() -> Iterator { return _base.makeIterator() } @@ -94,11 +96,10 @@ extension ${Self} : Sequence { return _base._copyToContiguousArray() } - @discardableResult public func _copyContents( - initializing ptr: UnsafeMutablePointer - ) -> UnsafeMutablePointer { - return _base._copyContents(initializing: ptr) + initializing buf: UnsafeMutableBufferPointer + ) -> (Iterator,UnsafeMutableBufferPointer.Index) { + return _base._copyContents(initializing: buf) } public func _customContainsEquatableElement( diff --git a/stdlib/public/core/ManagedBuffer.swift b/stdlib/public/core/ManagedBuffer.swift index 5b984e7cfbfb0..bcec029392a0b 100644 --- a/stdlib/public/core/ManagedBuffer.swift +++ b/stdlib/public/core/ManagedBuffer.swift @@ -77,7 +77,7 @@ open class ManagedBuffer { public final func withUnsafeMutablePointerToHeader( _ body: (UnsafeMutablePointer
) throws -> R ) rethrows -> R { - return try withUnsafeMutablePointers { (v, e) in return try body(v) } + return try withUnsafeMutablePointers { (v, _) in return try body(v) } } /// Call `body` with an `UnsafeMutablePointer` to the `Element` @@ -251,7 +251,7 @@ public struct ManagedBufferPointer : Equatable { public func withUnsafeMutablePointerToHeader( _ body: (UnsafeMutablePointer
) throws -> R ) rethrows -> R { - return try withUnsafeMutablePointers { (v, e) in return try body(v) } + return try withUnsafeMutablePointers { (v, _) in return try body(v) } } /// Call `body` with an `UnsafeMutablePointer` to the `Element` diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 48cd537a20d91..266061cca154d 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -318,7 +318,7 @@ internal func _adHocPrint_unlocked( printTypeName(mirror.subjectType) } if let (_, value) = mirror.children.first { - if (Mirror(reflecting: value).displayStyle == .tuple) { + if Mirror(reflecting: value).displayStyle == .tuple { _debugPrint_unlocked(value, &target) } else { target.write("(") diff --git a/stdlib/public/core/RangeReplaceableCollection.swift.gyb b/stdlib/public/core/RangeReplaceableCollection.swift.gyb index c2fe0575f8c75..9627646f5a4c9 100644 --- a/stdlib/public/core/RangeReplaceableCollection.swift.gyb +++ b/stdlib/public/core/RangeReplaceableCollection.swift.gyb @@ -294,26 +294,6 @@ public protocol RangeReplaceableCollection with newElements: C ) where C : Collection, C.Iterator.Element == Iterator.Element - /* - We could have these operators with default implementations, but the compiler - crashes: - - Dependent type should have been substituted by Sema - or SILGen - - func + (_: Self, _: S) -> Self - where S.Iterator.Element == Iterator.Element - - func + (_: S, _: Self) -> Self - where S.Iterator.Element == Iterator.Element - - func + (_: Self, _: S) -> Self - where S.Iterator.Element == Iterator.Element - - func + (_: Self, _: S) -> Self - where RC.Iterator.Element == Iterator.Element - */ - /// Prepares the collection to store the specified number of elements, when /// doing so is appropriate for the underlying type. /// @@ -370,16 +350,6 @@ public protocol RangeReplaceableCollection /// collection. mutating func append(_ newElement: Iterator.Element) - /* - The 'append(contentsOf:)' requirement should be an operator, but the compiler crashes: - - Dependent type should have been substituted by Sema - or SILGen - - func += (inout _: Self, _: S) - where S.Iterator.Element == Iterator.Element - */ - /// Adds the elements of a sequence or collection to the end of this /// collection. /// @@ -398,6 +368,8 @@ public protocol RangeReplaceableCollection /// /// - Complexity: O(*n*), where *n* is the length of the resulting /// collection. + // FIXME(ABI)#166 (Evolution): Consider replacing .append(contentsOf) with += + // suggestion in SE-91 mutating func append(contentsOf newElements: S) where S.Iterator.Element == Iterator.Element @@ -1171,6 +1143,29 @@ public func +< return lhs } +/// Appends the elements of a sequence to a range-replaceable collection. +/// +/// Use this operator to append the elements of a sequence to the end of +/// range-replaceable collection with same `Element` type. This example appends +/// the elements of a `Range` instance to an array of integers. +/// +/// var numbers = [1, 2, 3, 4, 5] +/// numbers += 10...15 +/// print(numbers) +/// // Prints "[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15]" +/// +/// - Parameters: +/// - lhs: The array to append to. +/// - rhs: A collection or finite sequence. +/// +/// - Complexity: O(*n*), where *n* is the length of the resulting array. +public func += < + R : RangeReplaceableCollection, S : Sequence +>(lhs: inout R, rhs: S) + where R.Iterator.Element == S.Iterator.Element { + lhs.append(contentsOf: rhs) +} + @available(*, unavailable, renamed: "RangeReplaceableCollection") public typealias RangeReplaceableCollectionType = RangeReplaceableCollection diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift index 2cf07ebb950b4..c309d4ecbb998 100644 --- a/stdlib/public/core/Sequence.swift +++ b/stdlib/public/core/Sequence.swift @@ -619,11 +619,11 @@ public protocol Sequence { /// in the same order. func _copyToContiguousArray() -> ContiguousArray - /// Copy a Sequence into an array, returning one past the last - /// element initialized. - @discardableResult - func _copyContents(initializing ptr: UnsafeMutablePointer) - -> UnsafeMutablePointer + /// Copy `self` into an unsafe buffer, returning a partially-consumed + /// iterator with any elements that didn't fit remaining. + func _copyContents( + initializing ptr: UnsafeMutableBufferPointer + ) -> (Iterator,UnsafeMutableBufferPointer.Index) } /// A default makeIterator() function for `IteratorProtocol` instances that @@ -1349,8 +1349,7 @@ extension Sequence { /// Returns a subsequence containing all but the last element of the /// sequence. /// - /// The sequence must be finite. If the sequence has no elements, the result - /// is an empty subsequence. + /// The sequence must be finite. /// /// let numbers = [1, 2, 3, 4, 5] /// print(numbers.dropLast()) @@ -1369,19 +1368,31 @@ extension Sequence { } extension Sequence { - @discardableResult + /// Copies `self` into the supplied buffer. + /// + /// - Precondition: The memory in `self` is uninitialized. The buffer must + /// contain sufficient uninitialized memory to accommodate `source.underestimatedCount`. + /// + /// - Postcondition: The `Pointee`s at `buffer[startIndex.. - ) -> UnsafeMutablePointer { - var p = UnsafeMutablePointer(ptr) - for x in IteratorSequence(self.makeIterator()) { - p.initialize(to: x) - p += 1 + initializing buffer: UnsafeMutableBufferPointer + ) -> (Iterator,UnsafeMutableBufferPointer.Index) { + var it = self.makeIterator() + guard var ptr = buffer.baseAddress else { return (it,buffer.startIndex) } + for idx in buffer.startIndex.. and , // pass an IteratorProtocol through IteratorSequence to give it "Sequence-ness" /// A sequence built around an iterator of type `Base`. diff --git a/stdlib/public/core/SequenceWrapper.swift b/stdlib/public/core/SequenceWrapper.swift index fa0230252fcd8..0a3962b216d04 100644 --- a/stdlib/public/core/SequenceWrapper.swift +++ b/stdlib/public/core/SequenceWrapper.swift @@ -119,8 +119,8 @@ extension Sequence /// element initialized. @discardableResult public func _copyContents( - initializing ptr: UnsafeMutablePointer - ) -> UnsafeMutablePointer { - return _base._copyContents(initializing: ptr) + initializing buf: UnsafeMutableBufferPointer + ) -> (Base.Iterator,UnsafeMutableBufferPointer.Index) { + return _base._copyContents(initializing: buf) } } diff --git a/stdlib/public/core/StringCore.swift b/stdlib/public/core/StringCore.swift index 93a27cfc897cd..667d82b99de5e 100644 --- a/stdlib/public/core/StringCore.swift +++ b/stdlib/public/core/StringCore.swift @@ -114,12 +114,12 @@ public struct _StringCore { src: srcStart, size: UInt(count << (srcElementWidth - 1))) } - else if (srcElementWidth < dstElementWidth) { + else if srcElementWidth < dstElementWidth { // Widening ASCII to UTF-16; we need to copy the bytes manually var dest = dstStart.assumingMemoryBound(to: UTF16.CodeUnit.self) var src = srcStart.assumingMemoryBound(to: UTF8.CodeUnit.self) let srcEnd = src + count - while (src != srcEnd) { + while src != srcEnd { dest.pointee = UTF16.CodeUnit(src.pointee) dest += 1 src += 1 @@ -130,7 +130,7 @@ public struct _StringCore { var dest = dstStart.assumingMemoryBound(to: UTF8.CodeUnit.self) var src = srcStart.assumingMemoryBound(to: UTF16.CodeUnit.self) let srcEnd = src + count - while (src != srcEnd) { + while src != srcEnd { dest.pointee = UTF8.CodeUnit(src.pointee) dest += 1 src += 1 @@ -365,7 +365,7 @@ public struct _StringCore { _sanityCheck(!hadError, "Swift.String with native storage should not have unpaired surrogates") } } - else if (hasCocoaBuffer) { + else if hasCocoaBuffer { #if _runtime(_ObjC) _StringCore( _cocoaStringToContiguous( diff --git a/stdlib/public/core/Unicode.swift b/stdlib/public/core/Unicode.swift index c6907a0ad6c69..fe800951daf0e 100644 --- a/stdlib/public/core/Unicode.swift +++ b/stdlib/public/core/Unicode.swift @@ -219,7 +219,7 @@ public struct UTF8 : UnicodeCodec { // Non-ASCII, proceed to buffering mode. _decodeBuffer = UInt32(codeUnit) _bitsInBuffer = 8 - } else if (_decodeBuffer & 0x80 == 0) { + } else if _decodeBuffer & 0x80 == 0 { // ASCII in buffer. We don't refill the buffer so we can return // to bufferless mode once we've exhausted it. let codeUnit = _decodeBuffer & 0xff diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 02393bd3fc399..66fccb75de109 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -290,6 +290,29 @@ extension Unsafe${Mutable}BufferPointer : CustomDebugStringConvertible { } %end + +extension UnsafeMutableBufferPointer { + /// Initializes memory in the buffer with the elements of `source`. + /// Returns an iterator to any elements of `source` that didn't fit in the + /// buffer, and an index to the point in the buffer one past the last element + /// written (so `startIndex` if no elements written, `endIndex` if the buffer + /// was completely filled). + /// + /// The region of memory described by the buffer must be sufficient to + /// accommodate `source.underestimatedCount`, and it must be uninitialized or + /// `ELement` must be a trivial type. After calling `initialize(from:)`, the + /// memory in buffer[startIndex..(from source: S) + -> (unwritten: S.Iterator, initializedUpTo: Index) + where S.Iterator.Element == Iterator.Element { + return source._copyContents(initializing: self) + } +} + + @available(*, unavailable, renamed: "UnsafeBufferPointerIterator") public struct UnsafeBufferPointerGenerator {} diff --git a/stdlib/public/core/UnsafePointer.swift.gyb b/stdlib/public/core/UnsafePointer.swift.gyb index ad31badcf5382..9c1ed2384f36b 100644 --- a/stdlib/public/core/UnsafePointer.swift.gyb +++ b/stdlib/public/core/UnsafePointer.swift.gyb @@ -628,9 +628,15 @@ public struct ${Self} /// /// - Parameter source: A collection of elements of the pointer's `Pointee` /// type. + // This is fundamentally unsafe since collections can underreport their count. + @available(*, deprecated, message: "it will be removed in Swift 4.0. Please use 'UnsafeMutableBufferPointer.initialize(from:)' instead") public func initialize(from source: C) where C.Iterator.Element == Pointee { - source._copyContents(initializing: self) + let buf = UnsafeMutableBufferPointer(start: self, count: numericCast(source.count)) + var (remainders,writtenUpTo) = source._copyContents(initializing: buf) + // ensure that exactly rhs.count elements were written + _precondition(remainders.next() == nil, "rhs underreported its count") + _precondition(writtenUpTo == buf.endIndex, "rhs overreported its count") } /// Replaces the memory referenced by this pointer with the values diff --git a/test/Compatibility/accessibility_compound.swift b/test/Compatibility/accessibility_compound.swift new file mode 100644 index 0000000000000..611bb5151715a --- /dev/null +++ b/test/Compatibility/accessibility_compound.swift @@ -0,0 +1,40 @@ +// RUN: %target-typecheck-verify-swift -swift-version 3 + +public struct Pair {} + +public struct PublicStruct { + public struct Inner {} + internal struct Internal {} +} + +private typealias PrivateAlias = PublicStruct // expected-note {{type declared here}} + +public let a: PrivateAlias.Inner? +public let b: PrivateAlias.Internal? // expected-error {{constant cannot be declared public because its type uses an internal type}} +public let c: Pair? // expected-error {{constant cannot be declared public because its type uses an internal type}} +public let c2: Pair? // expected-error {{constant cannot be declared public because its type uses an internal type}} +public let d: PrivateAlias? // expected-error {{constant cannot be declared public because its type uses a private type}} + + +// rdar://problem/21408035 +private class PrivateBox { // expected-note {{type declared here}} + typealias ValueType = T + typealias AlwaysFloat = Float +} + +let boxUnboxInt: PrivateBox.ValueType = 0 // FIXME: This used to error in Swift 3.0. +let boxFloat: PrivateBox.AlwaysFloat = 0 // expected-error {{constant must be declared private or fileprivate because its type uses a private type}} + +private protocol PrivateProto { + associatedtype Inner +} +extension PublicStruct: PrivateProto {} + +private class SpecificBox { // expected-note {{type declared here}} + typealias InnerType = T.Inner + typealias AlwaysFloat = Float +} + +let specificBoxUnboxInt: SpecificBox.InnerType = .init() // FIXME: This used to error in Swift 3.0. +let specificBoxFloat: SpecificBox.AlwaysFloat = 0 // expected-error {{constant must be declared private or fileprivate because its type uses a private type}} + diff --git a/test/Compatibility/availability_compound.swift b/test/Compatibility/availability_compound.swift new file mode 100644 index 0000000000000..3b47e32345262 --- /dev/null +++ b/test/Compatibility/availability_compound.swift @@ -0,0 +1,18 @@ +// RUN: %target-typecheck-verify-swift -swift-version 3 + +public struct Pair {} + +public struct PublicStruct { + public struct Inner {} + @available(*, unavailable) + internal struct Obsolete {} // expected-note * {{marked unavailable here}} +} + +@available(*, unavailable, renamed: "PublicStruct") +public typealias ObsoleteAlias = PublicStruct // expected-note {{marked unavailable here}} + +public let a: ObsoleteAlias.Inner? +public let b: ObsoleteAlias.Obsolete? // expected-error {{'Obsolete' is unavailable}} +public let c: Pair? // expected-error {{'Obsolete' is unavailable}} +public let c2: Pair? // expected-error {{'Obsolete' is unavailable}} +public let d: ObsoleteAlias? // expected-error {{'ObsoleteAlias' has been renamed to 'PublicStruct'}} diff --git a/test/Constraints/assignment.swift b/test/Constraints/assignment.swift index 604362996da2a..d73def27f2911 100644 --- a/test/Constraints/assignment.swift +++ b/test/Constraints/assignment.swift @@ -57,3 +57,4 @@ func f23798944() { } } +.sr_3506 = 0 // expected-error {{reference to member 'sr_3506' cannot be resolved without a contextual type}} \ No newline at end of file diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 434dd2fcec473..022818e959f4f 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -384,3 +384,14 @@ func g_2994(arg: Int) -> Double { C_2994(arg: { (r: S_2994) in f_2994(arg: g_2994(arg: r.dataOffset)) }) // expected-error {{cannot convert value of type 'Double' to expected argument type 'String'}} let _ = { $0[$1] }(1, 1) // expected-error {{cannot subscript a value of incorrect or ambiguous type}} +let _ = { $0 = ($0 = {}) } // expected-error {{assigning a variable to itself}} +let _ = { $0 = $0 = 42 } // expected-error {{assigning a variable to itself}} + +// https://bugs.swift.org/browse/SR-403 +// The () -> T => () -> () implicit conversion was kicking in anywhere +// inside a closure result, not just at the top-level. +let mismatchInClosureResultType : (String) -> ((Int) -> Void) = { + (String) -> ((Int) -> Void) in + return { } + // expected-error@-1 {{contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored}} +} diff --git a/test/Constraints/function.swift b/test/Constraints/function.swift index e90e9b8fdb6a8..6aeb021a8036b 100644 --- a/test/Constraints/function.swift +++ b/test/Constraints/function.swift @@ -83,3 +83,19 @@ sr590() // expected-error {{missing argument for parameter #1 in call}} // Make sure calling with structural tuples still works. sr590(()) sr590((1, 2)) + +// SR-2657: Poor diagnostics when function arguments should be '@escaping'. +private class SR2657BlockClass { + let f: T + init(f: T) { self.f = f } +} + +func foo(block: () -> ()) { + let a = SR2657BlockClass(f: block) // No error + let b = SR2657BlockClass<()->()>(f: block) + // expected-error@-1 {{invalid conversion from non-escaping function of type '() -> ()' to potentially escaping function type '() -> ()'}} + let c: SR2657BlockClass<()->()> = SR2657BlockClass(f: block) + // expected-error@-1 {{cannot convert value of type 'SR2657BlockClass<() -> ()>' to specified type 'SR2657BlockClass<() -> ()>'}} + let d: SR2657BlockClass<()->()> = SR2657BlockClass<()->()>(f: block) + // expected-error@-1 {{invalid conversion from non-escaping function of type '() -> ()' to potentially escaping function type '() -> ()'}} +} diff --git a/test/Constraints/if_expr.swift b/test/Constraints/if_expr.swift index 6cb604fc450eb..bce22450080a2 100644 --- a/test/Constraints/if_expr.swift +++ b/test/Constraints/if_expr.swift @@ -56,3 +56,5 @@ var y = 22 ? 1 : 0 // expected-error{{'Int' is not convertible to 'Bool'}} _ = x ? x : x // expected-error {{'Int' is not convertible to 'Bool'}} _ = true ? x : 1.2 // expected-error {{result values in '? :' expression have mismatching types 'Int' and 'Double'}} +_ = (x: true) ? true : false // expected-error {{'(x: Bool)' is not convertible to 'Bool'}} +_ = (x: 1) ? true : false // expected-error {{'(x: Int)' is not convertible to 'Bool'}} diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 278c80542cff4..b5e24b02de4e0 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -140,243 +140,6 @@ func goo() { G.In.foo() } -//// -// Members of archetypes -//// - -func id(_ t: T) -> T { return t } - -protocol P { - init() - func bar(_ x: Int) - mutating func mut(_ x: Int) - static func tum() -} - -extension P { - func returnSelfInstance() -> Self { - return self - } - - func returnSelfOptionalInstance(_ b: Bool) -> Self? { - return b ? self : nil - } - - func returnSelfIUOInstance(_ b: Bool) -> Self! { - return b ? self : nil - } - - static func returnSelfStatic() -> Self { - return Self() - } - - static func returnSelfOptionalStatic(_ b: Bool) -> Self? { - return b ? Self() : nil - } - - static func returnSelfIUOStatic(_ b: Bool) -> Self! { - return b ? Self() : nil - } -} - -protocol ClassP : class { - func bas(_ x: Int) - func quux(_ x: Int) -} - -class ClassC : ClassP { - func bas(_ x: Int) {} -} - -extension ClassP { - func quux(_ x: Int) {} - func bing(_ x: Int) {} -} - -func generic(_ t: T) { - var t = t - // Instance member of archetype - let _: (Int) -> () = id(t.bar) - let _: () = id(t.bar(0)) - - // Static member of archetype metatype - let _: () -> () = id(T.tum) - - // Instance member of archetype metatype - let _: (T) -> (Int) -> () = id(T.bar) - let _: (Int) -> () = id(T.bar(t)) - - _ = t.mut // expected-error{{partial application of 'mutating' method is not allowed}} - _ = t.tum // expected-error{{static member 'tum' cannot be used on instance of type 'T'}} - - // Instance member of extension returning Self) - let _: (T) -> () -> T = id(T.returnSelfInstance) - let _: () -> T = id(T.returnSelfInstance(t)) - let _: T = id(T.returnSelfInstance(t)()) - - let _: () -> T = id(t.returnSelfInstance) - let _: T = id(t.returnSelfInstance()) - - let _: (T) -> (Bool) -> T? = id(T.returnSelfOptionalInstance) - let _: (Bool) -> T? = id(T.returnSelfOptionalInstance(t)) - let _: T? = id(T.returnSelfOptionalInstance(t)(false)) - - let _: (Bool) -> T? = id(t.returnSelfOptionalInstance) - let _: T? = id(t.returnSelfOptionalInstance(true)) - - let _: (T) -> (Bool) -> T! = id(T.returnSelfIUOInstance) - let _: (Bool) -> T! = id(T.returnSelfIUOInstance(t)) - let _: T! = id(T.returnSelfIUOInstance(t)(true)) - - let _: (Bool) -> T! = id(t.returnSelfIUOInstance) - let _: T! = id(t.returnSelfIUOInstance(true)) - - // Static member of extension returning Self) - let _: () -> T = id(T.returnSelfStatic) - let _: T = id(T.returnSelfStatic()) - - let _: (Bool) -> T? = id(T.returnSelfOptionalStatic) - let _: T? = id(T.returnSelfOptionalStatic(false)) - - let _: (Bool) -> T! = id(T.returnSelfIUOStatic) - let _: T! = id(T.returnSelfIUOStatic(true)) -} - -func genericClassP(_ t: T) { - // Instance member of archetype) - let _: (Int) -> () = id(t.bas) - let _: () = id(t.bas(0)) - - // Instance member of archetype metatype) - let _: (T) -> (Int) -> () = id(T.bas) - let _: (Int) -> () = id(T.bas(t)) - let _: () = id(T.bas(t)(1)) -} - -func genericClassC(_ c: C) { - // Make sure that we can find members of protocol extensions - // on a class-bound archetype - let _ = c.bas(123) - let _ = c.quux(123) - let _ = c.bing(123) -} - -//// -// Members of existentials -//// - -func existential(_ p: P) { - var p = p - // Fully applied mutating method - p.mut(1) - _ = p.mut // expected-error{{partial application of 'mutating' method is not allowed}} - - // Instance member of existential) - let _: (Int) -> () = id(p.bar) - let _: () = id(p.bar(0)) - - // Static member of existential metatype) - let _: () -> () = id(type(of: p).tum) - - // Instance member of extension returning Self - let _: () -> P = id(p.returnSelfInstance) - let _: P = id(p.returnSelfInstance()) - let _: P? = id(p.returnSelfOptionalInstance(true)) - let _: P! = id(p.returnSelfIUOInstance(true)) -} - -func staticExistential(_ p: P.Type, pp: P.Protocol) { - let ppp: P = p.init() - _ = pp.init() // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} - _ = P() // expected-error{{protocol type 'P' cannot be instantiated}} - - // Instance member of metatype - let _: (P) -> (Int) -> () = P.bar - let _: (Int) -> () = P.bar(ppp) - P.bar(ppp)(5) - - // Instance member of metatype value - let _: (P) -> (Int) -> () = pp.bar - let _: (Int) -> () = pp.bar(ppp) - pp.bar(ppp)(5) - - // Static member of existential metatype value - let _: () -> () = p.tum - - // Instance member of existential metatype -- not allowed - _ = p.bar // expected-error{{instance member 'bar' cannot be used on type 'P'}} - _ = p.mut // expected-error{{instance member 'mut' cannot be used on type 'P'}} - - // Static member of metatype -- not allowed - _ = pp.tum // expected-error{{static member 'tum' cannot be used on protocol metatype 'P.Protocol'}} - _ = P.tum // expected-error{{static member 'tum' cannot be used on protocol metatype 'P.Protocol'}} - - // Static member of extension returning Self) - let _: () -> P = id(p.returnSelfStatic) - let _: P = id(p.returnSelfStatic()) - - let _: (Bool) -> P? = id(p.returnSelfOptionalStatic) - let _: P? = id(p.returnSelfOptionalStatic(false)) - - let _: (Bool) -> P! = id(p.returnSelfIUOStatic) - let _: P! = id(p.returnSelfIUOStatic(true)) -} - -protocol StaticP { - static func foo(a: Int) -} -extension StaticP { - func bar() { - _ = StaticP.foo(a:) // expected-error{{static member 'foo(a:)' cannot be used on protocol metatype 'StaticP.Protocol'}} {{9-16=Self}} - - func nested() { - _ = StaticP.foo(a:) // expected-error{{static member 'foo(a:)' cannot be used on protocol metatype 'StaticP.Protocol'}} {{11-18=Self}} - } - } -} - -func existentialClassP(_ p: ClassP) { - // Instance member of existential) - let _: (Int) -> () = id(p.bas) - let _: () = id(p.bas(0)) - - // Instance member of existential metatype) - let _: (ClassP) -> (Int) -> () = id(ClassP.bas) - let _: (Int) -> () = id(ClassP.bas(p)) - let _: () = id(ClassP.bas(p)(1)) -} - -// Partial application of curried protocol methods -protocol Scalar {} -protocol Vector { - func scale(_ c: Scalar) -> Self -} -protocol Functional { - func apply(_ v: Vector) -> Scalar -} -protocol Coalgebra { - func coproduct(_ f: Functional) -> (_ v1: Vector, _ v2: Vector) -> Scalar -} - -// Make sure existential is closed early when we partially apply -func wrap(_ t: T) -> T { - return t -} - -func exercise(_ c: Coalgebra, f: Functional, v: Vector) { - let _: (Vector, Vector) -> Scalar = wrap(c.coproduct(f)) - let _: (Scalar) -> Vector = v.scale -} - -// Make sure existential isn't closed too late -protocol Copyable { - func copy() -> Self -} - -func copyTwice(_ c: Copyable) -> Copyable { - return c.copy().copy() -} - //// // Misc ambiguities //// diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index 882f0abea0232..4d81dad003b4c 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -1,5 +1,25 @@ // RUN: %target-typecheck-verify-swift +// Test constraint simplification of chains of binary operators. +// +do { + let a: String? = "a" + let b: String? = "b" + let c: String? = "c" + let d: String? = a! + b! + c! + + let x: Double = 1 + _ = x + x + x + + let sr3483: Double? = 1 + _ = sr3483! + sr3483! + sr3483! + + let sr2636: [String: Double] = ["pizza": 10.99, "ice cream": 4.99, "salad": 7.99] + _ = sr2636["pizza"]! + _ = sr2636["pizza"]! + sr2636["salad"]! + _ = sr2636["pizza"]! + sr2636["salad"]! + sr2636["ice cream"]! +} + // Use operators defined within a type. struct S0 { static func +(lhs: S0, rhs: S0) -> S0 { return lhs } diff --git a/test/Constraints/protocols.swift b/test/Constraints/protocols.swift index 86cf886c682fa..1c5dae9ffcb4c 100644 --- a/test/Constraints/protocols.swift +++ b/test/Constraints/protocols.swift @@ -93,6 +93,183 @@ let _: () -> Int = { return "" } +//===----------------------------------------------------------------------===// +// Members of archetypes +//===----------------------------------------------------------------------===// + +func id(_ t: T) -> T { return t } + +protocol P { + init() + func bar(_ x: Int) + mutating func mut(_ x: Int) + static func tum() +} + +protocol ClassP : class { + func bas(_ x: Int) + func quux(_ x: Int) +} + +class ClassC : ClassP { + func bas(_ x: Int) {} +} + +extension ClassP { + func quux(_ x: Int) {} + func bing(_ x: Int) {} +} + +func generic(_ t: T) { + var t = t + // Instance member of archetype + let _: (Int) -> () = id(t.bar) + let _: () = id(t.bar(0)) + + // Static member of archetype metatype + let _: () -> () = id(T.tum) + + // Instance member of archetype metatype + let _: (T) -> (Int) -> () = id(T.bar) + let _: (Int) -> () = id(T.bar(t)) + + _ = t.mut // expected-error{{partial application of 'mutating' method is not allowed}} + _ = t.tum // expected-error{{static member 'tum' cannot be used on instance of type 'T'}} +} + +func genericClassP(_ t: T) { + // Instance member of archetype) + let _: (Int) -> () = id(t.bas) + let _: () = id(t.bas(0)) + + // Instance member of archetype metatype) + let _: (T) -> (Int) -> () = id(T.bas) + let _: (Int) -> () = id(T.bas(t)) + let _: () = id(T.bas(t)(1)) +} + +func genericClassC(_ c: C) { + // Make sure that we can find members of protocol extensions + // on a class-bound archetype + let _ = c.bas(123) + let _ = c.quux(123) + let _ = c.bing(123) +} + +//===----------------------------------------------------------------------===// +// Members of existentials +//===----------------------------------------------------------------------===// + +func existential(_ p: P) { + var p = p + // Fully applied mutating method + p.mut(1) + _ = p.mut // expected-error{{partial application of 'mutating' method is not allowed}} + + // Instance member of existential) + let _: (Int) -> () = id(p.bar) + let _: () = id(p.bar(0)) + + // Static member of existential metatype) + let _: () -> () = id(type(of: p).tum) +} + +func staticExistential(_ p: P.Type, pp: P.Protocol) { + let _ = p() // expected-error{{initializing from a metatype value must reference 'init' explicitly}} + let _ = p().bar // expected-error{{initializing from a metatype value must reference 'init' explicitly}} + let _ = p().bar(1) // expected-error{{initializing from a metatype value must reference 'init' explicitly}} + + let ppp: P = p.init() + + _ = pp() // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} // expected-error{{initializing from a metatype value must reference 'init' explicitly}} + _ = pp().bar // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} // expected-error{{initializing from a metatype value must reference 'init' explicitly}} + _ = pp().bar(2) // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} // expected-error{{initializing from a metatype value must reference 'init' explicitly}} + + _ = pp.init() // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} + _ = pp.init().bar // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} + _ = pp.init().bar(3) // expected-error{{value of type 'P.Protocol' is a protocol; it cannot be instantiated}} + + _ = P() // expected-error{{protocol type 'P' cannot be instantiated}} + _ = P().bar // expected-error{{protocol type 'P' cannot be instantiated}} + _ = P().bar(4) // expected-error{{protocol type 'P' cannot be instantiated}} + + // Instance member of metatype + let _: (P) -> (Int) -> () = P.bar + let _: (Int) -> () = P.bar(ppp) + P.bar(ppp)(5) + + // Instance member of metatype value + let _: (P) -> (Int) -> () = pp.bar + let _: (Int) -> () = pp.bar(ppp) + pp.bar(ppp)(5) + + // Static member of existential metatype value + let _: () -> () = p.tum + + // Instance member of existential metatype -- not allowed + _ = p.bar // expected-error{{instance member 'bar' cannot be used on type 'P'}} + _ = p.mut // expected-error{{instance member 'mut' cannot be used on type 'P'}} + + // Static member of metatype -- not allowed + _ = pp.tum // expected-error{{static member 'tum' cannot be used on protocol metatype 'P.Protocol'}} + _ = P.tum // expected-error{{static member 'tum' cannot be used on protocol metatype 'P.Protocol'}} +} + +protocol StaticP { + static func foo(a: Int) +} +extension StaticP { + func bar() { + _ = StaticP.foo(a:) // expected-error{{static member 'foo(a:)' cannot be used on protocol metatype 'StaticP.Protocol'}} {{9-16=Self}} + + func nested() { + _ = StaticP.foo(a:) // expected-error{{static member 'foo(a:)' cannot be used on protocol metatype 'StaticP.Protocol'}} {{11-18=Self}} + } + } +} + +func existentialClassP(_ p: ClassP) { + // Instance member of existential) + let _: (Int) -> () = id(p.bas) + let _: () = id(p.bas(0)) + + // Instance member of existential metatype) + let _: (ClassP) -> (Int) -> () = id(ClassP.bas) + let _: (Int) -> () = id(ClassP.bas(p)) + let _: () = id(ClassP.bas(p)(1)) +} + +// Partial application of curried protocol methods +protocol Scalar {} +protocol Vector { + func scale(_ c: Scalar) -> Self +} +protocol Functional { + func apply(_ v: Vector) -> Scalar +} +protocol Coalgebra { + func coproduct(_ f: Functional) -> (_ v1: Vector, _ v2: Vector) -> Scalar +} + +// Make sure existential is closed early when we partially apply +func wrap(_ t: T) -> T { + return t +} + +func exercise(_ c: Coalgebra, f: Functional, v: Vector) { + let _: (Vector, Vector) -> Scalar = wrap(c.coproduct(f)) + let _: (Scalar) -> Vector = v.scale +} + +// Make sure existential isn't closed too late +protocol Copyable { + func copy() -> Self +} + +func copyTwice(_ c: Copyable) -> Copyable { + return c.copy().copy() +} + //===----------------------------------------------------------------------===// // Dynamic self //===----------------------------------------------------------------------===// @@ -101,18 +278,87 @@ protocol Clonable { func doubleMaybeClone() -> Self?? func subdivideClone() -> (Self, Self) func metatypeOfClone() -> Self.Type - func badClonerFn() -> ((Self) -> Self) - func veryBadClonerFn() -> ((inout Self) -> ()) func goodClonerFn() -> (() -> Self) } -func testClonable(_ v : Clonable) { // expected-error {{protocol 'Clonable' can only be used as a generic constraint because it has Self or associated type requirements}} - let v2 = v.maybeClone() - let v3 = v.doubleMaybeClone() - let v4 = v.subdivideClone() - let v5 = v.metatypeOfClone() - let v6 = v.goodClonerFn() +extension Clonable { + func badClonerFn() -> ((Self) -> Self) { } + + func veryBadClonerFn() -> ((inout Self) -> ()) { } + + func extClone() -> Self { } + + func extMaybeClone(_ b: Bool) -> Self? { } + + func extProbablyClone(_ b: Bool) -> Self! { } + + static func returnSelfStatic() -> Self { } + + static func returnSelfOptionalStatic(_ b: Bool) -> Self? { } + + static func returnSelfIUOStatic(_ b: Bool) -> Self! { } +} + +func testClonableArchetype(_ t: T) { + // Instance member of extension returning Self) + let _: (T) -> () -> T = id(T.extClone) + let _: () -> T = id(T.extClone(t)) + let _: T = id(T.extClone(t)()) + + let _: () -> T = id(t.extClone) + let _: T = id(t.extClone()) + + let _: (T) -> (Bool) -> T? = id(T.extMaybeClone) + let _: (Bool) -> T? = id(T.extMaybeClone(t)) + let _: T? = id(T.extMaybeClone(t)(false)) + + let _: (Bool) -> T? = id(t.extMaybeClone) + let _: T? = id(t.extMaybeClone(true)) + + let _: (T) -> (Bool) -> T! = id(T.extProbablyClone) + let _: (Bool) -> T! = id(T.extProbablyClone(t)) + let _: T! = id(T.extProbablyClone(t)(true)) + + let _: (Bool) -> T! = id(t.extProbablyClone) + let _: T! = id(t.extProbablyClone(true)) + + // Static member of extension returning Self) + let _: () -> T = id(T.returnSelfStatic) + let _: T = id(T.returnSelfStatic()) + + let _: (Bool) -> T? = id(T.returnSelfOptionalStatic) + let _: T? = id(T.returnSelfOptionalStatic(false)) + + let _: (Bool) -> T! = id(T.returnSelfIUOStatic) + let _: T! = id(T.returnSelfIUOStatic(true)) +} + +func testClonableExistential(_ v: Clonable, _ vv: Clonable.Type) { + let _: Clonable? = v.maybeClone() + let _: Clonable?? = v.doubleMaybeClone() + // FIXME: Tuple-to-tuple conversions are not implemented + let _: (Clonable, Clonable) = v.subdivideClone() + // expected-error@-1{{cannot express tuple conversion '(Clonable, Clonable)' to '(Clonable, Clonable)'}} + let _: Clonable.Type = v.metatypeOfClone() + let _: () -> Clonable = v.goodClonerFn() + + // Instance member of extension returning Self + let _: () -> Clonable = id(v.extClone) + let _: Clonable = id(v.extClone()) + let _: Clonable? = id(v.extMaybeClone(true)) + let _: Clonable! = id(v.extProbablyClone(true)) + + // Static member of extension returning Self) + let _: () -> Clonable = id(vv.returnSelfStatic) + let _: Clonable = id(vv.returnSelfStatic()) + + let _: (Bool) -> Clonable? = id(vv.returnSelfOptionalStatic) + let _: Clonable? = id(vv.returnSelfOptionalStatic(false)) + + let _: (Bool) -> Clonable! = id(vv.returnSelfIUOStatic) + let _: Clonable! = id(vv.returnSelfIUOStatic(true)) + + let _ = v.badClonerFn() // expected-error {{member 'badClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}} + let _ = v.veryBadClonerFn() // expected-error {{member 'veryBadClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}} - let v7 = v.badClonerFn() // expected-error {{member 'badClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}} - let v8 = v.veryBadClonerFn() // expected-error {{member 'veryBadClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}} } diff --git a/test/Constraints/type_of.swift b/test/Constraints/type_of.swift new file mode 100644 index 0000000000000..f2b6cbd686369 --- /dev/null +++ b/test/Constraints/type_of.swift @@ -0,0 +1,38 @@ +// RUN: %target-swift-frontend -module-name main -typecheck -verify -swift-version 4 %s + +struct S: P {} +protocol P {} + +let _: S.Type = type(of: S()) +let _ = type(of: S()) +let _: P.Type = type(of: S() as P) +let _ = type(of: S() as P) +let _: P.Protocol = type(of: S() as P) // expected-error{{}} + +let _: S.Type = Swift.type(of: S()) +let _ = Swift.type(of: S()) +let _: P.Type = Swift.type(of: S() as P) +let _ = Swift.type(of: S() as P) +let _: P.Protocol = Swift.type(of: S() as P) // expected-error{{}} + +let _: (S) -> S.Type = type(of:) // expected-error{{}} + +func type(_: S) -> S {} +func type(kinda _: S) -> Any.Type {} + +let _ = type(S()) +let _: S = type(S()) +let _ = type(kinda: S()) +let _: Any.Type = type(kinda: S()) + +struct Q {} +struct R {} + +func type(of: Q) -> R {} + +let _: R = type(of: Q()) +let _: Q.Type = type(of: Q()) +let _: Q.Type = Swift.type(of: Q()) +let _: R = Swift.type(of: Q()) // expected-error{{}} +let _: Q.Type = main.type(of: Q()) // expected-error{{}} +let _: R = main.type(of: Q()) diff --git a/test/Constraints/without_actually_escaping.swift b/test/Constraints/without_actually_escaping.swift new file mode 100644 index 0000000000000..90b42b6c3a7df --- /dev/null +++ b/test/Constraints/without_actually_escaping.swift @@ -0,0 +1,66 @@ +// RUN: %target-swift-frontend -module-name main -typecheck -verify -swift-version 3 %s +// RUN: %target-swift-frontend -module-name main -typecheck -verify -swift-version 4 %s + +// Some convenient test points to escape closures to +var x: (Int) -> Int = { $0 } +var y: (inout Int, Int) -> Void = { $0 = $1 } +var z: (Int, Int, Int) throws -> Int = { $2 } + +func escapeX(_ xx: (Int) -> Int, _ value: Int) { // expected-note* {{non-escaping}} + x = xx // expected-error{{non-escaping parameter}} + withoutActuallyEscaping(xx) { escapableXX in + x = xx // expected-error{{non-escaping parameter}} + x = escapableXX + x = xx // expected-error{{non-escaping parameter}} + + _ = x(value) + _ = xx(value) + _ = escapableXX(value) + } + withoutActuallyEscaping(xx, do: { escapableXX in + x = escapableXX + }) + Swift.withoutActuallyEscaping(xx) { escapableXX in + x = escapableXX + } + Swift.withoutActuallyEscaping(xx, do: { escapableXX in + x = escapableXX + }) + x = xx // expected-error{{non-escaping parameter}} +} + +func escapeY(_ yy: (inout Int, Int) -> Void, _ value: inout Int) { // expected-note{{non-escaping}} + y = yy // expected-error{{non-escaping parameter}} + withoutActuallyEscaping(yy) { escapableYY in + y = escapableYY + + y(&value, value) + yy(&value, value) + escapableYY(&value, value) + } +} + +func escapeZ(_ zz: (Int, Int, Int) throws -> Int) { // expected-note{{non-escaping}} + z = zz // expected-error{{non-escaping parameter}} + withoutActuallyEscaping(zz) { escapableZZ in + z = escapableZZ + } +} + +func returnThroughWAE(_ xx: (Int) -> Int, _ value: Int) -> Int { + return withoutActuallyEscaping(xx) { escapableXX in + x = escapableXX + return x(value) + } +} + +func rethrowThroughWAE(_ zz: (Int, Int, Int) throws -> Int, _ value: Int) throws { + try withoutActuallyEscaping(zz) { escapableZZ in + _ = try zz(value, value, value) + _ = try escapableZZ(value, value, value) + } +} + +let _: ((Int) -> Int, (@escaping (Int) -> Int) -> ()) -> () + = withoutActuallyEscaping(_:do:) // expected-error{{}} + diff --git a/test/Generics/associated_types.swift b/test/Generics/associated_types.swift index 282856104b8a1..50fae7c3a0dcc 100644 --- a/test/Generics/associated_types.swift +++ b/test/Generics/associated_types.swift @@ -21,8 +21,7 @@ struct Z : Fooable { var a : AssocType // expected-warning {{variable 'a' was never used; consider replacing with '_' or removing it}} {{9-10=_}} } - // FIXME: We should be able to find this. - func blarg() -> AssocType {} // expected-error{{use of undeclared type 'AssocType'}} + func blarg() -> AssocType {} func wonka() -> Z.AssocType {} } diff --git a/test/Generics/function_defs.swift b/test/Generics/function_defs.swift index 65c716a6c3a13..5b892a64ecc24 100644 --- a/test/Generics/function_defs.swift +++ b/test/Generics/function_defs.swift @@ -46,7 +46,7 @@ protocol OtherEqualComparable { } func otherExistential(_ t1: T) { - var otherEqComp : OtherEqualComparable = t1 // expected-error{{value of type 'T' does not conform to specified type 'OtherEqualComparable'}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}} + var otherEqComp : OtherEqualComparable = t1 // expected-error{{value of type 'T' does not conform to specified type 'OtherEqualComparable'}} otherEqComp = t1 // expected-error{{value of type 'T' does not conform to 'OtherEqualComparable' in assignment}} _ = otherEqComp diff --git a/test/IDE/range_info_basics.swift b/test/IDE/range_info_basics.swift index fdb4668b096f4..e13a56cce0283 100644 --- a/test/IDE/range_info_basics.swift +++ b/test/IDE/range_info_basics.swift @@ -87,23 +87,29 @@ func foo6() -> Int { // RUN: %target-swift-ide-test -range -pos=57:1 -end-pos=69:8 -source-filename %s | %FileCheck %s -check-prefix=CHECK14 // RUN: %target-swift-ide-test -range -pos=63:1 -end-pos=66:44 -source-filename %s | %FileCheck %s -check-prefix=CHECK15 // RUN: %target-swift-ide-test -range -pos=63:1 -end-pos=68:15 -source-filename %s | %FileCheck %s -check-prefix=CHECK16 +// RUN: %target-swift-ide-test -range -pos=67:1 -end-pos=67:19 -source-filename %s | %FileCheck %s -check-prefix=CHECK17 // CHECK1: SingleDecl // CHECK1-NEXT: func foo1() -> Int { return 0 } // CHECK1-NEXT: swift_ide_test.(file) -// CHECK1-NEXT: foo1 +// CHECK1-NEXT: foo1false +// CHECK1-NEXT: 1 // CHECK1-NEXT: // CHECK2: SingleDecl // CHECK2-NEXT: class C { func foo() {} } // CHECK2-NEXT: swift_ide_test.(file) -// CHECK2-NEXT: C +// CHECK2-NEXT: Cfalse +// CHECK2-NEXT: foofalse +// CHECK2-NEXT: 1 // CHECK2-NEXT: // CHECK3: SingleDecl // CHECK3-NEXT: struct S { func foo() {} } // CHECK3-NEXT: swift_ide_test.(file) -// CHECK3-NEXT: S +// CHECK3-NEXT: Sfalse +// CHECK3-NEXT: foofalse +// CHECK3-NEXT: 1 // CHECK3-NEXT: // CHECK4: MultiStatement @@ -112,6 +118,7 @@ func foo6() -> Int { // CHECK4-NEXT: Void // CHECK4-NEXT: swift_ide_test.(file).func decl // CHECK4-NEXT: aaa@lvalue Int +// CHECK4-NEXT: 2 // CHECK4-NEXT: // CHECK5: MultiStatement @@ -121,6 +128,7 @@ func foo6() -> Int { // CHECK5-NEXT: Int // CHECK5-NEXT: swift_ide_test.(file).func decl // CHECK5-NEXT: aaa@lvalue Int +// CHECK5-NEXT: 3 // CHECK5-NEXT: // CHECK6: MultiStatement @@ -129,6 +137,7 @@ func foo6() -> Int { // CHECK6-NEXT: Int // CHECK6-NEXT: swift_ide_test.(file).func decl // CHECK6-NEXT: aaa@lvalue Int +// CHECK6-NEXT: 2 // CHECK6-NEXT: // CHECK7: MultiStatement @@ -138,10 +147,12 @@ func foo6() -> Int { // CHECK7-NEXT: print(b + c) // CHECK7-NEXT: () // CHECK7-NEXT: swift_ide_test.(file).func decl -// CHECK7-NEXT: b -// CHECK7-NEXT: c +// CHECK7-NEXT: bfalse +// CHECK7-NEXT: cfalse // CHECK7-NEXT: aInt // CHECK7-NEXT: b@lvalue Int +// CHECK7-NEXT: cInt +// CHECK7-NEXT: 4 // CHECK7-NEXT: // CHECK8: MultiStatement @@ -150,9 +161,11 @@ func foo6() -> Int { // CHECK8-NEXT: return c + b // CHECK8-NEXT: Int // CHECK8-NEXT: swift_ide_test.(file).func decl -// CHECK8-NEXT: c +// CHECK8-NEXT: cfalse // CHECK8-NEXT: s@lvalue S1 // CHECK8-NEXT: bInt +// CHECK8-NEXT: cInt +// CHECK8-NEXT: 3 // CHECK8-NEXT: // CHECK9: MultiStatement @@ -161,19 +174,23 @@ func foo6() -> Int { // CHECK9-NEXT: return c + b // CHECK9-NEXT: Int // CHECK9-NEXT: swift_ide_test.(file).func decl -// CHECK9-NEXT: b -// CHECK9-NEXT: c +// CHECK9-NEXT: bfalse +// CHECK9-NEXT: cfalse // CHECK9-NEXT: sS1 // CHECK9-NEXT: bInt +// CHECK9-NEXT: cInt +// CHECK9-NEXT: 3 // CHECK9-NEXT: // CHECK10: MultiStatement // CHECK10-NEXT: let a = c.c.getC().c.getC().getC().getC() // CHECK10-NEXT: let b = a.c.c.c.c.getC().getC() // CHECK10-NEXT: swift_ide_test.(file).func decl -// CHECK10-NEXT: a -// CHECK10-NEXT: b +// CHECK10-NEXT: atrue +// CHECK10-NEXT: btrue // CHECK10-NEXT: cC1 +// CHECK10-NEXT: aC1 +// CHECK10-NEXT: 2 // CHECK10-NEXT: // CHECK11: MultiStatement @@ -181,11 +198,12 @@ func foo6() -> Int { // CHECK11-NEXT: let b = a.c.c.c.c.getC().getC() // CHECK11-NEXT: let d = a.c.getC().getC().c.c // CHECK11-NEXT: swift_ide_test.(file).func decl -// CHECK11-NEXT: a -// CHECK11-NEXT: b -// CHECK11-NEXT: d +// CHECK11-NEXT: atrue +// CHECK11-NEXT: btrue +// CHECK11-NEXT: dtrue // CHECK11-NEXT: cC1 // CHECK11-NEXT: aC1 +// CHECK11-NEXT: 3 // CHECK11-NEXT: // CHECK12: MultiStatement @@ -195,11 +213,14 @@ func foo6() -> Int { // CHECK12-NEXT: return a.take(another: b).take(another: d) // CHECK12-NEXT: C1 // CHECK12-NEXT: swift_ide_test.(file).func decl -// CHECK12-NEXT: a -// CHECK12-NEXT: b -// CHECK12-NEXT: d +// CHECK12-NEXT: afalse +// CHECK12-NEXT: bfalse +// CHECK12-NEXT: dfalse // CHECK12-NEXT: cC1 // CHECK12-NEXT: aC1 +// CHECK12-NEXT: bC1 +// CHECK12-NEXT: dC1 +// CHECK12-NEXT: 4 // CHECK12-NEXT: // CHECK13: MultiStatement @@ -210,11 +231,13 @@ func foo6() -> Int { // CHECK13-NEXT: print(b + c) // CHECK13-NEXT: () // CHECK13-NEXT: swift_ide_test.(file).func decl.explicit closure discriminator=0 -// CHECK13-NEXT: a -// CHECK13-NEXT: b -// CHECK13-NEXT: c +// CHECK13-NEXT: afalse +// CHECK13-NEXT: bfalse +// CHECK13-NEXT: cfalse // CHECK13-NEXT: aInt // CHECK13-NEXT: b@lvalue Int +// CHECK13-NEXT: cInt +// CHECK13-NEXT: 5 // CHECK13-NEXT: // CHECK14: MultiStatement @@ -233,12 +256,19 @@ func foo6() -> Int { // CHECK14-NEXT: }() // CHECK14-NEXT: Int // CHECK14-NEXT: swift_ide_test.(file).func decl.explicit closure discriminator=0 -// CHECK14-NEXT: a -// CHECK14-NEXT: b -// CHECK14-NEXT: c +// CHECK14-NEXT: afalse +// CHECK14-NEXT: bfalse +// CHECK14-NEXT: cfalse +// CHECK14-NEXT: afalse +// CHECK14-NEXT: bfalse +// CHECK14-NEXT: cfalse // CHECK14-NEXT: aInt // CHECK14-NEXT: b@lvalue Int // CHECK14-NEXT: cInt +// CHECK14-NEXT: aInt +// CHECK14-NEXT: b@lvalue Int +// CHECK14-NEXT: cInt +// CHECK14-NEXT: 6 // CHECK14-NEXT: // CHECK15: MultiStatement @@ -248,10 +278,12 @@ func foo6() -> Int { // CHECK15-NEXT: b = b.bigEndian.bigEndian.byteSwapped // CHECK15-NEXT: () // CHECK15-NEXT: swift_ide_test.(file).func decl.explicit closure discriminator=0.explicit closure discriminator=0 -// CHECK15-NEXT: a -// CHECK15-NEXT: b -// CHECK15-NEXT: c +// CHECK15-NEXT: afalse +// CHECK15-NEXT: btrue +// CHECK15-NEXT: ctrue // CHECK15-NEXT: aInt +// CHECK15-NEXT: b@lvalue Int +// CHECK15-NEXT: 4 // CHECK15-NEXT: // CHECK16: MultiStatement @@ -263,10 +295,20 @@ func foo6() -> Int { // CHECK16-NEXT: return 1 // CHECK16-NEXT: Int // CHECK16-NEXT: swift_ide_test.(file).func decl.explicit closure discriminator=0.explicit closure discriminator=0 -// CHECK16-NEXT: a -// CHECK16-NEXT: b -// CHECK16-NEXT: c +// CHECK16-NEXT: afalse +// CHECK16-NEXT: bfalse +// CHECK16-NEXT: cfalse // CHECK16-NEXT: aInt // CHECK16-NEXT: b@lvalue Int // CHECK16-NEXT: cInt +// CHECK16-NEXT: 6 // CHECK16-NEXT: + +// CHECK17: SingleExpression +// CHECK17-NEXT: print(b + c) +// CHECK17-NEXT: () +// CHECK17-NEXT: swift_ide_test.(file).func decl.explicit closure discriminator=0.explicit closure discriminator=0 +// CHECK17-NEXT: b@lvalue Int +// CHECK17-NEXT: cInt +// CHECK17-NEXT: 1 +// CHECK17-NEXT: diff --git a/test/IRGen/enum_derived.swift b/test/IRGen/enum_derived.swift index 263184d32d693..65ed47a7641da 100644 --- a/test/IRGen/enum_derived.swift +++ b/test/IRGen/enum_derived.swift @@ -37,8 +37,8 @@ extension def_enum.TrafficLight : Error {} extension def_enum.Term : Error {} -// CHECK-NORMAL-LABEL: define hidden i64 @_TFO12enum_derived7Phantomg8rawValueVs5Int64(i1, %swift.type* nocapture readnone %T) local_unnamed_addr #0 -// CHECK-TESTABLE-LABEL: define{{( protected)?}} i64 @_TFO12enum_derived7Phantomg8rawValueVs5Int64(i1, %swift.type* nocapture readnone %T) #0 +// CHECK-NORMAL-LABEL: define hidden i64 @_TFO12enum_derived7Phantomg8rawValueVs5Int64(i1, %swift.type* nocapture readnone %T) local_unnamed_addr +// CHECK-TESTABLE-LABEL: define{{( protected)?}} i64 @_TFO12enum_derived7Phantomg8rawValueVs5Int64(i1, %swift.type* nocapture readnone %T) enum Phantom : Int64 { case Up diff --git a/test/IRGen/enum_function.sil b/test/IRGen/enum_function.sil index 17e72bd44d573..7f04657d4a64c 100644 --- a/test/IRGen/enum_function.sil +++ b/test/IRGen/enum_function.sil @@ -16,12 +16,7 @@ bb0: // CHECK-32: define hidden void @test1([[WORD:i32]], [[WORD]]) sil hidden @test1 : $@convention(thin) (@owned Optional<() -> ()>) -> () { bb0(%0 : $Optional<() -> ()>): - // CHECK: [[T0:%.*]] = icmp eq [[WORD]] %0, 0 - // CHECK: br i1 [[T0]], label - // CHECK: [[FNPTR:%.*]] = inttoptr [[WORD]] %0 to i8* - // CHECK: [[CTX:%.*]] = inttoptr [[WORD]] %1 to %swift.refcounted* - // CHECK: call void @swift_rt_swift_retain(%swift.refcounted* [[CTX]]) - // CHECK: br label + // CHECK: call void @_T0SqWy retain_value %0 : $Optional<() -> ()> // CHECK: icmp eq i64 %0, 0 diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil index 8106490f78e02..acda16ecc4d8c 100644 --- a/test/IRGen/enum_value_semantics.sil +++ b/test/IRGen/enum_value_semantics.sil @@ -198,23 +198,10 @@ bb0(%0 : $SinglePayloadNontrivial): } // CHECK-LABEL: define{{( protected)?}} void @single_payload_nontrivial_copy_destroy(i64) -// CHECK: switch i64 %0, label [[PRESENT:%.*]] [ -// CHECK-NEXT: i64 0, label [[NOT_PRESENT:%.*]] -// CHECK-NEXT: i64 2, label [[NOT_PRESENT]] -// CHECK-NEXT: i64 4, label [[NOT_PRESENT]] -// CHECK-NEXT: ] -// CHECK: [[T0:%.*]] = inttoptr i64 [[V:%.*]] to %swift.refcounted* -// CHECK-NEXT: call void @swift_rt_swift_retain(%swift.refcounted* [[T0]]) -// CHECK-NEXT: br label [[NOT_PRESENT]] -// CHECK: switch i64 %0, label [[PRESENT:%.*]] [ -// CHECK-NEXT: i64 0, label [[NOT_PRESENT:%.*]] -// CHECK-NEXT: i64 2, label [[NOT_PRESENT]] -// CHECK-NEXT: i64 4, label [[NOT_PRESENT]] -// CHECK-NEXT: ] -// CHECK: [[T0:%.*]] = inttoptr i64 [[V:%.*]] to %swift.refcounted* -// CHECK-NEXT: call void @swift_rt_swift_release(%swift.refcounted* [[T0]]) -// CHECK-NEXT: br label [[NOT_PRESENT]] -// CHECK: ret void +// CHECK: call void @_T020enum_value_semantics23SinglePayloadNontrivialOWy +// CHECK-NEXT: call void @single_payload_nontrivial_user +// CHECK-NEXT: call void @_T020enum_value_semantics23SinglePayloadNontrivialOWe +// CHECK-NEXT: ret void // // No payload enums @@ -482,19 +469,7 @@ bb0(%0 : $SinglePayloadNontrivial): // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds %O20enum_value_semantics22MultiPayloadNontrivial, %O20enum_value_semantics22MultiPayloadNontrivial* %0, i32 0, i32 1 // CHECK-NEXT: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8* // CHECK-NEXT: [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]], align 8 -// CHECK-NEXT: switch i8 [[TAG]], label %[[END:[0-9]+]] [ -// CHECK: i8 0, label %[[PAYLOAD1_DESTROY:[0-9]+]] -// CHECK: i8 2, label %[[PAYLOAD3_DESTROY:[0-9]+]] -// CHECK: ] -// CHECK: ;