diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f77111a401b..a79a0f21bdd05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,7 +81,7 @@ Swift Next mutableSelf.someProperty = newValue // Okay } } -``` + ``` * [SE-0253][]: @@ -145,6 +145,8 @@ Swift Next Swift 5.1 --------- +### 2019-09-20 (Xcode 11.0) + * [SR-8974][]: Duplicate tuple element labels are no longer allowed, because it leads diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f9bfdeee0c66..5ee19813e36de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1013,6 +1013,7 @@ if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) -DCMAKE_CXX_COMPILER=${SWIFT_LIBDISPATCH_CXX_COMPILER} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} + -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX= -DCMAKE_LINKER=${CMAKE_LINKER} -DCMAKE_RANLIB=${CMAKE_RANLIB} diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake index 4c1e0130580a4..ef56a89e5512d 100644 --- a/cmake/modules/SwiftSource.cmake +++ b/cmake/modules/SwiftSource.cmake @@ -323,9 +323,13 @@ function(_compile_swift_files set(module_base "${module_dir}/${SWIFTFILE_MODULE_NAME}") if(SWIFTFILE_SDK IN_LIST SWIFT_APPLE_PLATFORMS) set(specific_module_dir "${module_base}.swiftmodule") + set(specific_module_private_dir "${specific_module_dir}/Private") + set(source_info_file "${specific_module_private_dir}/${SWIFTFILE_ARCHITECTURE}.swiftsourceinfo") set(module_base "${module_base}.swiftmodule/${SWIFTFILE_ARCHITECTURE}") else() set(specific_module_dir) + set(specific_module_private_dir) + set(source_info_file "${module_base}.swiftsourceinfo") endif() set(module_file "${module_base}.swiftmodule") set(module_doc_file "${module_base}.swiftdoc") @@ -362,7 +366,8 @@ function(_compile_swift_files swift_install_in_component(DIRECTORY "${specific_module_dir}" DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/${library_subdir}" COMPONENT "${SWIFTFILE_INSTALL_IN_COMPONENT}" - OPTIONAL) + OPTIONAL + PATTERN "Private" EXCLUDE) else() swift_install_in_component(FILES ${module_outputs} DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/${library_subdir}" @@ -503,9 +508,11 @@ function(_compile_swift_files COMMAND "${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir} ${specific_module_dir} + ${specific_module_private_dir} COMMAND "${PYTHON_EXECUTABLE}" "${line_directive_tool}" "@${file_path}" -- "${swift_compiler_tool}" "-emit-module" "-o" "${module_file}" + "-emit-module-source-info-path" "${source_info_file}" ${swift_flags} ${swift_module_flags} "@${file_path}" ${command_touch_module_outputs} OUTPUT ${module_outputs} diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 84a6484f4baba..65da84443564b 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -290,6 +290,7 @@ Entities entity-spec ::= type 'fu' INDEX // implicit anonymous closure entity-spec ::= 'fA' INDEX // default argument N+1 generator entity-spec ::= 'fi' // non-local variable initializer + entity-spec ::= 'fP' // property wrapper backing initializer entity-spec ::= 'fD' // deallocating destructor; untyped entity-spec ::= 'fd' // non-deallocating destructor; untyped entity-spec ::= 'fE' // ivar destroyer; untyped @@ -480,7 +481,7 @@ Types type ::= 'Bf' NATURAL '_' // Builtin.Float type ::= 'Bi' NATURAL '_' // Builtin.Int type ::= 'BI' // Builtin.IntLiteral - type ::= 'BO' // Builtin.UnknownObject + type ::= 'BO' // Builtin.UnknownObject (no longer a distinct type, but still used for AnyObject) type ::= 'Bo' // Builtin.NativeObject type ::= 'Bp' // Builtin.RawPointer type ::= 'Bt' // Builtin.SILToken diff --git a/docs/ARCOptimization.rst b/docs/ARCOptimization.rst index e0e8ebf79efd7..1da72e2dc581d 100644 --- a/docs/ARCOptimization.rst +++ b/docs/ARCOptimization.rst @@ -335,7 +335,7 @@ is_unique performs depends on the argument type: - Objective-C object types require an additional check that the dynamic object type uses native Swift reference counting: - (Builtin.UnknownObject, unknown class reference, class existential) + (unknown class reference, class existential) - Bridged object types allow the dynamic object type check to be bypassed based on the pointer encoding: diff --git a/docs/CToSwiftNameTranslation.md b/docs/CToSwiftNameTranslation.md index ed3960f223d4c..d9a3778f66306 100644 --- a/docs/CToSwiftNameTranslation.md +++ b/docs/CToSwiftNameTranslation.md @@ -370,19 +370,6 @@ extension Counter { } ``` -The getter/setter syntax also allows for subscripts by using the base name `subscript`. - -```objc -__attribute__((swift_name("getter:LinkedListOfInts.subscript(self:_:)"))) -int LinkedListGetAtIndex(const LinkedListOfInts *head, int index); -``` - -```swift -extension LinkedListOfInts { - subscript(_ index: Int32) -> Int32 { get } -} -``` - Finally, functions can be imported as initializers as well by using the base name `init`. These are considered "factory" initializers and are never inherited or overridable. They must not have a `self` parameter. ```objc diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index a4d9a1213c52d..0e3bf5ce03338 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -647,7 +647,6 @@ class ASTContext final { const CanType TheAnyType; /// This is 'Any', the empty protocol composition const CanType TheNativeObjectType; /// Builtin.NativeObject const CanType TheBridgeObjectType; /// Builtin.BridgeObject - const CanType TheUnknownObjectType; /// Builtin.UnknownObject const CanType TheRawPointerType; /// Builtin.RawPointer const CanType TheUnsafeValueBufferType; /// Builtin.UnsafeValueBuffer const CanType TheSILTokenType; /// Builtin.SILToken diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 061465f333539..171689f5d7368 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -124,6 +124,8 @@ class ASTMangler : public Mangler { SymbolKind SKind); std::string mangleInitializerEntity(const VarDecl *var, SymbolKind SKind); + std::string mangleBackingInitializerEntity(const VarDecl *var, + SymbolKind SKind); std::string mangleNominalType(const NominalTypeDecl *decl); @@ -329,6 +331,7 @@ class ASTMangler : public Mangler { void appendDefaultArgumentEntity(const DeclContext *ctx, unsigned index); void appendInitializerEntity(const VarDecl *var); + void appendBackingInitializerEntity(const VarDecl *var); CanType getDeclTypeForMangling(const ValueDecl *decl, GenericSignature *&genericSig, diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index 9c925552c522a..91764dd88f44d 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -14,25 +14,29 @@ // for use with the TypeID template. // //===----------------------------------------------------------------------===// -SWIFT_TYPEID_NAMED(NominalTypeDecl *, NominalTypeDecl) -SWIFT_TYPEID_NAMED(VarDecl *, VarDecl) -SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl) -SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl) -SWIFT_TYPEID_NAMED(Decl *, Decl) -SWIFT_TYPEID_NAMED(ModuleDecl *, ModuleDecl) -SWIFT_TYPEID(Type) -SWIFT_TYPEID(TypePair) + +SWIFT_TYPEID(AncestryFlags) +SWIFT_TYPEID(CtorInitializerKind) SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo) SWIFT_TYPEID(PropertyWrapperTypeInfo) -SWIFT_TYPEID(CtorInitializerKind) +SWIFT_TYPEID(Requirement) SWIFT_TYPEID(ResilienceExpansion) -SWIFT_TYPEID_NAMED(Optional, PropertyWrapperMutability) +SWIFT_TYPEID(Type) +SWIFT_TYPEID(TypePair) SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr) -SWIFT_TYPEID_NAMED(OperatorDecl *, OperatorDecl) -SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl) -SWIFT_TYPEID(AncestryFlags) +SWIFT_TYPEID_NAMED(Decl *, Decl) +SWIFT_TYPEID_NAMED(GenericParamList *, GenericParamList) SWIFT_TYPEID_NAMED(GenericSignature *, GenericSignature) SWIFT_TYPEID_NAMED(GenericTypeParamType *, GenericTypeParamType) -SWIFT_TYPEID(Requirement) +SWIFT_TYPEID_NAMED(InfixOperatorDecl *, InfixOperatorDecl) SWIFT_TYPEID_NAMED(IterableDeclContext *, IterableDeclContext) -SWIFT_TYPEID_NAMED(GenericParamList *, GenericParamList) +SWIFT_TYPEID_NAMED(ModuleDecl *, ModuleDecl) +SWIFT_TYPEID_NAMED(NominalTypeDecl *, NominalTypeDecl) +SWIFT_TYPEID_NAMED(OperatorDecl *, OperatorDecl) +SWIFT_TYPEID_NAMED(Optional, + PropertyWrapperMutability) +SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl) +SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl) +SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl) +SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl) +SWIFT_TYPEID_NAMED(VarDecl *, VarDecl) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index cc8a95ac71f2e..c64b1290d3d1d 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -21,15 +21,19 @@ #include "swift/Basic/TypeID.h" namespace swift { +class AbstractFunctionDecl; +class BraceStmt; class CustomAttr; class Decl; class GenericParamList; class GenericSignature; class GenericTypeParamType; +class InfixOperatorDecl; class IterableDeclContext; class ModuleDecl; class NominalTypeDecl; class OperatorDecl; +class PrecedenceGroupDecl; struct PropertyWrapperBackingPropertyInfo; struct PropertyWrapperTypeInfo; enum class CtorInitializerKind; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 096e4b66a679b..610630010283e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -676,6 +676,7 @@ class alignas(1 << DeclAlignInBits) Decl { Decl(const Decl&) = delete; void operator=(const Decl&) = delete; + SourceLoc getLocFromSource() const; protected: @@ -1582,7 +1583,7 @@ enum class ImportKind : uint8_t { class ImportDecl final : public Decl, private llvm::TrailingObjects> { friend TrailingObjects; - + friend class Decl; public: typedef std::pair AccessPathElement; @@ -1654,7 +1655,7 @@ class ImportDecl final : public Decl, } SourceLoc getStartLoc() const { return ImportLoc; } - SourceLoc getLoc() const { return getFullAccessPath().front().second; } + SourceLoc getLocFromSource() const { return getFullAccessPath().front().second; } SourceRange getSourceRange() const { return SourceRange(ImportLoc, getFullAccessPath().back().second); } @@ -1677,7 +1678,11 @@ class ExtensionDecl final : public GenericContext, public Decl, TypeRepr *ExtendedTypeRepr; /// The nominal type being extended. - NominalTypeDecl *ExtendedNominal = nullptr; + /// + /// The bit indicates whether binding has been attempted. The pointer can be + /// null if either no binding was attempted or if binding could not find the + /// extended nominal. + llvm::PointerIntPair ExtendedNominal; MutableArrayRef Inherited; @@ -1716,6 +1721,7 @@ class ExtensionDecl final : public GenericContext, public Decl, std::pair takeConformanceLoaderSlow(); friend class ExtendedNominalRequest; + friend class Decl; public: using Decl::getASTContext; @@ -1728,7 +1734,7 @@ class ExtensionDecl final : public GenericContext, public Decl, ClangNode clangNode = ClangNode()); SourceLoc getStartLoc() const { return ExtensionLoc; } - SourceLoc getLoc() const { return ExtensionLoc; } + SourceLoc getLocFromSource() const { return ExtensionLoc; } SourceRange getSourceRange() const { return { ExtensionLoc, Braces.End }; } @@ -1736,6 +1742,12 @@ class ExtensionDecl final : public GenericContext, public Decl, SourceRange getBraces() const { return Braces; } void setBraces(SourceRange braces) { Braces = braces; } + bool hasBeenBound() const { return ExtendedNominal.getInt(); } + + void setExtendedNominal(NominalTypeDecl *n) { + ExtendedNominal.setPointerAndInt(n, true); + } + /// Retrieve the type being extended. /// /// Only use this entry point when the complete type, as spelled in the source, @@ -1744,8 +1756,21 @@ class ExtensionDecl final : public GenericContext, public Decl, Type getExtendedType() const; /// Retrieve the nominal type declaration that is being extended. + /// Will trip an assertion if the declaration has not already been computed. + /// In order to fail fast when type checking work is attempted + /// before extension binding has taken place. + NominalTypeDecl *getExtendedNominal() const; + /// Compute the nominal type declaration that is being extended. + NominalTypeDecl *computeExtendedNominal() const; + + /// \c hasBeenBound means nothing if this extension can never been bound + /// because it is not at the top level. + bool canNeverBeBound() const; + + bool hasValidParent() const; + /// Determine whether this extension has already been bound to a nominal /// type declaration. bool alreadyBoundToNominal() const { return NextExtension.getInt(); } @@ -2041,7 +2066,7 @@ class PatternBindingEntry { class PatternBindingDecl final : public Decl, private llvm::TrailingObjects { friend TrailingObjects; - + friend class Decl; SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present. SourceLoc VarLoc; ///< Location of the 'var' keyword. @@ -2050,7 +2075,7 @@ class PatternBindingDecl final : public Decl, PatternBindingDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc VarLoc, unsigned NumPatternEntries, DeclContext *Parent); - + SourceLoc getLocFromSource() const { return VarLoc; } public: static PatternBindingDecl *create(ASTContext &Ctx, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -2080,7 +2105,6 @@ class PatternBindingDecl final : public Decl, SourceLoc getStartLoc() const { return StaticLoc.isValid() ? StaticLoc : VarLoc; } - SourceLoc getLoc() const { return VarLoc; } SourceRange getSourceRange() const; unsigned getNumPatternEntries() const { @@ -2216,7 +2240,8 @@ class PatternBindingDecl final : public Decl, /// global variables. class TopLevelCodeDecl : public DeclContext, public Decl { BraceStmt *Body; - + SourceLoc getLocFromSource() const { return getStartLoc(); } + friend class Decl; public: TopLevelCodeDecl(DeclContext *Parent, BraceStmt *Body = nullptr) : DeclContext(DeclContextKind::TopLevelCodeDecl, Parent), @@ -2227,7 +2252,6 @@ class TopLevelCodeDecl : public DeclContext, public Decl { void setBody(BraceStmt *b) { Body = b; } SourceLoc getStartLoc() const; - SourceLoc getLoc() const { return getStartLoc(); } SourceRange getSourceRange() const; static bool classof(const Decl *D) { @@ -2266,6 +2290,8 @@ class IfConfigDecl : public Decl { /// The array is ASTContext allocated. ArrayRef Clauses; SourceLoc EndLoc; + SourceLoc getLocFromSource() const { return Clauses[0].Loc; } + friend class Decl; public: IfConfigDecl(DeclContext *Parent, ArrayRef Clauses, @@ -2291,7 +2317,6 @@ class IfConfigDecl : public Decl { } SourceLoc getEndLoc() const { return EndLoc; } - SourceLoc getLoc() const { return Clauses[0].Loc; } bool hadMissingEnd() const { return Bits.IfConfigDecl.HadMissingEnd; } @@ -2308,7 +2333,8 @@ class PoundDiagnosticDecl : public Decl { SourceLoc StartLoc; SourceLoc EndLoc; StringLiteralExpr *Message; - + SourceLoc getLocFromSource() const { return StartLoc; } + friend class Decl; public: PoundDiagnosticDecl(DeclContext *Parent, bool IsError, SourceLoc StartLoc, SourceLoc EndLoc, StringLiteralExpr *Message) @@ -2337,7 +2363,6 @@ class PoundDiagnosticDecl : public Decl { } SourceLoc getEndLoc() const { return EndLoc; }; - SourceLoc getLoc() const { return StartLoc; } SourceRange getSourceRange() const { return SourceRange(StartLoc, EndLoc); @@ -2400,7 +2425,8 @@ class ValueDecl : public Decl { friend class IsFinalRequest; friend class IsDynamicRequest; friend class IsImplicitlyUnwrappedOptionalRequest; - + friend class Decl; + SourceLoc getLocFromSource() const { return NameLoc; } protected: ValueDecl(DeclKind K, llvm::PointerUnion context, @@ -2473,7 +2499,6 @@ class ValueDecl : public Decl { bool canInferObjCFromRequirement(ValueDecl *requirement); SourceLoc getNameLoc() const { return NameLoc; } - SourceLoc getLoc() const { return NameLoc; } bool isUsableFromInline() const; @@ -5713,7 +5738,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Note that a true return value does not imply that the body was actually /// parsed. bool hasBody() const { - return getBodyKind() != BodyKind::None; + return getBodyKind() != BodyKind::None && + getBodyKind() != BodyKind::Skipped; } /// Returns true if the text of this function's body can be retrieved either @@ -5740,7 +5766,14 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Note that the body was skipped for this function. Function body /// cannot be attached after this call. void setBodySkipped(SourceRange bodyRange) { - assert(getBodyKind() == BodyKind::None); + // FIXME: Remove 'Parsed' from this once we can delay parsing function + // bodies. Right now -experimental-skip-non-inlinable-function-bodies + // requires being able to change the state from Parsed to Skipped, + // because we're still eagerly parsing function bodies. + assert(getBodyKind() == BodyKind::None || + getBodyKind() == BodyKind::Unparsed || + getBodyKind() == BodyKind::Parsed); + assert(bodyRange.isValid()); BodyRange = bodyRange; setBodyKind(BodyKind::Skipped); } @@ -5748,6 +5781,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// Note that parsing for the body was delayed. void setBodyDelayed(SourceRange bodyRange) { assert(getBodyKind() == BodyKind::None); + assert(bodyRange.isValid()); BodyRange = bodyRange; setBodyKind(BodyKind::Unparsed); } @@ -5793,6 +5827,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { return getBodyKind() == BodyKind::TypeChecked; } + bool isBodySkipped() const { + return getBodyKind() == BodyKind::Skipped; + } + bool isMemberwiseInitializer() const { return getBodyKind() == BodyKind::MemberwiseInitializer; } @@ -6296,6 +6334,7 @@ class EnumCaseDecl final : public Decl, private llvm::TrailingObjects { friend TrailingObjects; + friend class Decl; SourceLoc CaseLoc; EnumCaseDecl(SourceLoc CaseLoc, @@ -6308,6 +6347,7 @@ class EnumCaseDecl final std::uninitialized_copy(Elements.begin(), Elements.end(), getTrailingObjects()); } + SourceLoc getLocFromSource() const { return CaseLoc; } public: static EnumCaseDecl *create(SourceLoc CaseLoc, @@ -6319,11 +6359,6 @@ class EnumCaseDecl final return {getTrailingObjects(), Bits.EnumCaseDecl.NumElements}; } - - SourceLoc getLoc() const { - return CaseLoc; - } - SourceRange getSourceRange() const; static bool classof(const Decl *D) { @@ -6357,9 +6392,7 @@ class EnumElementDecl : public DeclContext, public ValueDecl { /// The raw value literal for the enum element, or null. LiteralExpr *RawValueExpr; - /// The type-checked raw value expression. - Expr *TypeCheckedRawValueExpr = nullptr; - + public: EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name, ParameterList *Params, @@ -6392,13 +6425,6 @@ class EnumElementDecl : public DeclContext, public ValueDecl { bool hasRawValueExpr() const { return RawValueExpr; } LiteralExpr *getRawValueExpr() const { return RawValueExpr; } void setRawValueExpr(LiteralExpr *e) { RawValueExpr = e; } - - Expr *getTypeCheckedRawValueExpr() const { - return TypeCheckedRawValueExpr; - } - void setTypeCheckedRawValueExpr(Expr *e) { - TypeCheckedRawValueExpr = e; - } /// Return the containing EnumDecl. EnumDecl *getParentEnum() const { @@ -6745,7 +6771,8 @@ class PrecedenceGroupDecl : public Decl { SourceLoc higherThanLoc, ArrayRef higherThan, SourceLoc lowerThanLoc, ArrayRef lowerThan, SourceLoc rbraceLoc); - + friend class Decl; + SourceLoc getLocFromSource() const { return NameLoc; } public: static PrecedenceGroupDecl *create(DeclContext *dc, SourceLoc precedenceGroupLoc, @@ -6765,7 +6792,6 @@ class PrecedenceGroupDecl : public Decl { SourceLoc rbraceLoc); - SourceLoc getLoc() const { return NameLoc; } SourceRange getSourceRange() const { return { PrecedenceGroupLoc, RBraceLoc }; } @@ -6884,7 +6910,8 @@ class OperatorDecl : public Decl { ArrayRef Identifiers; ArrayRef IdentifierLocs; ArrayRef DesignatedNominalTypes; - + SourceLoc getLocFromSource() const { return NameLoc; } + friend class Decl; public: OperatorDecl(DeclKind kind, DeclContext *DC, SourceLoc OperatorLoc, Identifier Name, SourceLoc NameLoc, @@ -6899,7 +6926,6 @@ class OperatorDecl : public Decl { : Decl(kind, DC), OperatorLoc(OperatorLoc), NameLoc(NameLoc), name(Name), DesignatedNominalTypes(DesignatedNominalTypes) {} - SourceLoc getLoc() const { return NameLoc; } SourceLoc getOperatorLoc() const { return OperatorLoc; } SourceLoc getNameLoc() const { return NameLoc; } @@ -6937,7 +6963,6 @@ class OperatorDecl : public Decl { /// \endcode class InfixOperatorDecl : public OperatorDecl { SourceLoc ColonLoc; - PrecedenceGroupDecl *PrecedenceGroup = nullptr; public: InfixOperatorDecl(DeclContext *DC, SourceLoc operatorLoc, Identifier name, @@ -6948,14 +6973,6 @@ class InfixOperatorDecl : public OperatorDecl { identifiers, identifierLocs), ColonLoc(colonLoc) {} - InfixOperatorDecl(DeclContext *DC, SourceLoc operatorLoc, Identifier name, - SourceLoc nameLoc, SourceLoc colonLoc, - PrecedenceGroupDecl *precedenceGroup, - ArrayRef designatedNominalTypes) - : OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc, - designatedNominalTypes), - ColonLoc(colonLoc), PrecedenceGroup(precedenceGroup) {} - SourceLoc getEndLoc() const { auto identifierLocs = getIdentifierLocs(); if (identifierLocs.empty()) @@ -6970,10 +6987,7 @@ class InfixOperatorDecl : public OperatorDecl { SourceLoc getColonLoc() const { return ColonLoc; } - PrecedenceGroupDecl *getPrecedenceGroup() const { return PrecedenceGroup; } - void setPrecedenceGroup(PrecedenceGroupDecl *PGD) { - PrecedenceGroup = PGD; - } + PrecedenceGroupDecl *getPrecedenceGroup() const; /// True if this decl's attributes conflict with those declared by another /// operator. @@ -7074,6 +7088,10 @@ class MissingMemberDecl : public Decl { && "not enough bits"); setImplicit(); } + friend class Decl; + SourceLoc getLocFromSource() const { + return SourceLoc(); + } public: static MissingMemberDecl * create(ASTContext &ctx, DeclContext *DC, DeclName name, @@ -7098,10 +7116,6 @@ class MissingMemberDecl : public Decl { return Bits.MissingMemberDecl.NumberOfFieldOffsetVectorEntries; } - SourceLoc getLoc() const { - return SourceLoc(); - } - SourceRange getSourceRange() const { return SourceRange(); } diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 4b3eee00d0c61..0a51fd2781ad6 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -409,6 +409,15 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { const_cast(this)->getInnermostDeclarationDeclContext(); } + /// Returns the innermost context that is an AbstractFunctionDecl whose + /// body has been skipped. + LLVM_READONLY + DeclContext *getInnermostSkippedFunctionContext(); + const DeclContext *getInnermostSkippedFunctionContext() const { + return + const_cast(this)->getInnermostSkippedFunctionContext(); + } + /// Returns the semantic parent of this context. A context has a /// parent if and only if it is not a module context. DeclContext *getParent() const { @@ -461,6 +470,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// AnyObject dynamic lookup. bool mayContainMembersAccessedByDynamicLookup() const; + /// Extensions are only allowed at the level in a file + /// FIXME: do this for Protocols, too someday + bool canBeParentOfExtension() const; + /// Returns true if lookups within this context could affect downstream files. /// /// \param functionsAreNonCascading If true, functions are considered non- diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 022faa7213f0e..a4ec15134e71d 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -18,15 +18,16 @@ #ifndef SWIFT_BASIC_DIAGNOSTICENGINE_H #define SWIFT_BASIC_DIAGNOSTICENGINE_H -#include "swift/AST/Attr.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/DeclNameLoc.h" #include "swift/AST/DiagnosticConsumer.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/VersionTuple.h" namespace swift { class Decl; + class DeclAttribute; class DiagnosticEngine; class SourceManager; class ValueDecl; diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index aa7edb108cf2c..b171c0f7dd92b 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -124,8 +124,13 @@ ERROR(error_mode_cannot_emit_module,none, "this mode does not support emitting modules", ()) ERROR(error_mode_cannot_emit_module_doc,none, "this mode does not support emitting module documentation files", ()) +ERROR(error_mode_cannot_emit_module_source_info,none, + "this mode does not support emitting module source info files", ()) ERROR(error_mode_cannot_emit_interface,none, "this mode does not support emitting module interface files", ()) +ERROR(cannot_emit_ir_skipping_function_bodies,none, + "-experimental-skip-non-inlinable-function-bodies does not support " + "emitting IR", ()) WARNING(emit_reference_dependencies_without_primary_file,none, "ignoring -emit-reference-dependencies (requires -primary-file)", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 7998497359785..7a7c5ccf037d1 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1116,6 +1116,8 @@ ERROR(missing_argument_named,none, "missing argument for parameter %0 in call", (Identifier)) ERROR(missing_argument_positional,none, "missing argument for parameter #%0 in call", (unsigned)) +ERROR(missing_arguments_in_call,none, + "missing arguments for parameters %0 in call", (StringRef)) ERROR(extra_argument_named,none, "extra argument %0 in call", (Identifier)) ERROR(extra_argument_positional,none, @@ -3695,6 +3697,10 @@ ERROR(single_tuple_parameter_mismatch_normal,none, (DescriptiveDeclKind, DeclBaseName, Type, StringRef)) ERROR(unknown_single_tuple_parameter_mismatch,none, "single parameter of type %0 is expected in call", (Type)) +ERROR(cannot_convert_single_tuple_into_multiple_arguments,none, + "%0 %select{%1 |}2expects %3 separate arguments" + "%select{|; remove extra parentheses to change tuple into separate arguments}4", + (DescriptiveDeclKind, DeclName, bool, unsigned, bool)) ERROR(enum_element_pattern_assoc_values_mismatch,none, "pattern with associated values does not match enum case %0", @@ -3843,9 +3849,6 @@ ERROR(sugar_type_not_found,none, "broken standard library: cannot find " "%select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|" "Error}0 type", (unsigned)) -ERROR(pointer_type_not_found,none, - "broken standard library: cannot find " - "%select{UnsafePointer|UnsafeMutablePointer}0 type", (unsigned)) ERROR(optional_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on " "Optional", ()) @@ -4745,8 +4748,6 @@ ERROR(property_wrapper_wrong_initial_value_init, none, (DeclName, Type, Type)) ERROR(property_wrapper_failable_init, none, "%0 cannot be failable", (DeclName)) -ERROR(property_wrapper_ambiguous_initial_value_init, none, - "property wrapper type %0 has multiple initial-value initializers", (Type)) ERROR(property_wrapper_ambiguous_default_value_init, none, "property wrapper type %0 has multiple default-value initializers", (Type)) ERROR(property_wrapper_type_requirement_not_accessible,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index e6b8a142a451b..b75f6dedb2d73 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -19,19 +19,19 @@ #include "swift/AST/CaptureInfo.h" #include "swift/AST/ConcreteDeclRef.h" +#include "swift/AST/DeclContext.h" #include "swift/AST/DeclNameLoc.h" #include "swift/AST/FunctionRefKind.h" #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/TrailingCallArguments.h" #include "swift/AST/TypeAlignments.h" #include "swift/AST/TypeLoc.h" -#include "swift/AST/TypeRepr.h" -// SWIFT_ENABLE_TENSORFLOW -#include "swift/AST/AutoDiff.h" #include "swift/AST/Availability.h" #include "swift/Basic/InlineBitfield.h" #include "llvm/Support/TrailingObjects.h" #include +// SWIFT_ENABLE_TENSORFLOW +#include "swift/AST/AutoDiff.h" namespace llvm { struct fltSemantics; @@ -42,7 +42,9 @@ namespace swift { class ArchetypeType; class ASTContext; class AvailabilitySpec; + class IdentTypeRepr; class Type; + class TypeRepr; class ValueDecl; class Decl; class DeclRefExpr; diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index 271a0632fd88c..5617ae7346908 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -19,6 +19,7 @@ #include "swift/AST/SimpleRequest.h" #include "swift/AST/ASTTypeIDs.h" #include "swift/Basic/Statistic.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/TinyPtrVector.h" namespace swift { @@ -273,6 +274,56 @@ class GenericParamListRequest : void cacheResult(GenericParamList *value) const; }; +struct PrecedenceGroupDescriptor { + DeclContext *dc; + Identifier ident; + SourceLoc nameLoc; + + SourceLoc getLoc() const; + + friend llvm::hash_code hash_value(const PrecedenceGroupDescriptor &owner) { + return hash_combine(llvm::hash_value(owner.dc), + llvm::hash_value(owner.ident.getAsOpaquePointer()), + llvm::hash_value(owner.nameLoc.getOpaquePointerValue())); + } + + friend bool operator==(const PrecedenceGroupDescriptor &lhs, + const PrecedenceGroupDescriptor &rhs) { + return lhs.dc == rhs.dc && + lhs.ident == rhs.ident && + lhs.nameLoc == rhs.nameLoc; + } + + friend bool operator!=(const PrecedenceGroupDescriptor &lhs, + const PrecedenceGroupDescriptor &rhs) { + return !(lhs == rhs); + } +}; + +void simple_display(llvm::raw_ostream &out, const PrecedenceGroupDescriptor &d); + +class LookupPrecedenceGroupRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, PrecedenceGroupDescriptor descriptor) const; + +public: + // Source location + SourceLoc getNearestLoc() const; + + // Separate caching. + bool isCached() const { return true; } +}; + #define SWIFT_TYPEID_ZONE NameLookup #define SWIFT_TYPEID_HEADER "swift/AST/NameLookupTypeIDZone.def" #include "swift/Basic/DefineTypeIDZone.h" diff --git a/include/swift/AST/NameLookupTypeIDZone.def b/include/swift/AST/NameLookupTypeIDZone.def index d7c9f832484b3..b33c93fee4bae 100644 --- a/include/swift/AST/NameLookupTypeIDZone.def +++ b/include/swift/AST/NameLookupTypeIDZone.def @@ -30,6 +30,9 @@ SWIFT_REQUEST(NameLookup, InheritedDeclsReferencedRequest, DirectlyReferencedTypeDecls( llvm::PointerUnion, unsigned), Uncached, HasNearestLocation) +SWIFT_REQUEST(NameLookup, LookupPrecedenceGroupRequest, + PrecedenceGroupDecl *(DeclContext *, Identifier, SourceLoc), + Cached, NoLocationInfo) SWIFT_REQUEST(NameLookup, SelfBoundsFromWhereClauseRequest, SelfBounds(llvm::PointerUnion), Uncached, NoLocationInfo) diff --git a/include/swift/AST/PropertyWrappers.h b/include/swift/AST/PropertyWrappers.h index d7e977e59262b..50e71d0a76fa8 100644 --- a/include/swift/AST/PropertyWrappers.h +++ b/include/swift/AST/PropertyWrappers.h @@ -35,12 +35,13 @@ struct PropertyWrapperTypeInfo { /// directed. VarDecl *valueVar = nullptr; - /// The initializer init(wrappedValue:) that will be called when the + /// Whether there is an init(wrappedValue:) that will be called when the /// initializing the property wrapper type from a value of the property type. - /// - /// This initializer is optional, but if present will be used for the `=` - /// initialization syntax. - ConstructorDecl *wrappedValueInit = nullptr; + enum { + NoWrappedValueInit = 0, + HasWrappedValueInit, + HasInitialValueInit + } wrappedValueInit = NoWrappedValueInit; /// The initializer `init()` that will be called to default-initialize a /// value with an attached property wrapper. diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 7dec43507ed59..a1dbc72ec031b 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -73,6 +73,9 @@ class SILOptions { /// Whether to stop the optimization pipeline after serializing SIL. bool StopOptimizationAfterSerialization = false; + /// Whether to skip emitting non-inlinable function bodies. + bool SkipNonInlinableFunctionBodies = false; + /// Optimization mode being used. OptimizationMode OptMode = OptimizationMode::NotSet; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 1df99c4070cf1..55c3685dd449f 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -33,6 +33,7 @@ class AbstractStorageDecl; class AccessorDecl; enum class AccessorKind; class GenericParamList; +class PrecedenceGroupDecl; struct PropertyWrapperBackingPropertyInfo; struct PropertyWrapperMutability; class RequirementRepr; @@ -1101,7 +1102,7 @@ class InferredGenericSignatureRequest : public SimpleRequest, + GenericParamList *, SmallVector, SmallVector, bool), @@ -1117,7 +1118,7 @@ class InferredGenericSignatureRequest : evaluate(Evaluator &evaluator, ModuleDecl *module, GenericSignature *baseSignature, - SmallVector addedParameters, + GenericParamList *gpl, SmallVector addedRequirements, SmallVector inferenceSources, bool allowConcreteGenericParams) const; @@ -1216,6 +1217,25 @@ class UnderlyingTypeRequest : void cacheResult(Type value) const; }; +class OperatorPrecedenceGroupRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, InfixOperatorDecl *PGD) const; + +public: + // Separate caching. + bool isCached() const { return true; } +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 366f11d775700..c539350de964a 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -54,7 +54,7 @@ SWIFT_REQUEST(NameLookup, GenericSignatureRequest, SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest, GenericSignature *(ModuleDecl *, GenericSignature *, - SmallVector, + GenericParamList *, SmallVector, SmallVector, bool), Cached, NoLocationInfo) @@ -85,6 +85,9 @@ SWIFT_REQUEST(TypeChecker, MangleLocalTypeDeclRequest, SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest, OpaqueReadOwnership(AbstractStorageDecl *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, OperatorPrecedenceGroupRequest, + PrecedenceGroupDecl *(PrecedenceGroupDecl *), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, OverriddenDeclsRequest, llvm::TinyPtrVector(ValueDecl *), SeparatelyCached, NoLocationInfo) diff --git a/include/swift/AST/TypeMatcher.h b/include/swift/AST/TypeMatcher.h index 28582a054a001..5f04a5f15aece 100644 --- a/include/swift/AST/TypeMatcher.h +++ b/include/swift/AST/TypeMatcher.h @@ -107,7 +107,6 @@ class TypeMatcher { TRIVIAL_CASE(BuiltinRawPointerType) TRIVIAL_CASE(BuiltinNativeObjectType) TRIVIAL_CASE(BuiltinBridgeObjectType) - TRIVIAL_CASE(BuiltinUnknownObjectType) TRIVIAL_CASE(BuiltinUnsafeValueBufferType) TRIVIAL_CASE(BuiltinVectorType) TRIVIAL_CASE(SILTokenType) diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index 1e15e580f2ff9..b04f82bb9a8de 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -98,7 +98,6 @@ ABSTRACT_TYPE(Builtin, Type) BUILTIN_TYPE(BuiltinRawPointer, BuiltinType) BUILTIN_TYPE(BuiltinNativeObject, BuiltinType) BUILTIN_TYPE(BuiltinBridgeObject, BuiltinType) - BUILTIN_TYPE(BuiltinUnknownObject, BuiltinType) BUILTIN_TYPE(BuiltinUnsafeValueBuffer, BuiltinType) BUILTIN_TYPE(BuiltinVector, BuiltinType) TYPE_RANGE(Builtin, BuiltinInteger, BuiltinVector) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 36cee13c00f86..2e942feb5722e 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -717,6 +717,12 @@ class alignas(1 << TypeAlignInBits) TypeBase { PointerTypeKind Ignore; return getAnyPointerElementType(Ignore); } + + /// Returns a type representing a pointer to \c this. + /// + /// \p kind must not be a raw pointer kind, since that would discard the + /// current type. + Type wrapInPointer(PointerTypeKind kind); /// Determine whether the given type is "specialized", meaning that /// it involves generic types for which generic arguments have been provided. @@ -1335,19 +1341,6 @@ class BuiltinBridgeObjectType : public BuiltinType { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinBridgeObjectType, BuiltinType); -/// BuiltinUnknownObjectType - The builtin opaque Objective-C pointer type. -/// Useful for pushing an Objective-C type through swift. -class BuiltinUnknownObjectType : public BuiltinType { - friend class ASTContext; - BuiltinUnknownObjectType(const ASTContext &C) - : BuiltinType(TypeKind::BuiltinUnknownObject, C) {} -public: - static bool classof(const TypeBase *T) { - return T->getKind() == TypeKind::BuiltinUnknownObject; - } -}; -DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinUnknownObjectType, BuiltinType); - /// BuiltinUnsafeValueBufferType - The builtin opaque fixed-size value /// buffer type, into which storage for an arbitrary value can be /// allocated using Builtin.allocateValueBuffer. diff --git a/include/swift/Basic/ExternalUnion.h b/include/swift/Basic/ExternalUnion.h index 0820fc2855e4f..8a82c78fd6d6c 100644 --- a/include/swift/Basic/ExternalUnion.h +++ b/include/swift/Basic/ExternalUnion.h @@ -433,27 +433,27 @@ struct MembersHelper<> { LLVM_ATTRIBUTE_ALWAYS_INLINE static void copyConstruct(void *self, int index, const void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void moveConstruct(void *self, int index, void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void copyAssignSame(int index, void *self, const void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void moveAssignSame(int index, void *self, void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void destruct(int index, void *self) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } }; diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index 0a20529f12f73..59e3e60c7fae7 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -50,6 +50,7 @@ TYPE("autolink", AutolinkFile, "autolink", "") TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "") TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "") TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "") +TYPE("swiftsourceinfo", SwiftSourceInfoFile, "swiftsourceinfo", "") TYPE("assembly", Assembly, "s", "") TYPE("raw-sil", RawSIL, "sil", "") TYPE("raw-sib", RawSIB, "sib", "") diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h index 3036063309233..d62547531d037 100644 --- a/include/swift/Basic/SupplementaryOutputPaths.h +++ b/include/swift/Basic/SupplementaryOutputPaths.h @@ -41,6 +41,15 @@ struct SupplementaryOutputPaths { /// \sa swift::serialize std::string ModuleOutputPath; + /// The path to which we should emit a module source information file. + /// It is valid whenever there are any inputs. + /// + /// This binary format stores source locations and other information about the + /// declarations in a module. + /// + /// \sa swift::serialize + std::string ModuleSourceInfoOutputPath; + /// The path to which we should emit a module documentation file. /// It is valid whenever there are any inputs. /// @@ -132,7 +141,8 @@ struct SupplementaryOutputPaths { ModuleDocOutputPath.empty() && DependenciesFilePath.empty() && ReferenceDependenciesFilePath.empty() && SerializedDiagnosticsPath.empty() && LoadedModuleTracePath.empty() && - TBDPath.empty() && ModuleInterfaceOutputPath.empty(); + TBDPath.empty() && ModuleInterfaceOutputPath.empty() && + ModuleSourceInfoOutputPath.empty(); } }; } // namespace swift diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 9e0822f284fb6..64c6e9920d4cd 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -167,6 +167,7 @@ NODE(PostfixOperator) NODE(PrefixOperator) NODE(PrivateDeclName) NODE(PropertyDescriptor) +CONTEXT_NODE(PropertyWrapperBackingInitializer) CONTEXT_NODE(Protocol) CONTEXT_NODE(ProtocolSymbolicReference) NODE(ProtocolConformance) diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h index 2b02e87f070c5..5592f2d291d23 100644 --- a/include/swift/Driver/Driver.h +++ b/include/swift/Driver/Driver.h @@ -354,6 +354,11 @@ class Driver { StringRef workingDirectory, CommandOutput *Output) const; + void chooseSwiftSourceInfoOutputPath(Compilation &C, + const TypeToPathMap *OutputMap, + StringRef workingDirectory, + CommandOutput *Output) const; + void chooseModuleInterfacePath(Compilation &C, const JobAction *JA, StringRef workingDirectory, llvm::SmallString<128> &buffer, diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h index 56ba02ea6956c..66a640fc24061 100644 --- a/include/swift/Frontend/FrontendInputsAndOutputs.h +++ b/include/swift/Frontend/FrontendInputsAndOutputs.h @@ -235,6 +235,7 @@ class FrontendInputsAndOutputs { bool hasLoadedModuleTracePath() const; bool hasModuleOutputPath() const; bool hasModuleDocOutputPath() const; + bool hasModuleSourceInfoOutputPath() const; bool hasModuleInterfaceOutputPath() const; bool hasTBDPath() const; diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index ad4f4ccd7bdd3..cdcc496c1e524 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -180,6 +180,8 @@ class FrontendOptions { /// \sa swift::SharedTimer bool DebugTimeCompilation = false; + bool SkipNonInlinableFunctionBodies = false; + /// The path to which we should output statistics files. std::string StatsOutputDir; @@ -339,6 +341,7 @@ class FrontendOptions { public: static bool doesActionGenerateSIL(ActionType); + static bool doesActionGenerateIR(ActionType); static bool doesActionProduceOutput(ActionType); static bool doesActionProduceTextualOutput(ActionType); static bool needsProperModuleName(ActionType); diff --git a/include/swift/IRGen/IRGenPublic.h b/include/swift/IRGen/IRGenPublic.h index a5857a6995379..3d1c11c487787 100644 --- a/include/swift/IRGen/IRGenPublic.h +++ b/include/swift/IRGen/IRGenPublic.h @@ -36,6 +36,9 @@ createIRGenModule(SILModule *SILMod, StringRef OutputFilename, /// Delete the IRGenModule and IRGenerator obtained by the above call. void deleteIRGenModule(std::pair &Module); +/// Gets the ABI version number that'll be set as a flag in the module. +uint32_t getSwiftABIVersion(); + } // end namespace irgen } // end namespace swift diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 25509ee0a8676..dd6bc64d6857a 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -38,6 +38,9 @@ def emit_module_doc_path : Separate<["-"], "emit-module-doc-path">, MetaVarName<"">, HelpText<"Output module documentation file ">; +def emit_module_source_info : Flag<["-"], "emit-module-source-info">, + HelpText<"Output module source info file">; + def merge_modules : Flag<["-"], "merge-modules">, ModeOpt, HelpText<"Merge the input modules without otherwise processing them">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 5a817c641d1fc..9b6cea3202671 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -254,6 +254,10 @@ def stats_output_dir: Separate<["-"], "stats-output-dir">, def trace_stats_events: Flag<["-"], "trace-stats-events">, Flags<[FrontendOption, HelpHidden]>, HelpText<"Trace changes to stats in -stats-output-dir">; +def experimental_skip_non_inlinable_function_bodies: + Flag<["-"], "experimental-skip-non-inlinable-function-bodies">, + Flags<[FrontendOption, HelpHidden]>, + HelpText<"Skip type-checking and SIL generation for non-inlinable function bodies">; def profile_stats_events: Flag<["-"], "profile-stats-events">, Flags<[FrontendOption, HelpHidden]>, HelpText<"Profile changes to stats in -stats-output-dir">; @@ -364,6 +368,12 @@ def emit_module_interface_path : ArgumentIsPath]>, MetaVarName<"">, HelpText<"Output module interface file to ">; +def emit_module_source_info_path : + Separate<["-"], "emit-module-source-info-path">, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, + ArgumentIsPath]>, + MetaVarName<"">, HelpText<"Output module source info file to ">; + def emit_parseable_module_interface : Flag<["-"], "emit-parseable-module-interface">, Alias, diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index 7cec25cbea816..fe5551570653a 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -21,6 +21,9 @@ #include "llvm/ADT/DenseMap.h" namespace swift { +class ComponentIdentTypeRepr; +class TupleTypeRepr; + /// Generates AST nodes from Syntax nodes. class Parser; class ASTGen { diff --git a/include/swift/Parse/ParsedRawSyntaxNode.h b/include/swift/Parse/ParsedRawSyntaxNode.h index 2c80ee7b89de1..eb55cff04b271 100644 --- a/include/swift/Parse/ParsedRawSyntaxNode.h +++ b/include/swift/Parse/ParsedRawSyntaxNode.h @@ -109,10 +109,12 @@ class ParsedRawSyntaxNode { } ParsedRawSyntaxNode(syntax::SyntaxKind k, tok tokKind, - CharSourceRange r, OpaqueSyntaxNode n) + CharSourceRange r, OpaqueSyntaxNode n, + bool IsMissing = false) : RecordedData{n, r}, SynKind(uint16_t(k)), TokKind(uint16_t(tokKind)), - DK(DataKind::Recorded) { + DK(DataKind::Recorded), + IsMissing(IsMissing) { assert(getKind() == k && "Syntax kind with too large value!"); assert(getTokenKind() == tokKind && "Token kind with too large value!"); } @@ -197,12 +199,14 @@ class ParsedRawSyntaxNode { return copy; } - CharSourceRange getDeferredRange() const { + CharSourceRange getDeferredRange(bool includeTrivia) const { switch (DK) { case DataKind::DeferredLayout: - return getDeferredLayoutRange(); + return getDeferredLayoutRange(includeTrivia); case DataKind::DeferredToken: - return getDeferredTokenRange(); + return includeTrivia + ? getDeferredTokenRangeWithTrivia() + : getDeferredTokenRange(); default: llvm_unreachable("node not deferred"); } @@ -227,18 +231,19 @@ class ParsedRawSyntaxNode { // Deferred Layout Data ====================================================// - CharSourceRange getDeferredLayoutRange() const { + CharSourceRange getDeferredLayoutRange(bool includeTrivia) const { assert(DK == DataKind::DeferredLayout); - assert(!DeferredLayout.Children.empty()); - auto getLastNonNullChild = [this]() -> const ParsedRawSyntaxNode & { - for (auto &Child : llvm::reverse(getDeferredChildren())) - if (!Child.isNull()) - return Child; - llvm_unreachable("layout node without non-null children"); + auto HasValidRange = [includeTrivia](const ParsedRawSyntaxNode &Child) { + return !Child.isNull() && !Child.isMissing() && + Child.getDeferredRange(includeTrivia).isValid(); }; - auto firstRange = DeferredLayout.Children.front().getDeferredRange(); - auto lastRange = getLastNonNullChild().getDeferredRange(); - firstRange.widen(lastRange); + auto first = llvm::find_if(getDeferredChildren(), HasValidRange); + if (first == getDeferredChildren().end()) + return CharSourceRange(); + auto last = llvm::find_if(llvm::reverse(getDeferredChildren()), + HasValidRange); + auto firstRange = first->getDeferredRange(includeTrivia); + firstRange.widen(last->getDeferredRange(includeTrivia)); return firstRange; } ArrayRef getDeferredChildren() const { diff --git a/include/swift/Parse/ParsedRawSyntaxRecorder.h b/include/swift/Parse/ParsedRawSyntaxRecorder.h index 1afe4837fdc76..a1df540c94075 100644 --- a/include/swift/Parse/ParsedRawSyntaxRecorder.h +++ b/include/swift/Parse/ParsedRawSyntaxRecorder.h @@ -73,6 +73,10 @@ class ParsedRawSyntaxRecorder { /// Used for incremental re-parsing. ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc, syntax::SyntaxKind kind); + + #ifndef NDEBUG + static void verifyElementRanges(ArrayRef elements); + #endif }; } // end namespace swift diff --git a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb index ac51c8ce91017..a78ac1598fa0d 100644 --- a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb +++ b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb @@ -62,9 +62,9 @@ public: % end Parsed${node.name} build(); - Parsed${node.name} makeDeferred(); private: + Parsed${node.name} makeDeferred(); Parsed${node.name} record(); void finishLayout(bool deferred); }; diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index 713d8b9b7c949..0e7ef3f4f1111 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -43,23 +43,22 @@ struct ParsedSyntaxRecorder { % end % child_params = ', '.join(child_params) private: - static Parsed${node.name} record${node.syntax_kind}(${child_params}, + static Parsed${node.name} record${node.syntax_kind}(MutableArrayRef layout, ParsedRawSyntaxRecorder &rec); -public: - static Parsed${node.name} defer${node.syntax_kind}(${child_params}, + static Parsed${node.name} defer${node.syntax_kind}(MutableArrayRef layout, SyntaxParsingContext &SPCtx); +public: static Parsed${node.name} make${node.syntax_kind}(${child_params}, SyntaxParsingContext &SPCtx); % elif node.is_syntax_collection(): private: static Parsed${node.name} record${node.syntax_kind}( - MutableArrayRef elts, + MutableArrayRef layout, ParsedRawSyntaxRecorder &rec); - -public: static Parsed${node.name} defer${node.syntax_kind}( - MutableArrayRef elts, + MutableArrayRef layout, SyntaxParsingContext &SPCtx); +public: static Parsed${node.name} make${node.syntax_kind}( MutableArrayRef elts, SyntaxParsingContext &SPCtx); @@ -69,14 +68,12 @@ public: % elif node.is_unknown(): private: static Parsed${node.name} record${node.syntax_kind}( - MutableArrayRef elts, + MutableArrayRef layout, ParsedRawSyntaxRecorder &rec); - -public: static Parsed${node.name} defer${node.syntax_kind}( - MutableArrayRef elts, + MutableArrayRef layout, SyntaxParsingContext &SPCtx); - +public: static Parsed${node.name} make${node.syntax_kind}( MutableArrayRef elts, SyntaxParsingContext &SPCtx); diff --git a/include/swift/Reflection/Records.h b/include/swift/Reflection/Records.h index c6f2fe7299b49..431877b309420 100644 --- a/include/swift/Reflection/Records.h +++ b/include/swift/Reflection/Records.h @@ -70,10 +70,11 @@ class FieldRecordFlags { class FieldRecord { const FieldRecordFlags Flags; + +public: const RelativeDirectPointer MangledTypeName; const RelativeDirectPointer FieldName; -public: FieldRecord() = delete; bool hasMangledTypeName() const { @@ -84,11 +85,8 @@ class FieldRecord { return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get()); } - StringRef getFieldName(uintptr_t Low, uintptr_t High) const { - uintptr_t nameAddr = (uintptr_t)FieldName.get(); - if (nameAddr < Low || nameAddr > High) - return ""; - return (const char *)nameAddr; + StringRef getFieldName() const { + return FieldName.get(); } bool isIndirectCase() const { @@ -162,10 +160,10 @@ class FieldDescriptor { return reinterpret_cast(this + 1); } +public: const RelativeDirectPointer MangledTypeName; const RelativeDirectPointer Superclass; -public: FieldDescriptor() = delete; const FieldDescriptorKind Kind; @@ -227,46 +225,13 @@ class FieldDescriptor { } }; -class FieldDescriptorIterator - : public std::iterator { -public: - const void *Cur; - const void * const End; - FieldDescriptorIterator(const void *Cur, const void * const End) - : Cur(Cur), End(End) {} - - const FieldDescriptor &operator*() const { - return *reinterpret_cast(Cur); - } - - const FieldDescriptor *operator->() const { - return reinterpret_cast(Cur); - } - - FieldDescriptorIterator &operator++() { - const auto &FR = this->operator*(); - const void *Next = reinterpret_cast(Cur) - + sizeof(FieldDescriptor) + FR.NumFields * FR.FieldRecordSize; - Cur = Next; - return *this; - } - - bool operator==(FieldDescriptorIterator const &other) const { - return Cur == other.Cur && End == other.End; - } - - bool operator!=(FieldDescriptorIterator const &other) const { - return !(*this == other); - } -}; - // Associated type records describe the mapping from an associated // type to the type witness of a conformance. class AssociatedTypeRecord { +public: const RelativeDirectPointer Name; const RelativeDirectPointer SubstitutedTypeName; -public: StringRef getName() const { return Name.get(); } @@ -322,10 +287,9 @@ struct AssociatedTypeRecordIterator { // An associated type descriptor contains a collection of associated // type records for a conformance. struct AssociatedTypeDescriptor { -private: +public: const RelativeDirectPointer ConformingTypeName; const RelativeDirectPointer ProtocolTypeName; -public: uint32_t NumAssociatedTypes; uint32_t AssociatedTypeRecordSize; @@ -357,46 +321,12 @@ struct AssociatedTypeDescriptor { } }; -class AssociatedTypeIterator - : public std::iterator { -public: - const void *Cur; - const void * const End; - AssociatedTypeIterator(const void *Cur, const void * const End) - : Cur(Cur), End(End) {} - - const AssociatedTypeDescriptor &operator*() const { - return *reinterpret_cast(Cur); - } - - const AssociatedTypeDescriptor *operator->() const { - return reinterpret_cast(Cur); - } - - AssociatedTypeIterator &operator++() { - const auto &ATR = this->operator*(); - size_t Size = sizeof(AssociatedTypeDescriptor) + - ATR.NumAssociatedTypes * ATR.AssociatedTypeRecordSize; - const void *Next = reinterpret_cast(Cur) + Size; - Cur = Next; - return *this; - } - - bool operator==(AssociatedTypeIterator const &other) const { - return Cur == other.Cur && End == other.End; - } - - bool operator!=(AssociatedTypeIterator const &other) const { - return !(*this == other); - } -}; - // Builtin type records describe basic layout information about // any builtin types referenced from the other sections. class BuiltinTypeDescriptor { +public: const RelativeDirectPointer TypeName; -public: uint32_t Size; // - Least significant 16 bits are the alignment. @@ -424,42 +354,10 @@ class BuiltinTypeDescriptor { } }; -class BuiltinTypeDescriptorIterator - : public std::iterator { -public: - const void *Cur; - const void * const End; - BuiltinTypeDescriptorIterator(const void *Cur, const void * const End) - : Cur(Cur), End(End) {} - - const BuiltinTypeDescriptor &operator*() const { - return *reinterpret_cast(Cur); - } - - const BuiltinTypeDescriptor *operator->() const { - return reinterpret_cast(Cur);; - } - - BuiltinTypeDescriptorIterator &operator++() { - const void *Next = reinterpret_cast(Cur) - + sizeof(BuiltinTypeDescriptor); - Cur = Next; - return *this; - } - - bool operator==(BuiltinTypeDescriptorIterator const &other) const { - return Cur == other.Cur && End == other.End; - } - - bool operator!=(BuiltinTypeDescriptorIterator const &other) const { - return !(*this == other); - } -}; - class CaptureTypeRecord { +public: const RelativeDirectPointer MangledTypeName; -public: CaptureTypeRecord() = delete; bool hasMangledTypeName() const { @@ -502,10 +400,10 @@ struct CaptureTypeRecordIterator { }; class MetadataSourceRecord { +public: const RelativeDirectPointer MangledTypeName; const RelativeDirectPointer MangledMetadataSource; -public: MetadataSourceRecord() = delete; bool hasMangledTypeName() const { @@ -608,41 +506,6 @@ class CaptureDescriptor { } }; -class CaptureDescriptorIterator - : public std::iterator { -public: - const void *Cur; - const void * const End; - CaptureDescriptorIterator(const void *Cur, const void * const End) - : Cur(Cur), End(End) {} - - const CaptureDescriptor &operator*() const { - return *reinterpret_cast(Cur); - } - - const CaptureDescriptor *operator->() const { - return reinterpret_cast(Cur); - } - - CaptureDescriptorIterator &operator++() { - const auto &CR = this->operator*(); - const void *Next = reinterpret_cast(Cur) - + sizeof(CaptureDescriptor) - + CR.NumCaptureTypes * sizeof(CaptureTypeRecord) - + CR.NumMetadataSources * sizeof(MetadataSourceRecord); - Cur = Next; - return *this; - } - - bool operator==(CaptureDescriptorIterator const &other) const { - return Cur == other.Cur && End == other.End; - } - - bool operator!=(CaptureDescriptorIterator const &other) const { - return !(*this == other); - } -}; - } // end namespace reflection } // end namespace swift diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index be51f67928b81..171f2df7b6d27 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -107,9 +107,8 @@ class ReflectionContext using typename super::StoredPointer; explicit ReflectionContext(std::shared_ptr reader) - : super(std::move(reader)) { - getBuilder().setMetadataReader(*this); - } + : super(std::move(reader), *this) + {} ReflectionContext(const ReflectionContext &other) = delete; ReflectionContext &operator=(const ReflectionContext &other) = delete; @@ -206,7 +205,7 @@ class ReflectionContext RangeEnd - RangeStart); auto findMachOSectionByName = [&](std::string Name) - -> std::pair { + -> std::pair, uint64_t> { for (unsigned I = 0; I < NumSect; ++I) { auto S = reinterpret_cast( SectionsBuf + (I * sizeof(typename T::Section))); @@ -216,10 +215,11 @@ class ReflectionContext auto SectBufData = reinterpret_cast(SectBuf.get()); auto LocalSectStart = reinterpret_cast(SectBufData + RemoteSecStart - RangeStart); - auto LocalSectEnd = reinterpret_cast(LocalSectStart + S->size); - return {LocalSectStart, LocalSectEnd}; + + auto StartRef = RemoteRef(RemoteSecStart, LocalSectStart); + return {StartRef, S->size}; } - return {nullptr, nullptr}; + return {nullptr, 0}; }; auto FieldMdSec = findMachOSectionByName("__swift5_fieldmd"); @@ -237,18 +237,13 @@ class ReflectionContext ReflStrMdSec.first == nullptr) return false; - auto LocalStartAddress = reinterpret_cast(SectBuf.get()); - auto RemoteStartAddress = static_cast(RangeStart); - ReflectionInfo info = { {FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, {CaptureSec.first, CaptureSec.second}, {TypeRefMdSec.first, TypeRefMdSec.second}, - {ReflStrMdSec.first, ReflStrMdSec.second}, - LocalStartAddress, - RemoteStartAddress}; + {ReflStrMdSec.first, ReflStrMdSec.second}}; this->addReflectionInfo(info); @@ -298,7 +293,7 @@ class ReflectionContext sizeof(llvm::object::coff_section) * COFFFileHdr->NumberOfSections); auto findCOFFSectionByName = [&](llvm::StringRef Name) - -> std::pair { + -> std::pair, uint64_t> { for (size_t i = 0; i < COFFFileHdr->NumberOfSections; ++i) { const llvm::object::coff_section *COFFSec = reinterpret_cast( @@ -313,34 +308,30 @@ class ReflectionContext auto Addr = ImageStart.getAddressData() + COFFSec->VirtualAddress; auto Buf = this->getReader().readBytes(RemoteAddress(Addr), COFFSec->VirtualSize); - const char *Begin = reinterpret_cast(Buf.get()); - const char *End = Begin + COFFSec->VirtualSize; + auto BufStart = Buf.get(); savedBuffers.push_back(std::move(Buf)); + auto Begin = RemoteRef(Addr, BufStart); + auto Size = COFFSec->VirtualSize; + // FIXME: This code needs to be cleaned up and updated // to make it work for 32 bit platforms. if (SectionName != ".sw5cptr" && SectionName != ".sw5bltn") { - Begin += 8; - End -= 8; + Begin = Begin.atByteOffset(8); + Size -= 16; } - return {Begin, End}; + return {Begin, Size}; } - return {nullptr, nullptr}; + return {nullptr, 0}; }; - std::pair CaptureSec = - findCOFFSectionByName(".sw5cptr"); - std::pair TypeRefMdSec = - findCOFFSectionByName(".sw5tyrf"); - std::pair FieldMdSec = - findCOFFSectionByName(".sw5flmd"); - std::pair AssocTySec = - findCOFFSectionByName(".sw5asty"); - std::pair BuiltinTySec = - findCOFFSectionByName(".sw5bltn"); - std::pair ReflStrMdSec = - findCOFFSectionByName(".sw5rfst"); + auto CaptureSec = findCOFFSectionByName(".sw5cptr"); + auto TypeRefMdSec = findCOFFSectionByName(".sw5tyrf"); + auto FieldMdSec = findCOFFSectionByName(".sw5flmd"); + auto AssocTySec = findCOFFSectionByName(".sw5asty"); + auto BuiltinTySec = findCOFFSectionByName(".sw5bltn"); + auto ReflStrMdSec = findCOFFSectionByName(".sw5rfst"); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -350,19 +341,13 @@ class ReflectionContext ReflStrMdSec.first == nullptr) return false; - auto LocalStartAddress = reinterpret_cast(DOSHdrBuf.get()); - auto RemoteStartAddress = - static_cast(ImageStart.getAddressData()); - ReflectionInfo Info = { {FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, {CaptureSec.first, CaptureSec.second}, {TypeRefMdSec.first, TypeRefMdSec.second}, - {ReflStrMdSec.first, ReflStrMdSec.second}, - LocalStartAddress, - RemoteStartAddress}; + {ReflStrMdSec.first, ReflStrMdSec.second}}; this->addReflectionInfo(Info); return true; } @@ -434,7 +419,7 @@ class ReflectionContext auto StrTab = reinterpret_cast(StrTabBuf.get()); auto findELFSectionByName = [&](std::string Name) - -> std::pair { + -> std::pair, uint64_t> { // Now for all the sections, find their name. for (const typename T::Section *Hdr : SecHdrVec) { uint32_t Offset = Hdr->sh_name; @@ -445,10 +430,12 @@ class ReflectionContext RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); auto SecSize = Hdr->sh_size; auto SecBuf = this->getReader().readBytes(SecStart, SecSize); - auto SecContents = reinterpret_cast(SecBuf.get()); - return {SecContents, SecContents + SecSize}; + auto SecContents = RemoteRef(SecStart.getAddressData(), + SecBuf.get()); + savedBuffers.push_back(std::move(SecBuf)); + return {SecContents, SecSize}; } - return {nullptr, nullptr}; + return {nullptr, 0}; }; auto FieldMdSec = findELFSectionByName("swift5_fieldmd"); @@ -468,19 +455,13 @@ class ReflectionContext ReflStrMdSec.first == nullptr) return false; - auto LocalStartAddress = reinterpret_cast(Buf.get()); - auto RemoteStartAddress = - static_cast(ImageStart.getAddressData()); - ReflectionInfo info = { {FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, {CaptureSec.first, CaptureSec.second}, {TypeRefMdSec.first, TypeRefMdSec.second}, - {ReflStrMdSec.first, ReflStrMdSec.second}, - LocalStartAddress, - RemoteStartAddress}; + {ReflStrMdSec.first, ReflStrMdSec.second}}; this->addReflectionInfo(info); @@ -627,6 +608,8 @@ class ReflectionContext auto CDAddr = this->readCaptureDescriptorFromMetadata(*MetadataAddress); if (!CDAddr) return nullptr; + if (!CDAddr->isResolved()) + return nullptr; // FIXME: Non-generic SIL boxes also use the HeapLocalVariable metadata // kind, but with a null capture descriptor right now (see @@ -634,11 +617,12 @@ class ReflectionContext // // Non-generic SIL boxes share metadata among types with compatible // layout, but we need some way to get an outgoing pointer map for them. - auto *CD = getBuilder().getCaptureDescriptor(*CDAddr); + auto CD = getBuilder().getCaptureDescriptor( + CDAddr->getResolvedAddress().getAddressData()); if (CD == nullptr) return nullptr; - auto Info = getBuilder().getClosureContextInfo(*CD); + auto Info = getBuilder().getClosureContextInfo(CD); return getClosureContextInfo(ObjectAddress, Info); } @@ -683,7 +667,7 @@ class ReflectionContext // Class existentials have trivial layout. // It is itself the pointer to the instance followed by the witness tables. case RecordKind::ClassExistential: - // This is just Builtin.UnknownObject + // This is just AnyObject. *OutInstanceTR = ExistentialRecordTI->getFields()[0].TR; *OutInstanceAddress = ExistentialAddress; return true; diff --git a/include/swift/Reflection/TypeLowering.h b/include/swift/Reflection/TypeLowering.h index 55ffc6f0d373d..31ea60e21561f 100644 --- a/include/swift/Reflection/TypeLowering.h +++ b/include/swift/Reflection/TypeLowering.h @@ -21,6 +21,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Casting.h" +#include "swift/Remote/MetadataReader.h" #include #include @@ -30,6 +31,7 @@ namespace reflection { using llvm::cast; using llvm::dyn_cast; +using remote::RemoteRef; class TypeRef; class TypeRefBuilder; @@ -147,7 +149,8 @@ class BuiltinTypeInfo : public TypeInfo { std::string Name; public: - explicit BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor); + explicit BuiltinTypeInfo(TypeRefBuilder &builder, + RemoteRef descriptor); const std::string &getMangledTypeName() const { return Name; @@ -280,7 +283,7 @@ class TypeConverter { const TypeInfo *getEmptyTypeInfo(); template - const TypeInfoTy *makeTypeInfo(Args... args) { + const TypeInfoTy *makeTypeInfo(Args &&... args) { auto TI = new TypeInfoTy(::std::forward(args)...); Pool.push_back(std::unique_ptr(TI)); return TI; diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index 083946331540f..4c88a7b7ad09b 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -32,50 +32,167 @@ namespace swift { namespace reflection { +using remote::RemoteRef; + template class ReflectionContext; template class ReflectionSection { using const_iterator = Iterator; - const void * Begin; - const void * End; + RemoteRef Start; + uint64_t Size; public: - ReflectionSection(const void * Begin, - const void * End) - : Begin(Begin), End(End) {} - - ReflectionSection(uint64_t Begin, uint64_t End) - : Begin(reinterpret_cast(Begin)), - End(reinterpret_cast(End)) {} + ReflectionSection(RemoteRef Start, uint64_t Size) + : Start(Start), Size(Size) {} - void *startAddress() { - return const_cast(Begin); - } - const void *startAddress() const { - return Begin; + RemoteRef startAddress() const { + return Start; } - - const void *endAddress() const { - return End; + + RemoteRef endAddress() const { + return Start.atByteOffset(Size); } const_iterator begin() const { - return const_iterator(Begin, End); + return const_iterator(Start, Size); } const_iterator end() const { - return const_iterator(End, End); + return const_iterator(endAddress(), 0); } size_t size() const { - return (const char *)End - (const char *)Begin; + return Size; + } + + bool containsRemoteAddress(uint64_t remoteAddr, + uint64_t size) const { + return Start.getAddressData() <= remoteAddr + && remoteAddr + size <= Start.getAddressData() + Size; + } + + template + RemoteRef getRemoteRef(uint64_t remoteAddr) const { + assert(containsRemoteAddress(remoteAddr, sizeof(U))); + auto localAddr = (uint64_t)(uintptr_t)Start.getLocalBuffer() + + (remoteAddr - Start.getAddressData()); + + return RemoteRef(remoteAddr, (const U*)localAddr); } }; +template +class ReflectionSectionIteratorBase + : public std::iterator { +protected: + Self &asImpl() { + return *static_cast(this); + } +public: + RemoteRef Cur; + uint64_t Size; + + ReflectionSectionIteratorBase(RemoteRef Cur, uint64_t Size) + : Cur(Cur), Size(Size) { + if (Size != 0 && Self::getCurrentRecordSize(this->operator*()) > Size) { + fputs("reflection section too small!\n", stderr); + abort(); + } + } + + RemoteRef operator*() const { + assert(Size > 0); + return RemoteRef(Cur.getAddressData(), + (const Descriptor*)Cur.getLocalBuffer()); + } + + Self &operator++() { + auto CurRecord = this->operator*(); + auto CurSize = Self::getCurrentRecordSize(CurRecord); + Cur = Cur.atByteOffset(CurSize); + Size -= CurSize; + + if (Size > 0) { + auto NextRecord = this->operator*(); + auto NextSize = Self::getCurrentRecordSize(NextRecord); + if (NextSize > Size) { + fputs("reflection section too small!\n", stderr); + abort(); + } + } + + return asImpl(); + } + + bool operator==(const Self &other) const { + return Cur == other.Cur && Size == other.Size; + } + + bool operator!=(const Self &other) const { + return !(*this == other); + } +}; + +class FieldDescriptorIterator + : public ReflectionSectionIteratorBase +{ +public: + FieldDescriptorIterator(RemoteRef Cur, uint64_t Size) + : ReflectionSectionIteratorBase(Cur, Size) + {} + + static uint64_t getCurrentRecordSize(RemoteRef FR) { + return sizeof(FieldDescriptor) + FR->NumFields * FR->FieldRecordSize; + } +}; using FieldSection = ReflectionSection; + +class AssociatedTypeIterator + : public ReflectionSectionIteratorBase +{ +public: + AssociatedTypeIterator(RemoteRef Cur, uint64_t Size) + : ReflectionSectionIteratorBase(Cur, Size) + {} + + static uint64_t getCurrentRecordSize(RemoteRef ATR){ + return sizeof(AssociatedTypeDescriptor) + + ATR->NumAssociatedTypes * ATR->AssociatedTypeRecordSize; + } +}; using AssociatedTypeSection = ReflectionSection; + +class BuiltinTypeDescriptorIterator + : public ReflectionSectionIteratorBase { +public: + BuiltinTypeDescriptorIterator(RemoteRef Cur, uint64_t Size) + : ReflectionSectionIteratorBase(Cur, Size) + {} + + static uint64_t getCurrentRecordSize(RemoteRef ATR){ + return sizeof(BuiltinTypeDescriptor); + } +}; using BuiltinTypeSection = ReflectionSection; + +class CaptureDescriptorIterator + : public ReflectionSectionIteratorBase { +public: + CaptureDescriptorIterator(RemoteRef Cur, uint64_t Size) + : ReflectionSectionIteratorBase(Cur, Size) + {} + + static uint64_t getCurrentRecordSize(RemoteRef CR){ + return sizeof(CaptureDescriptor) + + CR->NumCaptureTypes * sizeof(CaptureTypeRecord) + + CR->NumMetadataSources * sizeof(MetadataSourceRecord); + } +}; using CaptureSection = ReflectionSection; using GenericSection = ReflectionSection; @@ -86,9 +203,6 @@ struct ReflectionInfo { CaptureSection Capture; GenericSection TypeReference; GenericSection ReflectionString; - - uint64_t LocalStartAddress; - uint64_t RemoteStartAddress; }; struct ClosureContextInfo { @@ -137,17 +251,12 @@ class TypeRefBuilder { using BuiltTypeDecl = Optional; using BuiltProtocolDecl = Optional>; - TypeRefBuilder(); - TypeRefBuilder(const TypeRefBuilder &other) = delete; TypeRefBuilder &operator=(const TypeRefBuilder &other) = delete; private: Demangle::Demangler Dem; - std::function - OpaqueUnderlyingTypeReader; - /// Makes sure dynamically allocated TypeRefs stick around for the life of /// this TypeRefBuilder and are automatically released. std::vector> TypeRefPool; @@ -157,9 +266,7 @@ class TypeRefBuilder { TypeRefID::Hash, TypeRefID::Equal> AssociatedTypeCache; /// Cache for field info lookups. - std::unordered_map> - FieldTypeInfoCache; + std::unordered_map> FieldTypeInfoCache; TypeConverter TC; MetadataSourceBuilder MSB; @@ -455,79 +562,66 @@ class TypeRefBuilder { return ReflectionInfos; } -private: - std::vector ReflectionInfos; +public: + enum ForTesting_t { ForTesting }; - uint64_t getRemoteAddrOfTypeRefPointer(const void *pointer); + // Only for testing. A TypeRefBuilder built this way will not be able to + // decode records in remote memory. + explicit TypeRefBuilder(ForTesting_t) : TC(*this) {} - std::function Demangle::Node *> - SymbolicReferenceResolver; - - std::string normalizeReflectionName(StringRef name); - bool reflectionNameMatches(StringRef reflectionName, +private: + std::vector ReflectionInfos; + + std::string normalizeReflectionName(RemoteRef name); + bool reflectionNameMatches(RemoteRef reflectionName, StringRef searchName); + +public: + RemoteRef readTypeRef(uint64_t remoteAddr); - Demangle::Node *demangleTypeRef(StringRef mangledName) { - return Dem.demangleType(mangledName, SymbolicReferenceResolver); + template + RemoteRef readTypeRef(RemoteRef record, + const Field &field) { + uint64_t remoteAddr = record.resolveRelativeFieldData(field); + + return readTypeRef(remoteAddr); } + + StringRef getTypeRefString(RemoteRef record) { + return Demangle::makeSymbolicMangledNameStringRef(record.getLocalBuffer()); + } + +private: + // These fields are captured from the MetadataReader template passed into the + // TypeRefBuilder struct, to isolate its template-ness from the rest of + // TypeRefBuilder. + unsigned PointerSize; + std::function)> + TypeRefDemangler; + std::function + OpaqueUnderlyingTypeReader; public: template - void setMetadataReader( - remote::MetadataReader &reader) { - // Have the TypeRefBuilder demangle symbolic references by reading their - // demangling out of the referenced context descriptors in the target - // process. - SymbolicReferenceResolver = - [this, &reader](SymbolicReferenceKind kind, - Directness directness, - int32_t offset, const void *base) -> Demangle::Node * { - // Resolve the reference to a remote address. - auto remoteAddress = getRemoteAddrOfTypeRefPointer(base); - if (remoteAddress == 0) - return nullptr; - - auto address = remoteAddress + offset; - if (directness == Directness::Indirect) { - if (auto indirectAddress = reader.readPointerValue(address)) { - address = *indirectAddress; - } else { - return nullptr; - } - } - - switch (kind) { - case Demangle::SymbolicReferenceKind::Context: { - auto context = reader.readContextDescriptor(address); - if (!context) - return nullptr; - // Try to preserve a reference to an OpaqueTypeDescriptor symbolically, - // since we'd like to read out and resolve the type ref to the - // underlying type if available. - if (context->getKind() == ContextDescriptorKind::OpaqueType) { - return Dem.createNode( - Node::Kind::OpaqueTypeDescriptorSymbolicReference, - context.getAddressData()); - } - - return reader.buildContextMangling(context, Dem); - } - case Demangle::SymbolicReferenceKind::AccessorFunctionReference: - // The symbolic reference points at a resolver function, but we can't - // execute code in the target process to resolve it from here. - return nullptr; - } - - return nullptr; - }; - - OpaqueUnderlyingTypeReader = - [&reader](const void *descriptor, unsigned ordinal) -> const TypeRef* { - auto context = (typename Runtime::StoredPointer)descriptor; - return reader.readUnderlyingTypeForOpaqueTypeDescriptor(context, ordinal); - }; + TypeRefBuilder(remote::MetadataReader &reader) + : TC(*this), + PointerSize(sizeof(typename Runtime::StoredPointer)), + TypeRefDemangler( + [this, &reader](RemoteRef string) -> Demangle::Node * { + return reader.demangle(string, + remote::MangledNameKind::Type, + Dem, /*useOpaqueTypeSymbolicReferences*/ true); + }), + OpaqueUnderlyingTypeReader( + [&reader](const void *descriptor, unsigned ordinal) -> const TypeRef* { + auto context = (typename Runtime::StoredPointer)descriptor; + return reader.readUnderlyingTypeForOpaqueTypeDescriptor(context, + ordinal); + }) + {} + + Demangle::Node *demangleTypeRef(RemoteRef string) { + return TypeRefDemangler(string); } TypeConverter &getTypeConverter() { return TC; } @@ -541,29 +635,29 @@ class TypeRefBuilder { lookupSuperclass(const TypeRef *TR); /// Load unsubstituted field types for a nominal type. - std::pair + RemoteRef getFieldTypeInfo(const TypeRef *TR); /// Get the parsed and substituted field types for a nominal type. bool getFieldTypeRefs(const TypeRef *TR, - const std::pair &FD, - std::vector &Fields); + RemoteRef FD, + std::vector &Fields); /// Get the primitive type lowering for a builtin type. - const BuiltinTypeDescriptor *getBuiltinTypeInfo(const TypeRef *TR); + RemoteRef getBuiltinTypeInfo(const TypeRef *TR); /// Get the raw capture descriptor for a remote capture descriptor /// address. - const CaptureDescriptor *getCaptureDescriptor(uint64_t RemoteAddress); + RemoteRef getCaptureDescriptor(uint64_t RemoteAddress); /// Get the unsubstituted capture types for a closure context. - ClosureContextInfo getClosureContextInfo(const CaptureDescriptor &CD); + ClosureContextInfo getClosureContextInfo(RemoteRef CD); /// /// Dumping typerefs, field declarations, associated types /// - void dumpTypeRef(llvm::StringRef MangledName, + void dumpTypeRef(RemoteRef mangledName, std::ostream &OS, bool printTypeName = false); void dumpFieldSection(std::ostream &OS); void dumpAssociatedTypeSection(std::ostream &OS); diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 6907030c50d54..3424e30bda4af 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -69,7 +69,7 @@ class MemoryReader { /// NOTE: subclasses MUST override at least one of the readBytes functions. The default /// implementation calls through to the other one. virtual ReadBytesResult - readBytes(RemoteAddress address, uint64_t size) { + readBytes(RemoteAddress address, uint64_t size) { auto *Buf = malloc(size); ReadBytesResult Result(Buf, [](const void *ptr) { free(const_cast(ptr)); @@ -96,6 +96,34 @@ class MemoryReader { memcpy(dest, Ptr.get(), size); return true; } + + /// Attempts to resolve a pointer value read from the given remote address. + virtual RemoteAbsolutePointer resolvePointer(RemoteAddress address, + uint64_t readValue) { + // Default implementation returns the read value as is. + return RemoteAbsolutePointer("", readValue); + } + + /// Attempt to read and resolve a pointer value at the given remote address. + llvm::Optional readPointer(RemoteAddress address, + unsigned pointerSize) { + auto result = readBytes(address, pointerSize); + if (!result) + return llvm::None; + + uint64_t pointerData; + if (pointerSize == 4) { + uint32_t theData; + memcpy(&theData, result.get(), 4); + pointerData = theData; + } else if (pointerSize == 8) { + memcpy(&pointerData, result.get(), 8); + } else { + return llvm::None; + } + + return resolvePointer(address, pointerData); + } virtual ~MemoryReader() = default; }; diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index beaeb8dfded43..ec413b7921ca7 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -22,6 +22,7 @@ #include "swift/Demangling/Demangler.h" #include "swift/Demangling/TypeDecoder.h" #include "swift/Basic/Defer.h" +#include "swift/Basic/ExternalUnion.h" #include "swift/Basic/Range.h" #include "swift/Basic/LLVM.h" #include "swift/ABI/TypeIdentity.h" @@ -41,6 +42,12 @@ using FunctionParam = swift::Demangle::FunctionParam; template using TypeDecoder = swift::Demangle::TypeDecoder; +/// The kind of mangled name to read. +enum class MangledNameKind { + Type, + Symbol, +}; + /// A pointer to the local buffer of an object that also remembers the /// address at which it was stored remotely. template @@ -50,10 +57,12 @@ class RemoteRef { const T *LocalBuffer; public: - /*implicit*/ - RemoteRef(std::nullptr_t _) + RemoteRef() : Address(0), LocalBuffer(nullptr) {} + /*implicit*/ + RemoteRef(std::nullptr_t _) : RemoteRef() {} + template explicit RemoteRef(StoredPointer address, const T *localBuffer) : Address((uint64_t)address), LocalBuffer(localBuffer) {} @@ -69,7 +78,7 @@ class RemoteRef { explicit operator bool() const { return LocalBuffer != nullptr; } - + const T *operator->() const { assert(LocalBuffer); return LocalBuffer; @@ -104,6 +113,11 @@ class RemoteRef { uint64_t resolveRelativeFieldData(U &field) const { return getField(field).resolveRelativeAddressData(); } + + RemoteRef atByteOffset(int64_t Offset) const { + return RemoteRef(Address + Offset, + (const T *)((intptr_t)LocalBuffer + Offset)); + } }; /// A structure, designed for use with std::unique_ptr, which destroys @@ -168,6 +182,75 @@ class MetadataReader { std::unique_ptr, delete_with_free>; + /// A reference to a context descriptor that may be in an unloaded image. + class ParentContextDescriptorRef { + bool IsResolved; + using Payloads = ExternalUnionMembers; + static typename Payloads::Index getPayloadIndex(bool IsResolved) { + return IsResolved ? Payloads::template indexOf() + : Payloads::template indexOf(); + } + + ExternalUnion Payload; + + public: + explicit ParentContextDescriptorRef(StringRef Symbol) + : IsResolved(false) + { + Payload.template emplace(IsResolved, Symbol); + } + + explicit ParentContextDescriptorRef(ContextDescriptorRef Resolved) + : IsResolved(true) + { + Payload.template emplace(IsResolved, Resolved); + } + + ParentContextDescriptorRef() + : ParentContextDescriptorRef(ContextDescriptorRef()) + {} + + ParentContextDescriptorRef(const ParentContextDescriptorRef &o) + : IsResolved(o.IsResolved) + { + Payload.copyConstruct(IsResolved, o.Payload); + } + + ParentContextDescriptorRef(ParentContextDescriptorRef &&o) + : IsResolved(o.IsResolved) + { + Payload.moveConstruct(IsResolved, std::move(o.Payload)); + } + + ~ParentContextDescriptorRef() { + Payload.destruct(IsResolved); + } + + ParentContextDescriptorRef &operator=(const ParentContextDescriptorRef &o) { + Payload.copyAssign(IsResolved, o.IsResolved, o.Payload); + IsResolved = o.isResolved(); + return *this; + } + ParentContextDescriptorRef &operator=(ParentContextDescriptorRef &&o) { + Payload.moveAssign(IsResolved, o.IsResolved, std::move(o.Payload)); + IsResolved = o.isResolved(); + return *this; + } + + bool isResolved() const { return IsResolved; } + + StringRef getSymbol() const { + return Payload.template get(IsResolved); + } + + ContextDescriptorRef getResolved() const { + return Payload.template get(IsResolved); + } + + explicit operator bool() const { + return !isResolved() || getResolved(); + } + }; /// A cache of read nominal type descriptors, keyed by the address of the /// nominal type descriptor. std::unordered_map @@ -280,6 +363,79 @@ class MetadataReader { ContextDescriptorCache.clear(); } + /// Demangle a mangled name that was read from the given remote address. + Demangle::NodePointer demangle(RemoteRef mangledName, + MangledNameKind kind, + Demangler &dem, + bool useOpaqueTypeSymbolicReferences = false) { + // Symbolic reference resolver for the demangle operation below. + auto symbolicReferenceResolver = [&](SymbolicReferenceKind kind, + Directness directness, + int32_t offset, + const void *base) -> + swift::Demangle::NodePointer { + // Resolve the reference to a remote address. + auto offsetInMangledName = + (const char *)base - mangledName.getLocalBuffer(); + auto remoteAddress = + mangledName.getAddressData() + offsetInMangledName + offset; + + RemoteAbsolutePointer resolved; + if (directness == Directness::Indirect) { + if (auto indirectAddress = readPointer(remoteAddress)) { + resolved = *indirectAddress; + } else { + return nullptr; + } + } else { + resolved = RemoteAbsolutePointer("", remoteAddress); + } + + switch (kind) { + case Demangle::SymbolicReferenceKind::Context: { + auto context = readContextDescriptor(resolved); + if (!context) + return nullptr; + // Try to preserve a reference to an OpaqueTypeDescriptor + // symbolically, since we'd like to read out and resolve the type ref + // to the underlying type if available. + if (useOpaqueTypeSymbolicReferences + && context.isResolved() + && context.getResolved()->getKind() == ContextDescriptorKind::OpaqueType){ + return dem.createNode( + Node::Kind::OpaqueTypeDescriptorSymbolicReference, + context.getResolved().getAddressData()); + } + + return buildContextMangling(context, dem); + } + case Demangle::SymbolicReferenceKind::AccessorFunctionReference: { + // The symbolic reference points at a resolver function, but we can't + // execute code in the target process to resolve it from here. + return nullptr; + } + } + + return nullptr; + }; + + auto mangledNameStr = + Demangle::makeSymbolicMangledNameStringRef(mangledName.getLocalBuffer()); + + swift::Demangle::NodePointer result; + switch (kind) { + case MangledNameKind::Type: + result = dem.demangleType(mangledNameStr, symbolicReferenceResolver); + break; + + case MangledNameKind::Symbol: + result = dem.demangleSymbol(mangledNameStr, symbolicReferenceResolver); + break; + } + + return result; + } + /// Given a demangle tree, attempt to turn it into a type. BuiltType decodeMangledType(NodePointer Node) { return swift::Demangle::decodeMangledType(Builder, Node); @@ -344,14 +500,6 @@ class MetadataReader { return start; } - /// Given a pointer to an address, attemp to read the pointer value. - Optional readPointerValue(StoredPointer Address) { - StoredPointer PointerVal; - if (!Reader->readInteger(RemoteAddress(Address), &PointerVal)) - return None; - return Optional(PointerVal); - } - /// Given a pointer to the metadata, attempt to read the value /// witness table. Note that it's not safe to access any non-mandatory /// members of the value witness table, like extra inhabitants or enum members. @@ -739,6 +887,23 @@ class MetadataReader { Dem.demangleSymbol(StringRef(MangledTypeName, Length)); return decodeMangledType(Demangled); } + + /// Given the address of a context descriptor, attempt to read it, or + /// represent it symbolically. + ParentContextDescriptorRef + readContextDescriptor(const RemoteAbsolutePointer &address) { + // Map an unresolved pointer to an unresolved context ref. + if (!address.isResolved()) { + // We can only handle references to a symbol without an offset currently. + if (address.getOffset() != 0) { + return ParentContextDescriptorRef(); + } + return ParentContextDescriptorRef(address.getSymbol()); + } + + return ParentContextDescriptorRef( + readContextDescriptor(address.getResolvedAddress().getAddressData())); + } /// Given the address of a context descriptor, attempt to read it. ContextDescriptorRef @@ -787,7 +952,7 @@ class MetadataReader { baseSize = sizeof(TargetAnonymousContextDescriptor); if (AnonymousContextDescriptorFlags(flags.getKindSpecificFlags()) .hasMangledName()) { - baseSize += sizeof(TargetMangledContextName); + metadataInitSize = sizeof(TargetMangledContextName); } break; case ContextDescriptorKind::Class: @@ -872,6 +1037,44 @@ class MetadataReader { return ContextDescriptorRef(address, descriptor); } + /// Demangle the entity represented by a symbolic reference to a given symbol name. + Demangle::NodePointer + buildContextManglingForSymbol(StringRef symbol, Demangler &dem) { + auto demangledSymbol = dem.demangleSymbol(symbol); + if (demangledSymbol->getKind() == Demangle::Node::Kind::Global) { + demangledSymbol = demangledSymbol->getChild(0); + } + + switch (demangledSymbol->getKind()) { + // Pointers to nominal type or protocol descriptors would demangle to + // the type they represent. + case Demangle::Node::Kind::NominalTypeDescriptor: + case Demangle::Node::Kind::ProtocolDescriptor: + demangledSymbol = demangledSymbol->getChild(0); + assert(demangledSymbol->getKind() == Demangle::Node::Kind::Type); + break; + // We don't handle pointers to other symbols yet. + // TODO: Opaque type descriptors could be useful. + default: + return nullptr; + } + return demangledSymbol; + } + + /// Given a read context descriptor, attempt to build a demangling tree + /// for it. + Demangle::NodePointer + buildContextMangling(const ParentContextDescriptorRef &descriptor, + Demangler &dem) { + if (descriptor.isResolved()) { + return buildContextMangling(descriptor.getResolved(), dem); + } + + // Try to demangle the symbol name to figure out what context it would + // point to. + return buildContextManglingForSymbol(descriptor.getSymbol(), dem); + } + /// Given a read context descriptor, attempt to build a demangling tree /// for it. Demangle::NodePointer @@ -1249,47 +1452,40 @@ class MetadataReader { auto heapMeta = cast>(meta); return heapMeta->OffsetToFirstCapture; } + + Optional readPointer(StoredPointer address) { + return Reader->readPointer(RemoteAddress(address), sizeof(StoredPointer)); + } + + Optional readResolvedPointerValue(StoredPointer address) { + if (auto pointer = readPointer(address)) { + if (!pointer->isResolved()) + return None; + return (StoredPointer)pointer->getResolvedAddress().getAddressData(); + } + return None; + } + + template + RemoteAbsolutePointer resolvePointerField(RemoteRef base, + const U &field) { + auto pointerRef = base.getField(field); + return Reader->resolvePointer(RemoteAddress(getAddress(pointerRef)), + *pointerRef.getLocalBuffer()); + } /// Given a remote pointer to class metadata, attempt to read its superclass. - Optional + Optional readCaptureDescriptorFromMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) return None; auto heapMeta = cast>(meta); - return heapMeta->CaptureDescription; + return resolvePointerField(meta, heapMeta->CaptureDescription); } protected: - template - Optional - resolveNullableRelativeIndirectableOffset(StoredPointer targetAddress) { - Offset relative; - if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) - return None; - if (relative == 0) - return 0; - bool indirect = relative & 1; - relative &= ~1u; - - using SignedOffset = typename std::make_signed::type; - using SignedPointer = typename std::make_signed::type; - auto signext = (SignedPointer)(SignedOffset)relative; - - StoredPointer resultAddress = targetAddress + signext; - - // Low bit set in the offset indicates that the offset leads to the absolute - // address in memory. - if (indirect) { - if (!Reader->readBytes(RemoteAddress(resultAddress), - (uint8_t *)&resultAddress, - sizeof(StoredPointer))) - return None; - } - return resultAddress; - } - template StoredPointer getAddress(RemoteRef base) { return (StoredPointer)base.getAddressData(); @@ -1302,14 +1498,14 @@ class MetadataReader { } template - Optional resolveRelativeIndirectableField( + Optional resolveRelativeIndirectableField( RemoteRef base, const Field &field) { auto fieldRef = base.getField(field); int32_t offset; memcpy(&offset, fieldRef.getLocalBuffer(), sizeof(int32_t)); if (offset == 0) - return 0; + return Optional(nullptr); bool indirect = offset & 1; offset &= ~1u; @@ -1320,14 +1516,10 @@ class MetadataReader { // Low bit set in the offset indicates that the offset leads to the absolute // address in memory. if (indirect) { - if (!Reader->readBytes(RemoteAddress(resultAddress), - (uint8_t *)&resultAddress, - sizeof(StoredPointer))) { - return None; - } + return readPointer(resultAddress); } - return resultAddress; + return RemoteAbsolutePointer("", resultAddress); } /// Given a pointer to an Objective-C class, try to read its class name. @@ -1530,17 +1722,26 @@ class MetadataReader { } } - /// Returns Optional(nullptr) if there's no parent descriptor. + /// Returns Optional(ParentContextDescriptorRef()) if there's no parent descriptor. /// Returns None if there was an error reading the parent descriptor. - Optional + Optional readParentContextDescriptor(ContextDescriptorRef base) { auto parentAddress = resolveRelativeIndirectableField(base, base->Parent); if (!parentAddress) return None; - if (!*parentAddress) - return ContextDescriptorRef(nullptr); - if (auto parentDescriptor = readContextDescriptor(*parentAddress)) - return parentDescriptor; + if (!parentAddress->isResolved()) { + // Currently we can only handle references directly to a symbol without + // an offset. + if (parentAddress->getOffset() != 0) { + return None; + } + return ParentContextDescriptorRef(parentAddress->getSymbol()); + } + auto addr = parentAddress->getResolvedAddress(); + if (!addr) + return ParentContextDescriptorRef(); + if (auto parentDescriptor = readContextDescriptor(addr.getAddressData())) + return ParentContextDescriptorRef(parentDescriptor); return None; } @@ -1623,12 +1824,6 @@ class MetadataReader { return name; } - /// The kind of mangled name to read. - enum class MangledNameKind { - Type, - Symbol, - }; - /// Clone the given demangle node into the demangler \c dem. static Demangle::NodePointer cloneDemangleNode(Demangle::NodePointer node, Demangler &dem) { @@ -1648,7 +1843,7 @@ class MetadataReader { } return newNode; } - + /// Read a mangled name at the given remote address and return the /// demangle tree. Demangle::NodePointer readMangledName(RemoteAddress address, @@ -1702,55 +1897,9 @@ class MetadataReader { break; } - // Symbolic reference resolver for the demangle operation below. - auto symbolicReferenceResolver = [&](SymbolicReferenceKind kind, - Directness directness, - int32_t offset, - const void *base) -> - swift::Demangle::NodePointer { - // Resolve the reference to a remote address. - auto offsetInMangledName = (const char *)base - mangledName.data(); - auto remoteAddress = - address.getAddressData() + offsetInMangledName + offset; - - if (directness == Directness::Indirect) { - if (auto indirectAddress = readPointerValue(remoteAddress)) { - remoteAddress = *indirectAddress; - } else { - return nullptr; - } - } - - switch (kind) { - case Demangle::SymbolicReferenceKind::Context: { - Demangler innerDemangler; - auto result = readDemanglingForContextDescriptor( - remoteAddress, innerDemangler); - - return cloneDemangleNode(result, dem); - } - case Demangle::SymbolicReferenceKind::AccessorFunctionReference: { - // The symbolic reference points at a resolver function, but we can't - // execute code in the target process to resolve it from here. - return nullptr; - } - } - - return nullptr; - }; - - swift::Demangle::NodePointer result; - switch (kind) { - case MangledNameKind::Type: - result = dem.demangleType(mangledName, symbolicReferenceResolver); - break; - - case MangledNameKind::Symbol: - result = dem.demangleSymbol(mangledName, symbolicReferenceResolver); - break; - } - - return result; + return demangle(RemoteRef(address.getAddressData(), + mangledName.data()), + kind, dem); } /// Read and demangle the name of an anonymous context. @@ -1777,13 +1926,20 @@ class MetadataReader { /// produce a mangled node describing the name of \c context. Demangle::NodePointer adoptAnonymousContextName(ContextDescriptorRef contextRef, - Optional &parentContextRef, - Demangler &dem, - Demangle::NodePointer &outerNode) { + Optional &parentContextRef, + Demangler &dem, + Demangle::NodePointer &outerNode) { outerNode = nullptr; - if (!parentContextRef || !*parentContextRef) + // Bail if there is no parent, or if the parent is in another image. + // (Anonymous contexts should always be emitted in the same image as their + // children.) + if (!parentContextRef + || !*parentContextRef + || !parentContextRef->isResolved()) return nullptr; + + auto parentContextLocalRef = parentContextRef->getResolved(); auto context = contextRef.getLocalBuffer(); auto typeContext = dyn_cast>(context); @@ -1792,11 +1948,11 @@ class MetadataReader { return nullptr; auto anonymousParent = dyn_cast_or_null>( - parentContextRef->getLocalBuffer()); + parentContextLocalRef.getLocalBuffer()); if (!anonymousParent) return nullptr; - auto mangledNode = demangleAnonymousContextName(*parentContextRef, dem); + auto mangledNode = demangleAnonymousContextName(parentContextLocalRef, dem); if (!mangledNode) return nullptr; @@ -1833,7 +1989,7 @@ class MetadataReader { // We have a match. Update the parent context to skip the anonymous // context entirely. - parentContextRef = readParentContextDescriptor(*parentContextRef); + parentContextRef = readParentContextDescriptor(parentContextLocalRef); // The outer node is the first child. outerNode = mangledNode->getChild(0); @@ -1884,6 +2040,26 @@ class MetadataReader { return resultAddress; } + Demangle::NodePointer + buildContextDescriptorMangling(const ParentContextDescriptorRef &descriptor, + Demangler &dem) { + if (descriptor.isResolved()) { + return buildContextDescriptorMangling(descriptor.getResolved(), dem); + } + + // Try to demangle the symbol name to figure out what context it would + // point to. + auto demangledSymbol = buildContextManglingForSymbol(descriptor.getSymbol(), + dem); + if (!demangledSymbol) + return nullptr; + // Look through Type notes since we're building up a mangling here. + if (demangledSymbol->getKind() == Demangle::Node::Kind::Type){ + demangledSymbol = demangledSymbol->getChild(0); + } + return demangledSymbol; + } + Demangle::NodePointer buildContextDescriptorMangling(ContextDescriptorRef descriptor, Demangler &dem) { @@ -2154,17 +2330,13 @@ class MetadataReader { case ContextDescriptorKind::OpaqueType: { // The opaque type may have a named anonymous context for us to map // back to its defining decl. - if (!parentDescriptorResult) - return nullptr; - - auto anonymous = - dyn_cast_or_null>( - parentDescriptorResult->getLocalBuffer()); - if (!anonymous) + if (!parentDescriptorResult + || !*parentDescriptorResult + || !parentDescriptorResult->isResolved()) return nullptr; auto mangledNode = - demangleAnonymousContextName(*parentDescriptorResult, dem); + demangleAnonymousContextName(parentDescriptorResult->getResolved(), dem); if (!mangledNode) return nullptr; if (mangledNode->getKind() == Node::Kind::Global) diff --git a/include/swift/Remote/RemoteAddress.h b/include/swift/Remote/RemoteAddress.h index 1c0d477babf14..c1448121beeba 100644 --- a/include/swift/Remote/RemoteAddress.h +++ b/include/swift/Remote/RemoteAddress.h @@ -19,6 +19,9 @@ #define SWIFT_REMOTE_REMOTEADDRESS_H #include +#include +#include +#include namespace swift { namespace remote { @@ -46,6 +49,40 @@ class RemoteAddress { } }; +/// A symbolic relocated absolute pointer value. +class RemoteAbsolutePointer { + /// The symbol name that the pointer refers to. Empty if the value is absolute. + std::string Symbol; + /// The offset from the symbol, or the resolved remote address if \c Symbol is empty. + int64_t Offset; + +public: + RemoteAbsolutePointer() + : Symbol(), Offset(0) + {} + + RemoteAbsolutePointer(std::nullptr_t) + : RemoteAbsolutePointer() + {} + + RemoteAbsolutePointer(llvm::StringRef Symbol, int64_t Offset) + : Symbol(Symbol), Offset(Offset) + {} + + bool isResolved() const { return Symbol.empty(); } + llvm::StringRef getSymbol() const { return Symbol; } + int64_t getOffset() const { return Offset; } + + RemoteAddress getResolvedAddress() const { + assert(isResolved()); + return RemoteAddress(Offset); + } + + explicit operator bool() const { + return Offset != 0 || !Symbol.empty(); + } +}; + } // end namespace remote } // end namespace swift diff --git a/include/swift/Runtime/BuiltinTypes.def b/include/swift/Runtime/BuiltinTypes.def index 8002be8a004fa..5b3894def9128 100644 --- a/include/swift/Runtime/BuiltinTypes.def +++ b/include/swift/Runtime/BuiltinTypes.def @@ -56,6 +56,8 @@ BUILTIN_POINTER_TYPE(Bb, "Builtin.BridgeObject") BUILTIN_POINTER_TYPE(Bp, "Builtin.RawPointer") BUILTIN_TYPE(BB, "Builtin.UnsafeValueBuffer") +// No longer used in the compiler as an AST type, but still used for fields  +// shaped like AnyObject (normal mangling yXl). BUILTIN_POINTER_TYPE(BO, "Builtin.UnknownObject") // Int8 vector types diff --git a/include/swift/SIL/ApplySite.h b/include/swift/SIL/ApplySite.h index b441a2af2c2fb..b8069a93ae65a 100644 --- a/include/swift/SIL/ApplySite.h +++ b/include/swift/SIL/ApplySite.h @@ -21,6 +21,7 @@ #ifndef SWIFT_SIL_APPLYSITE_H #define SWIFT_SIL_APPLYSITE_H +#include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILInstruction.h" namespace swift { @@ -397,6 +398,24 @@ class ApplySite { } } + /// If this is a terminator apply site, then pass the first instruction of + /// each successor to fun. Otherwise, pass std::next(Inst). + /// + /// The intention is that this abstraction will enable the compiler writer to + /// ignore whether or not an apply site is a terminator when inserting + /// instructions after an apply site. This results in eliminating unnecessary + /// if-else code otherwise required to handle such situations. + void insertAfter(llvm::function_ref func) { + auto *ti = dyn_cast(Inst); + if (!ti) { + return func(std::next(Inst->getIterator())); + } + + for (auto *succBlock : ti->getSuccessorBlocks()) { + func(succBlock->begin()); + } + } + static ApplySite getFromOpaqueValue(void *p) { return ApplySite(p); } friend bool operator==(ApplySite lhs, ApplySite rhs) { diff --git a/include/swift/SIL/DebugUtils.h b/include/swift/SIL/DebugUtils.h index 9bc80caa9fc2d..9269ba7934f78 100644 --- a/include/swift/SIL/DebugUtils.h +++ b/include/swift/SIL/DebugUtils.h @@ -42,14 +42,22 @@ namespace swift { class SILInstruction; - -/// Deletes all of the debug instructions that use \p Inst. -inline void deleteAllDebugUses(ValueBase *Inst) { - for (auto UI = Inst->use_begin(), E = Inst->use_end(); UI != E;) { - auto *Inst = UI->getUser(); - UI++; - if (Inst->isDebugInstruction()) - Inst->eraseFromParent(); + +/// Deletes all of the debug instructions that use \p value. +inline void deleteAllDebugUses(SILValue value) { + for (auto ui = value->use_begin(), ue = value->use_end(); ui != ue;) { + auto *inst = ui->getUser(); + ++ui; + if (inst->isDebugInstruction()) { + inst->eraseFromParent(); + } + } +} + +/// Deletes all of the debug uses of any result of \p inst. +inline void deleteAllDebugUses(SILInstruction *inst) { + for (SILValue v : inst->getResults()) { + deleteAllDebugUses(v); } } diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index cb778bf52bd58..df84e9ec2044a 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -200,7 +200,86 @@ bool isOwnershipForwardingInst(SILInstruction *i); bool isGuaranteedForwardingInst(SILInstruction *i); -struct BorrowScopeIntroducerKind { +struct BorrowScopeOperandKind { + using UnderlyingKindTy = std::underlying_type::type; + + enum Kind : UnderlyingKindTy { + BeginBorrow = UnderlyingKindTy(SILInstructionKind::BeginBorrowInst), + BeginApply = UnderlyingKindTy(SILInstructionKind::BeginApplyInst), + }; + + Kind value; + + BorrowScopeOperandKind(Kind newValue) : value(newValue) {} + BorrowScopeOperandKind(const BorrowScopeOperandKind &other) + : value(other.value) {} + operator Kind() const { return value; } + + static Optional get(SILInstructionKind kind) { + switch (kind) { + default: + return None; + case SILInstructionKind::BeginBorrowInst: + return BorrowScopeOperandKind(BeginBorrow); + case SILInstructionKind::BeginApplyInst: + return BorrowScopeOperandKind(BeginApply); + } + } + + void print(llvm::raw_ostream &os) const; + LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger"); +}; + +/// An operand whose user instruction introduces a new borrow scope for the +/// operand's value. The value of the operand must be considered as implicitly +/// borrowed until the user's corresponding end scope instruction. +struct BorrowScopeOperand { + BorrowScopeOperandKind kind; + Operand *op; + + BorrowScopeOperand(Operand *op) + : kind(*BorrowScopeOperandKind::get(op->getUser()->getKind())), op(op) {} + + /// If value is a borrow introducer return it after doing some checks. + static Optional get(Operand *op) { + auto *user = op->getUser(); + auto kind = BorrowScopeOperandKind::get(user->getKind()); + if (!kind) + return None; + return BorrowScopeOperand(*kind, op); + } + + void visitEndScopeInstructions(function_ref func) const { + switch (kind) { + case BorrowScopeOperandKind::BeginBorrow: + for (auto *use : cast(op->getUser())->getUses()) { + if (isa(use->getUser())) { + func(use); + } + } + return; + case BorrowScopeOperandKind::BeginApply: { + auto *user = cast(op->getUser()); + for (auto *use : user->getTokenResult()->getUses()) { + func(use); + } + return; + } + } + llvm_unreachable("Covered switch isn't covered"); + } + +private: + /// Internal constructor for failable static constructor. Please do not expand + /// its usage since it assumes the code passed in is well formed. + BorrowScopeOperand(BorrowScopeOperandKind kind, Operand *op) + : kind(kind), op(op) {} +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + BorrowScopeOperandKind kind); + +struct BorrowScopeIntroducingValueKind { using UnderlyingKindTy = std::underlying_type::type; /// Enum we use for exhaustive pattern matching over borrow scope introducers. @@ -210,23 +289,23 @@ struct BorrowScopeIntroducerKind { SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument), }; - static Optional get(ValueKind kind) { + static Optional get(ValueKind kind) { switch (kind) { default: return None; case ValueKind::LoadBorrowInst: - return BorrowScopeIntroducerKind(LoadBorrow); + return BorrowScopeIntroducingValueKind(LoadBorrow); case ValueKind::BeginBorrowInst: - return BorrowScopeIntroducerKind(BeginBorrow); + return BorrowScopeIntroducingValueKind(BeginBorrow); case ValueKind::SILFunctionArgument: - return BorrowScopeIntroducerKind(SILFunctionArgument); + return BorrowScopeIntroducingValueKind(SILFunctionArgument); } } Kind value; - BorrowScopeIntroducerKind(Kind newValue) : value(newValue) {} - BorrowScopeIntroducerKind(const BorrowScopeIntroducerKind &other) + BorrowScopeIntroducingValueKind(Kind newValue) : value(newValue) {} + BorrowScopeIntroducingValueKind(const BorrowScopeIntroducingValueKind &other) : value(other.value) {} operator Kind() const { return value; } @@ -238,10 +317,10 @@ struct BorrowScopeIntroducerKind { /// of the scope. bool isLocalScope() const { switch (value) { - case BorrowScopeIntroducerKind::BeginBorrow: - case BorrowScopeIntroducerKind::LoadBorrow: + case BorrowScopeIntroducingValueKind::BeginBorrow: + case BorrowScopeIntroducingValueKind::LoadBorrow: return true; - case BorrowScopeIntroducerKind::SILFunctionArgument: + case BorrowScopeIntroducingValueKind::SILFunctionArgument: return false; } llvm_unreachable("Covered switch isnt covered?!"); @@ -252,7 +331,7 @@ struct BorrowScopeIntroducerKind { }; llvm::raw_ostream &operator<<(llvm::raw_ostream &os, - BorrowScopeIntroducerKind kind); + BorrowScopeIntroducingValueKind kind); /// A higher level construct for working with values that represent the /// introduction of a new borrow scope. @@ -271,26 +350,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, /// borrow introducers can not have guaranteed results that are not creating a /// new borrow scope. No such instructions exist today. struct BorrowScopeIntroducingValue { - BorrowScopeIntroducerKind kind; + BorrowScopeIntroducingValueKind kind; SILValue value; BorrowScopeIntroducingValue(LoadBorrowInst *lbi) - : kind(BorrowScopeIntroducerKind::LoadBorrow), value(lbi) {} + : kind(BorrowScopeIntroducingValueKind::LoadBorrow), value(lbi) {} BorrowScopeIntroducingValue(BeginBorrowInst *bbi) - : kind(BorrowScopeIntroducerKind::BeginBorrow), value(bbi) {} + : kind(BorrowScopeIntroducingValueKind::BeginBorrow), value(bbi) {} BorrowScopeIntroducingValue(SILFunctionArgument *arg) - : kind(BorrowScopeIntroducerKind::SILFunctionArgument), value(arg) { + : kind(BorrowScopeIntroducingValueKind::SILFunctionArgument), value(arg) { assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed); } BorrowScopeIntroducingValue(SILValue v) - : kind(*BorrowScopeIntroducerKind::get(v->getKind())), value(v) { + : kind(*BorrowScopeIntroducingValueKind::get(v->getKind())), value(v) { assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed); } /// If value is a borrow introducer return it after doing some checks. static Optional get(SILValue value) { - auto kind = BorrowScopeIntroducerKind::get(value->getKind()); + auto kind = BorrowScopeIntroducingValueKind::get(value->getKind()); if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) return None; return BorrowScopeIntroducingValue(*kind, value); @@ -334,7 +413,8 @@ struct BorrowScopeIntroducingValue { private: /// Internal constructor for failable static constructor. Please do not expand /// its usage since it assumes the code passed in is well formed. - BorrowScopeIntroducingValue(BorrowScopeIntroducerKind kind, SILValue value) + BorrowScopeIntroducingValue(BorrowScopeIntroducingValueKind kind, + SILValue value) : kind(kind), value(value) {} }; diff --git a/include/swift/SIL/Projection.h b/include/swift/SIL/Projection.h index 675e32aa8b03a..1e4324e07b29f 100644 --- a/include/swift/SIL/Projection.h +++ b/include/swift/SIL/Projection.h @@ -22,11 +22,12 @@ #ifndef SWIFT_SIL_PROJECTION_H #define SWIFT_SIL_PROJECTION_H +#include "swift/AST/TypeAlignments.h" #include "swift/Basic/NullablePtr.h" #include "swift/Basic/PointerIntEnum.h" -#include "swift/AST/TypeAlignments.h" -#include "swift/SIL/SILValue.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILValue.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "llvm/ADT/Hashing.h" @@ -751,15 +752,17 @@ class ProjectionTreeNode { ~ProjectionTreeNode() = default; ProjectionTreeNode(const ProjectionTreeNode &) = default; - llvm::ArrayRef getChildProjections() { - return llvm::makeArrayRef(ChildProjections); + bool isLeaf() const { return ChildProjections.empty(); } + + ArrayRef getChildProjections() const { + return llvm::makeArrayRef(ChildProjections); } - llvm::Optional &getProjection() { return Proj; } + Optional &getProjection() { return Proj; } - llvm::SmallVector getNonProjUsers() const { - return NonProjUsers; - }; + const ArrayRef getNonProjUsers() const { + return llvm::makeArrayRef(NonProjUsers); + } SILType getType() const { return NodeType; } @@ -914,6 +917,24 @@ class ProjectionTree { return false; } + void getAllLeafTypes(llvm::SmallVectorImpl &outArray) const { + llvm::SmallVector worklist; + worklist.push_back(getRoot()); + + while (!worklist.empty()) { + auto *node = worklist.pop_back_val(); + // If we have a leaf node, add its type. + if (node->isLeaf()) { + outArray.push_back(node->getType()); + continue; + } + + // Otherwise, add the nodes children to the worklist. + transform(node->getChildProjections(), std::back_inserter(worklist), + [&](unsigned idx) { return getNode(idx); }); + } + } + void getLiveLeafTypes(llvm::SmallVectorImpl &OutArray) const { for (unsigned LeafIndex : LiveLeafIndices) { const ProjectionTreeNode *Node = getNode(LeafIndex); @@ -940,7 +961,9 @@ class ProjectionTree { void replaceValueUsesWithLeafUses(SILBuilder &B, SILLocation Loc, llvm::SmallVectorImpl &Leafs); - + + void getUsers(SmallPtrSetImpl &users) const; + private: void createRoot(SILType BaseTy) { assert(ProjectionTreeNodes.empty() && diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index b36411cfb3546..cc061ea25055f 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -403,6 +403,8 @@ class SILBuilder { Optional Var = None, bool hasDynamicLifetime = false) { Loc.markAsPrologue(); + assert((!dyn_cast_or_null(Loc.getAsASTNode()) || Var) && + "location is a VarDecl, but SILDebugVariable is empty"); return insert(AllocStackInst::create(getSILDebugLocation(Loc), elementType, getFunction(), C.OpenedArchetypes, Var, hasDynamicLifetime)); @@ -443,6 +445,8 @@ class SILBuilder { Optional Var = None, bool hasDynamicLifetime = false) { Loc.markAsPrologue(); + assert((!dyn_cast_or_null(Loc.getAsASTNode()) || Var) && + "location is a VarDecl, but SILDebugVariable is empty"); return insert(AllocBoxInst::create(getSILDebugLocation(Loc), BoxType, *F, C.OpenedArchetypes, Var, hasDynamicLifetime)); diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 8bdedae2c25cb..13e56b96c5f33 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -787,9 +787,16 @@ template void SILCloner::visitAllocStackInst(AllocStackInst *Inst) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createAllocStack(getOpLocation(Inst->getLoc()), - getOpType(Inst->getElementType()))); + // Drop the debug info from mandatory-inlined instructions. It's the law! + SILLocation Loc = getOpLocation(Inst->getLoc()); + Optional VarInfo = Inst->getVarInfo(); + if (Loc.getKind() == SILLocation::MandatoryInlinedKind) { + Loc = MandatoryInlinedLocation::getAutoGeneratedLocation(); + VarInfo = None; + } + recordClonedInstruction(Inst, + getBuilder().createAllocStack( + Loc, getOpType(Inst->getElementType()), VarInfo)); } template @@ -832,11 +839,19 @@ template void SILCloner::visitAllocBoxInst(AllocBoxInst *Inst) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + // Drop the debug info from mandatory-inlined instructions. + SILLocation Loc = getOpLocation(Inst->getLoc()); + Optional VarInfo = Inst->getVarInfo(); + if (Loc.getKind() == SILLocation::MandatoryInlinedKind) { + Loc = MandatoryInlinedLocation::getAutoGeneratedLocation(); + VarInfo = None; + } + recordClonedInstruction( Inst, getBuilder().createAllocBox( - getOpLocation(Inst->getLoc()), - this->getOpType(Inst->getType()).template castTo())); + Loc, this->getOpType(Inst->getType()).template castTo(), + VarInfo)); } template diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index 14e27e0e78323..a3b7909a4e00e 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -28,8 +28,7 @@ class SILValue; class SILBuilder; class SerializedSILLoader; -struct APIntSymbolicValue; -struct ArraySymbolicValue; +struct SymbolicArrayStorage; struct DerivedAddressValue; struct EnumWithPayloadSymbolicValue; struct SymbolicValueMemoryObject; @@ -256,6 +255,12 @@ class SymbolicValue { /// This represents an index *into* a memory object. RK_DerivedAddress, + + /// This represents the internal storage of an array. + RK_ArrayStorage, + + /// This represents an array. + RK_Array, }; union { @@ -299,6 +304,31 @@ class SymbolicValue { /// When this SymbolicValue is of "DerivedAddress" kind, this pointer stores /// information about the memory object and access path of the access. DerivedAddressValue *derivedAddress; + + // The following fields are for representing an Array. + // + // In Swift, an array is a non-trivial struct that stores a reference to an + // internal storage: _ContiguousArrayStorage. Though arrays have value + // semantics in Swift, it is not the case in SIL. In SIL, an array can be + // mutated by taking the address of the internal storage i.e., through a + // shared, mutable pointer to the internal storage of the array. In fact, + // this is how an array initialization is lowered in SIL. Therefore, the + // symbolic representation of an array is an addressable "memory cell" + // (i.e., a SymbolicValueMemoryObject) containing the array storage. The + // array storage is modeled by the type: SymbolicArrayStorage. This + // representation of the array enables obtaining the address of the internal + // storage and modifying the array through that address. Array operations + // such as `append` that mutate an array must clone the internal storage of + // the array, following the semantics of the Swift implementation of those + // operations. + + /// Representation of array storage (RK_ArrayStorage). SymbolicArrayStorage + /// is a container for a sequence of symbolic values. + SymbolicArrayStorage *arrayStorage; + + /// When this symbolic value is of an "Array" kind, this stores a memory + /// object that contains a SymbolicArrayStorage value. + SymbolicValueMemoryObject *array; } value; RepresentationKind representationKind : 8; @@ -348,6 +378,12 @@ class SymbolicValue { /// This value represents the address of, or into, a memory object. Address, + /// This represents an internal array storage. + ArrayStorage, + + /// This represents an array value. + Array, + /// These values are generally only seen internally to the system, external /// clients shouldn't have to deal with them. UninitMemory @@ -471,6 +507,32 @@ class SymbolicValue { /// Return just the memory object for an address value. SymbolicValueMemoryObject *getAddressValueMemoryObject() const; + /// Create a symbolic array storage containing \c elements. + static SymbolicValue + getSymbolicArrayStorage(ArrayRef elements, CanType elementType, + SymbolicValueAllocator &allocator); + + /// Create a symbolic array using the given symbolic array storage, which + /// contains the array elements. + static SymbolicValue getArray(Type arrayType, SymbolicValue arrayStorage, + SymbolicValueAllocator &allocator); + + /// Return the elements stored in this SymbolicValue of "ArrayStorage" kind. + ArrayRef getStoredElements(CanType &elementType) const; + + /// Return the symbolic value representing the internal storage of this array. + SymbolicValue getStorageOfArray() const; + + /// Return the symbolic value representing the address of the element of this + /// array at the given \c index. The return value is a derived address whose + /// base is the memory object \c value.array (which contains the array + /// storage) and whose accesspath is \c index. + SymbolicValue getAddressOfArrayElement(SymbolicValueAllocator &allocator, + unsigned index) const; + + /// Return the type of this array symbolic value. + Type getArrayType() const; + //===--------------------------------------------------------------------===// // Helpers @@ -545,7 +607,6 @@ struct SymbolicValueMemoryObject { SymbolicValueMemoryObject(const SymbolicValueMemoryObject &) = delete; void operator=(const SymbolicValueMemoryObject &) = delete; }; - } // end namespace swift #endif diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index ae821cf7ba1d3..039aa42ff78e6 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -135,6 +135,10 @@ struct SILDeclRef { /// routines have an ivar destroyer, which is emitted as /// .cxx_destruct. IVarDestroyer, + + /// References the wrapped value injection function used to initialize + /// the backing storage property from a wrapped value. + PropertyWrapperBackingInitializer, }; /// The ValueDecl or AbstractClosureExpr represented by this SILDeclRef. diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 6bce8980a23fb..6c3d34d322846 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -1317,14 +1317,18 @@ class UnaryInstructionWithTypeDependentOperandsBase /// arguments that are needed by DebugValueInst, DebugValueAddrInst, /// AllocStackInst, and AllocBoxInst. struct SILDebugVariable { + StringRef Name; + unsigned ArgNo : 16; + unsigned Constant : 1; + SILDebugVariable() : ArgNo(0), Constant(false) {} SILDebugVariable(bool Constant, uint16_t ArgNo) : ArgNo(ArgNo), Constant(Constant) {} SILDebugVariable(StringRef Name, bool Constant, unsigned ArgNo) : Name(Name), ArgNo(ArgNo), Constant(Constant) {} - StringRef Name; - unsigned ArgNo : 16; - unsigned Constant : 1; + bool operator==(const SILDebugVariable &V) { + return ArgNo == V.ArgNo && Constant == V.Constant && Name == V.Name; + } }; /// A DebugVariable where storage for the strings has been diff --git a/include/swift/SIL/SILLocation.h b/include/swift/SIL/SILLocation.h index 15a96a5b41bf2..bb1e990ccbe28 100644 --- a/include/swift/SIL/SILLocation.h +++ b/include/swift/SIL/SILLocation.h @@ -679,6 +679,7 @@ class MandatoryInlinedLocation : public SILLocation { : SILLocation(L, MandatoryInlinedKind) {} static MandatoryInlinedLocation getMandatoryInlinedLocation(SILLocation L); + static MandatoryInlinedLocation getAutoGeneratedLocation(); static MandatoryInlinedLocation getModuleLocation(unsigned Flags) { auto L = MandatoryInlinedLocation(); diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 55f1e8797f307..a30bb75029357 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -159,6 +159,19 @@ class SILType { } /// Returns the canonical AST type referenced by this SIL type. + /// + /// NOTE: + /// 1. The returned AST type may not be a proper formal type. + /// For example, it may contain a SILFunctionType instead of a + /// FunctionType. + /// 2. The returned type may not be the same as the original + /// unlowered type that produced this SILType (even after + /// canonicalization). If you need it, you must pass it separately. + /// For example, `AnyObject.Type` may get lowered to + /// `$@thick AnyObject.Type`, for which the AST type will be + /// `@thick AnyObject.Type`. + /// More generally, you cannot recover a formal type from + /// a lowered type. See docs/SIL.rst for more details. CanType getASTType() const { return CanType(value.getPointer()); } @@ -516,8 +529,6 @@ class SILType { /// Get the NativeObject type as a SILType. static SILType getNativeObjectType(const ASTContext &C); - /// Get the UnknownObject type as a SILType. - static SILType getUnknownObjectType(const ASTContext &C); /// Get the BridgeObject type as a SILType. static SILType getBridgeObjectType(const ASTContext &C); /// Get the RawPointer type as a SILType. diff --git a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h index 0103eb7e7192b..d0fabe87592be 100644 --- a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h @@ -332,6 +332,17 @@ class ConsumedArgToEpilogueReleaseMatcher { return completeList.getValue(); } + Optional> + getPartiallyPostDomReleaseSet(SILArgument *arg) const { + auto iter = ArgInstMap.find(arg); + if (iter == ArgInstMap.end()) + return None; + auto partialList = iter->second.getPartiallyPostDomReleases(); + if (!partialList) + return None; + return partialList; + } + ArrayRef getReleasesForArgument(SILValue value) const { auto *arg = dyn_cast(value); if (!arg) diff --git a/include/swift/SILOptimizer/Analysis/CallerAnalysis.h b/include/swift/SILOptimizer/Analysis/CallerAnalysis.h index 35ea773a3cb4b..b23570c2e49fa 100644 --- a/include/swift/SILOptimizer/Analysis/CallerAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/CallerAnalysis.h @@ -278,6 +278,10 @@ class CallerAnalysis::FunctionInfo { /// visibility of a protocol conformance or class. bool mayHaveIndirectCallers : 1; + /// Whether the function is sufficiently visible to be called by a different + /// module. + bool mayHaveExternalCallers : 1; + public: FunctionInfo(SILFunction *f); @@ -289,7 +293,8 @@ class CallerAnalysis::FunctionInfo { /// function (e.g. a specialized function) without needing to introduce a /// thunk since we can rewrite all of the callers to call the new function. bool foundAllCallers() const { - return hasOnlyCompleteDirectCallerSets() && !mayHaveIndirectCallers; + return hasOnlyCompleteDirectCallerSets() && !mayHaveIndirectCallers && + !mayHaveExternalCallers; } /// Returns true if this function has at least one direct caller. diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 2126032328982..f108e4604a133 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -315,6 +315,9 @@ PASS(SimplifyUnreachableContainingBlocks, "simplify-unreachable-containing-block "Utility pass. Removes all non-term insts from blocks with unreachable terms") PASS(SerializeSILPass, "serialize-sil", "Utility pass. Serializes the current SILModule") +PASS(NonInlinableFunctionSkippingChecker, "check-non-inlinable-function-skipping", + "Utility pass to ensure -experimental-skip-non-inlinable-function-bodies " + "skips everything it should") PASS(YieldOnceCheck, "yield-once-check", "Check correct usage of yields in yield-once coroutines") PASS(OSLogOptimization, "os-log-optimization", "Optimize os log calls") diff --git a/include/swift/Serialization/SerializationOptions.h b/include/swift/Serialization/SerializationOptions.h index 7cce7af751f74..ee8d1d6431160 100644 --- a/include/swift/Serialization/SerializationOptions.h +++ b/include/swift/Serialization/SerializationOptions.h @@ -29,6 +29,7 @@ namespace swift { const char *OutputPath = nullptr; const char *DocOutputPath = nullptr; + const char *SourceInfoOutputPath = nullptr; StringRef GroupInfoPath; StringRef ImportedHeader; diff --git a/include/swift/Strings.h b/include/swift/Strings.h index c7a357ce26583..506954fc39029 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -106,6 +106,9 @@ constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_RAWPOINTER = { constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER = {"Builtin.UnsafeValueBuffer"}; /// The name of the Builtin type for UnknownObject +/// +/// This no longer exists as an AST-accessible type, but it's still used for  +/// fields shaped like AnyObject when ObjC interop is enabled. constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_UNKNOWNOBJECT = { "Builtin.UnknownObject"}; /// The name of the Builtin type for Vector diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 5c33ef47cb8d1..bd2931a0ed20e 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -187,6 +187,11 @@ namespace swift { /// If set, dumps wall time taken to type check each expression to /// llvm::errs(). DebugTimeExpressions = 1 << 3, + + /// If set, the typechecker will skip typechecking non-inlinable function + /// bodies. Set this if you're trying to quickly emit a module or module + /// interface without a full compilation. + SkipNonInlinableFunctionBodies = 1 << 4, }; /// Once parsing and name-binding are complete, this walks the AST to resolve @@ -282,6 +287,7 @@ namespace swift { const SerializationOptions &opts, std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, + std::unique_ptr *moduleSourceInfoBuffer, const SILModule *M = nullptr); // SWIFT_ENABLE_TENSORFLOW diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h index 849e7c8a24cdd..e424bcef33423 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h @@ -72,20 +72,20 @@ SWIFT_REMOTE_MIRROR_LINKAGE void swift_reflection_destroyReflectionContext(SwiftReflectionContextRef Context); -/// Add reflection sections for a loaded Swift image. +/// DEPRECATED. Add reflection sections for a loaded Swift image. +/// +/// You probably want to use \c swift_reflection_addImage instead. SWIFT_REMOTE_MIRROR_LINKAGE void swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef, swift_reflection_info_t Info); -#if defined(__APPLE__) && defined(__MACH__) /// Add reflection information from a loaded Swift image. /// Returns true on success, false if the image's memory couldn't be read. SWIFT_REMOTE_MIRROR_LINKAGE int swift_reflection_addImage(SwiftReflectionContextRef ContextRef, swift_addr_t imageStart); -#endif /// Returns a boolean indicating if the isa mask was successfully /// read, in which case it is stored in the isaMask out parameter. diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h index c64ce70e5449a..36393c6c45d68 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h @@ -48,38 +48,23 @@ typedef struct swift_reflection_section { void *End; } swift_reflection_section_t; +typedef struct swift_reflection_section_pair { + swift_reflection_section_t section; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero +} swift_reflection_section_pair_t; + /// Represents the set of Swift reflection sections of an image. /// Not all sections may be present. +/// +/// DEPRECATED. New RemoteMirror clients should use +/// \c swift_reflection_addImage . typedef struct swift_reflection_info { - struct { - swift_reflection_section_t section; - swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero - } field; - - struct { - swift_reflection_section_t section; - swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero - } associated_types; - - struct { - swift_reflection_section_t section; - swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero - } builtin_types; - - struct { - swift_reflection_section_t section; - swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero - } capture; - - struct { - swift_reflection_section_t section; - swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero - } type_references; - - struct { - swift_reflection_section_t section; - swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero - } reflection_strings; + swift_reflection_section_pair_t field; + swift_reflection_section_pair_t associated_types; + swift_reflection_section_pair_t builtin_types; + swift_reflection_section_pair_t capture; + swift_reflection_section_pair_t type_references; + swift_reflection_section_pair_t reflection_strings; // Start address in local and remote address spaces. swift_reflection_ptr_t LocalStartAddress; diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 7419e60d3c469..363109c5964d6 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -24,9 +24,6 @@ namespace swift { class FileUnit; class ModuleDecl; -/// The current ABI version of Swift, as tapi labels it. -const uint8_t TAPI_SWIFT_ABI_VERSION = 5; - /// Options for controlling the exact set of symbols included in the TBD /// output. struct TBDGenOptions { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fdc4ec4691530..ad727fe8e51ff 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -580,8 +580,6 @@ ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts, BuiltinNativeObjectType(*this)), TheBridgeObjectType(new (*this, AllocationArena::Permanent) BuiltinBridgeObjectType(*this)), - TheUnknownObjectType(new (*this, AllocationArena::Permanent) - BuiltinUnknownObjectType(*this)), TheRawPointerType(new (*this, AllocationArena::Permanent) BuiltinRawPointerType(*this)), TheUnsafeValueBufferType(new (*this, AllocationArena::Permanent) @@ -2360,18 +2358,11 @@ TypeAliasType *TypeAliasType::get(TypeAliasDecl *typealias, Type parent, // Compute the recursive properties. // auto properties = underlying->getRecursiveProperties(); - auto storedProperties = properties; - if (parent) { + if (parent) properties |= parent->getRecursiveProperties(); - if (parent->hasTypeVariable()) - storedProperties |= RecursiveTypeProperties::HasTypeVariable; - } - for (auto substGP : substitutions.getReplacementTypes()) { + for (auto substGP : substitutions.getReplacementTypes()) properties |= substGP->getRecursiveProperties(); - if (substGP->hasTypeVariable()) - storedProperties |= RecursiveTypeProperties::HasTypeVariable; - } // Figure out which arena this type will go into. auto &ctx = underlying->getASTContext(); @@ -2393,7 +2384,7 @@ TypeAliasType *TypeAliasType::get(TypeAliasDecl *typealias, Type parent, genericSig ? 1 : 0); auto mem = ctx.Allocate(size, alignof(TypeAliasType), arena); auto result = new (mem) TypeAliasType(typealias, parent, substitutions, - underlying, storedProperties); + underlying, properties); types.InsertNode(result, insertPos); return result; } diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index ccf8229c398ad..ad194b5ee4a7f 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -190,9 +190,7 @@ Type ASTBuilder::createTypeAliasType(GenericTypeDecl *decl, Type parent) { auto *dc = aliasDecl->getDeclContext(); auto subs = parent->getContextSubstitutionMap(dc->getParentModule(), dc); - // FIXME: subst() should build the sugar for us - declaredType = declaredType.subst(subs); - return TypeAliasType::get(aliasDecl, parent, subs, declaredType); + return declaredType.subst(subs); } static SubstitutionMap @@ -323,9 +321,7 @@ Type ASTBuilder::createBoundGenericType(GenericTypeDecl *decl, if (!subMap) return Type(); - // FIXME: subst() should build the sugar for us - auto declaredType = aliasDecl->getDeclaredInterfaceType().subst(subMap); - return TypeAliasType::get(aliasDecl, parent, subMap, declaredType); + return aliasDecl->getDeclaredInterfaceType().subst(subMap); } Type ASTBuilder::createTupleType(ArrayRef eltTypes, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 33ce04a75f4f1..b710e6585e06a 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3414,7 +3414,6 @@ namespace { TRIVIAL_TYPE_PRINTER(BuiltinRawPointer, builtin_raw_pointer) TRIVIAL_TYPE_PRINTER(BuiltinNativeObject, builtin_native_object) TRIVIAL_TYPE_PRINTER(BuiltinBridgeObject, builtin_bridge_object) - TRIVIAL_TYPE_PRINTER(BuiltinUnknownObject, builtin_unknown_object) TRIVIAL_TYPE_PRINTER(BuiltinUnsafeValueBuffer, builtin_unsafe_value_buffer) TRIVIAL_TYPE_PRINTER(SILToken, sil_token) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 28de54122449f..f69b889aab113 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -155,6 +155,14 @@ std::string ASTMangler::mangleInitializerEntity(const VarDecl *var, return finalize(); } +std::string ASTMangler::mangleBackingInitializerEntity(const VarDecl *var, + SymbolKind SKind) { + beginMangling(); + appendBackingInitializerEntity(var); + appendSymbolKind(SKind); + return finalize(); +} + std::string ASTMangler::mangleNominalType(const NominalTypeDecl *decl) { beginMangling(); appendAnyGenericType(decl); @@ -841,8 +849,6 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) { return appendOperator("Bo"); case TypeKind::BuiltinBridgeObject: return appendOperator("Bb"); - case TypeKind::BuiltinUnknownObject: - return appendOperator("BO"); case TypeKind::BuiltinUnsafeValueBuffer: return appendOperator("BB"); case TypeKind::SILToken: @@ -861,10 +867,16 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) { // It's not possible to mangle the context of the builtin module. // For the DWARF output we want to mangle the type alias + context, // unless the type alias references a builtin type. + auto underlyingType = aliasTy->getSinglyDesugaredType(); TypeAliasDecl *decl = aliasTy->getDecl(); if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) { - return appendType(aliasTy->getSinglyDesugaredType(), - forDecl); + return appendType(underlyingType, forDecl); + } + + if (decl->getDeclaredInterfaceType() + .subst(aliasTy->getSubstitutionMap()).getPointer() + != aliasTy) { + return appendType(underlyingType, forDecl); } if (aliasTy->getSubstitutionMap()) { @@ -2400,6 +2412,11 @@ void ASTMangler::appendInitializerEntity(const VarDecl *var) { appendOperator("fi"); } +void ASTMangler::appendBackingInitializerEntity(const VarDecl *var) { + appendEntity(var, "vp", var->isStatic()); + appendOperator("fP"); +} + /// Is this declaration a method for mangling purposes? If so, we'll leave the /// Self type out of its mangling. static bool isMethodDecl(const Decl *decl) { diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 63a7381da0748..c6a12f27b6609 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3620,7 +3620,6 @@ class TypePrinter : public TypeVisitor { } ASTPRINTER_PRINT_BUILTINTYPE(BuiltinRawPointerType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinNativeObjectType) - ASTPRINTER_PRINT_BUILTINTYPE(BuiltinUnknownObjectType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinBridgeObjectType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinUnsafeValueBufferType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinIntegerLiteralType) diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 414d4ee2fbad3..41795ecb98ad3 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -31,6 +31,7 @@ #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" +#include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" #include "swift/Subsystems.h" #include "llvm/ADT/SmallBitVector.h" diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index b159130bfa2d7..d14d5b79bfb50 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -265,12 +265,8 @@ class Traversal : public ASTVisitorgetGenericParams() && - Walker.shouldWalkIntoGenericParams(); - if (WalkGenerics) { - visitGenericParamList(NTD->getGenericParams()); - } + bool WalkGenerics = visitGenericParamListIfNeeded(NTD); for (auto &Inherit : NTD->getInherited()) { if (doIt(Inherit)) @@ -329,11 +325,8 @@ class Traversal : public ASTVisitorgetGenericParams() && - Walker.shouldWalkIntoGenericParams(); - if (WalkGenerics) { - visitGenericParamList(SD->getGenericParams()); - } + bool WalkGenerics = visitGenericParamListIfNeeded(SD); + visit(SD->getIndices()); if (doIt(SD->getElementTypeLoc())) return true; @@ -364,14 +357,9 @@ class Traversal : public ASTVisitorgetGenericParams() && - Walker.shouldWalkIntoGenericParams() && + bool WalkGenerics = // accessor generics are visited from the storage decl - !isa(AFD); - - if (WalkGenerics) { - visitGenericParamList(AFD->getGenericParams()); - } + !isa(AFD) && visitGenericParamListIfNeeded(AFD); if (auto *PD = AFD->getImplicitSelfDecl(/*createIfNeeded=*/false)) visit(PD); @@ -415,15 +403,7 @@ class Traversal : public ASTVisitorgetTypeCheckedRawValueExpr()) { - if (auto newRawValueExpr = doIt(rawValueExpr)) - ED->setTypeCheckedRawValueExpr(newRawValueExpr); - else - return true; - } else if (auto *rawLiteralExpr = ED->getRawValueExpr()) { + if (auto *rawLiteralExpr = ED->getRawValueExpr()) { Expr *newRawExpr = doIt(rawLiteralExpr); if (auto newRawLiteralExpr = dyn_cast(newRawExpr)) ED->setRawValueExpr(newRawLiteralExpr); @@ -1382,6 +1362,18 @@ class Traversal : public ASTVisitorgetGenericParams()) { + visitGenericParamList(params); + return true; + } + } + return false; + } }; } // end anonymous namespace diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 48b6391c7d839..3b7221f1a9d01 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -23,6 +23,7 @@ // SWIFT_ENABLE_TENSORFLOW #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/Module.h" +#include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" // SWIFT_ENABLE_TENSORFLOW #include "swift/AST/ParameterList.h" diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index e137818554cd0..f3152d1c60bf2 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -81,8 +81,6 @@ Type swift::getBuiltinType(ASTContext &Context, StringRef Name) { return Context.TheRawPointerType; if (Name == "NativeObject") return Context.TheNativeObjectType; - if (Name == "UnknownObject") - return Context.TheUnknownObjectType; if (Name == "BridgeObject") return Context.TheBridgeObjectType; if (Name == "SILToken") @@ -2217,9 +2215,6 @@ StringRef BuiltinType::getTypeName(SmallVectorImpl &result, case BuiltinTypeKind::BuiltinNativeObject: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_NATIVEOBJECT); break; - case BuiltinTypeKind::BuiltinUnknownObject: - printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_UNKNOWNOBJECT); - break; case BuiltinTypeKind::BuiltinBridgeObject: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_BRIDGEOBJECT); break; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index defff427b9757..1d8755c623e40 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -480,18 +480,26 @@ SourceRange Decl::getSourceRangeIncludingAttrs() const { return Range; } -SourceLoc Decl::getLoc() const { +SourceLoc Decl::getLocFromSource() const { switch (getKind()) { #define DECL(ID, X) \ -static_assert(sizeof(checkSourceLocType(&ID##Decl::getLoc)) == 1, \ - #ID "Decl is missing getLoc()"); \ -case DeclKind::ID: return cast(this)->getLoc(); +static_assert(sizeof(checkSourceLocType(&ID##Decl::getLocFromSource)) == 1, \ + #ID "Decl is missing getLocFromSource()"); \ +case DeclKind::ID: return cast(this)->getLocFromSource(); #include "swift/AST/DeclNodes.def" } llvm_unreachable("Unknown decl kind"); } +SourceLoc Decl::getLoc() const { +#define DECL(ID, X) \ +static_assert(sizeof(checkSourceLocType(&ID##Decl::getLoc)) == 2, \ + #ID "Decl is re-defining getLoc()"); +#include "swift/AST/DeclNodes.def" + return getLocFromSource(); +} + Expr *AbstractFunctionDecl::getSingleExpressionBody() const { assert(hasSingleExpressionBody() && "Not a single-expression body"); auto braceStmt = getBody(); @@ -1086,9 +1094,25 @@ ExtensionDecl::takeConformanceLoaderSlow() { } NominalTypeDecl *ExtensionDecl::getExtendedNominal() const { + assert((hasBeenBound() || canNeverBeBound()) && + "Extension must have already been bound (by bindExtensions)"); + return ExtendedNominal.getPointer(); +} + +NominalTypeDecl *ExtensionDecl::computeExtendedNominal() const { ASTContext &ctx = getASTContext(); - return evaluateOrDefault(ctx.evaluator, - ExtendedNominalRequest{const_cast(this)}, nullptr); + return evaluateOrDefault( + ctx.evaluator, ExtendedNominalRequest{const_cast(this)}, + nullptr); +} + +bool ExtensionDecl::canNeverBeBound() const { + // \c bindExtensions() only looks at valid parents for extensions. + return !hasValidParent(); +} + +bool ExtensionDecl::hasValidParent() const { + return getDeclContext()->canBeParentOfExtension(); } bool ExtensionDecl::isConstrainedExtension() const { @@ -3258,13 +3282,10 @@ Type TypeDecl::getDeclaredInterfaceType() const { } Type interfaceType = getInterfaceType(); - if (interfaceType.isNull() || interfaceType->is()) - return interfaceType; - - if (isa(this)) - return interfaceType; + if (!interfaceType) + return ErrorType::get(getASTContext()); - return interfaceType->castTo()->getInstanceType(); + return interfaceType->getMetatypeInstanceType(); } int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) { @@ -3628,15 +3649,16 @@ void TypeAliasDecl::computeType() { Type parent; auto parentDC = getDeclContext(); if (parentDC->isTypeContext()) - parent = parentDC->getDeclaredInterfaceType(); + parent = parentDC->getSelfInterfaceType(); auto sugaredType = TypeAliasType::get(this, parent, subs, getUnderlyingType()); setInterfaceType(MetatypeType::get(sugaredType, ctx)); } Type TypeAliasDecl::getUnderlyingType() const { - return evaluateOrDefault(getASTContext().evaluator, + auto &ctx = getASTContext(); + return evaluateOrDefault(ctx.evaluator, UnderlyingTypeRequest{const_cast(this)}, - Type()); + ErrorType::get(ctx)); } void TypeAliasDecl::setUnderlyingType(Type underlying) { @@ -3666,10 +3688,11 @@ UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { } Type TypeAliasDecl::getStructuralType() const { - auto &context = getASTContext(); + auto &ctx = getASTContext(); return evaluateOrDefault( - context.evaluator, - StructuralTypeRequest{const_cast(this)}, Type()); + ctx.evaluator, + StructuralTypeRequest{const_cast(this)}, + ErrorType::get(ctx)); } Type AbstractTypeParamDecl::getSuperclass() const { @@ -5567,7 +5590,8 @@ bool VarDecl::hasAttachedPropertyWrapper() const { return !getAttachedPropertyWrappers().empty(); } -/// Whether all of the attached property wrappers have an init(initialValue:) initializer. +/// Whether all of the attached property wrappers have an init(wrappedValue:) +/// initializer. bool VarDecl::allAttachedPropertyWrappersHaveInitialValueInit() const { for (unsigned i : indices(getAttachedPropertyWrappers())) { if (!getAttachedPropertyWrapperTypeInfo(i).wrappedValueInit) @@ -7558,6 +7582,28 @@ PrecedenceGroupDecl::PrecedenceGroupDecl(DeclContext *dc, lowerThan.size() * sizeof(Relation)); } +llvm::Expected LookupPrecedenceGroupRequest::evaluate( + Evaluator &eval, PrecedenceGroupDescriptor descriptor) const { + auto *dc = descriptor.dc; + PrecedenceGroupDecl *group = nullptr; + if (auto sf = dc->getParentSourceFile()) { + bool cascading = dc->isCascadingContextForLookup(false); + group = sf->lookupPrecedenceGroup(descriptor.ident, cascading, + descriptor.nameLoc); + } else { + group = dc->getParentModule()->lookupPrecedenceGroup(descriptor.ident, + descriptor.nameLoc); + } + return group; +} + +PrecedenceGroupDecl *InfixOperatorDecl::getPrecedenceGroup() const { + return evaluateOrDefault( + getASTContext().evaluator, + OperatorPrecedenceGroupRequest{const_cast(this)}, + nullptr); +} + bool FuncDecl::isDeferBody() const { return getName() == getASTContext().getIdentifier("$defer"); } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 33f0547426792..f0c48ce09e215 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -231,6 +231,17 @@ Decl *DeclContext::getInnermostDeclarationDeclContext() { return nullptr; } +DeclContext *DeclContext::getInnermostSkippedFunctionContext() { + auto dc = this; + do { + if (auto afd = dyn_cast(dc)) + if (afd->isBodySkipped()) + return afd; + } while ((dc = dc->getParent())); + + return nullptr; +} + DeclContext *DeclContext::getParentForLookup() const { if (isa(this) || isa(this)) { // If we are inside a protocol or an extension, skip directly @@ -478,6 +489,10 @@ bool DeclContext::mayContainMembersAccessedByDynamicLookup() const { return false; } +bool DeclContext::canBeParentOfExtension() const { + return isa(this); +} + bool DeclContext::walkContext(ASTWalker &Walker) { switch (getContextKind()) { case DeclContextKind::Module: diff --git a/lib/AST/DiagnosticConsumer.cpp b/lib/AST/DiagnosticConsumer.cpp index f341c16356bf0..122e322c3fa0d 100644 --- a/lib/AST/DiagnosticConsumer.cpp +++ b/lib/AST/DiagnosticConsumer.cpp @@ -19,6 +19,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/Defer.h" +#include "swift/Basic/Range.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 26209736a7780..9c91a3e80ab5e 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -398,7 +398,7 @@ static bool shouldShowAKA(Type type, StringRef typeName) { return false; // Don't show generic type parameters. - if (type->hasTypeParameter()) + if (type->getCanonicalType()->hasTypeParameter()) return false; // Only show 'aka' if there's a typealias involved; other kinds of sugar diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 1c0a3ddaef27c..4f2b3c816a16c 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -3784,16 +3784,17 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype( return pa; } -static Type getStructuralType(TypeDecl *typeDecl) { +static Type getStructuralType(TypeDecl *typeDecl, bool keepSugar) { if (auto typealias = dyn_cast(typeDecl)) { - // When we're computing requirement signatures, the structural type - // suffices. Otherwise we'll potentially try to validate incomplete - // requirements. - auto *proto = dyn_cast_or_null( - typealias->getDeclContext()->getAsDecl()); - if (proto && proto->isComputingRequirementSignature()) - return typealias->getStructuralType(); - return typealias->getUnderlyingType(); + if (typealias->getUnderlyingTypeRepr() != nullptr) { + auto type = typealias->getStructuralType(); + if (!keepSugar) + if (auto *aliasTy = cast(type.getPointer())) + return aliasTy->getSinglyDesugaredType(); + return type; + } + if (!keepSugar) + return typealias->getUnderlyingType(); } return typeDecl->getDeclaredInterfaceType(); @@ -3804,43 +3805,33 @@ static Type substituteConcreteType(GenericSignatureBuilder &builder, TypeDecl *concreteDecl) { assert(concreteDecl); - auto *proto = concreteDecl->getDeclContext()->getSelfProtocolDecl(); + auto *dc = concreteDecl->getDeclContext(); + auto *proto = dc->getSelfProtocolDecl(); // Form an unsubstituted type referring to the given type declaration, // for use in an inferred same-type requirement. - auto type = getStructuralType(concreteDecl); - if (!type) - return Type(); + auto type = getStructuralType(concreteDecl, /*keepSugar=*/true); - Type parentType; SubstitutionMap subMap; if (proto) { // Substitute in the type of the current PotentialArchetype in // place of 'Self' here. - parentType = basePA->getDependentType(builder.getGenericParams()); + auto parentType = basePA->getDependentType(builder.getGenericParams()); subMap = SubstitutionMap::getProtocolSubstitutions( proto, parentType, ProtocolConformanceRef(proto)); - - type = type.subst(subMap); } else { // Substitute in the superclass type. auto parentPA = basePA->getEquivalenceClassIfPresent(); - parentType = + auto parentType = parentPA->concreteType ? parentPA->concreteType : parentPA->superclass; auto parentDecl = parentType->getAnyNominal(); - subMap = parentType->getMemberSubstitutionMap(parentDecl->getParentModule(), - concreteDecl); - type = type.subst(subMap); - } - - // If we had a typealias, form a sugared type. - if (auto *typealias = dyn_cast(concreteDecl)) { - type = TypeAliasType::get(typealias, parentType, subMap, type); + subMap = parentType->getContextSubstitutionMap( + parentDecl->getParentModule(), dc); } - return type; + return type.subst(subMap); }; ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass( @@ -4215,11 +4206,8 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement( // An inferred same-type requirement between the two type declarations // within this protocol or a protocol it inherits. auto addInferredSameTypeReq = [&](TypeDecl *first, TypeDecl *second) { - Type firstType = getStructuralType(first); - if (!firstType) return; - - Type secondType = getStructuralType(second); - if (!secondType) return; + Type firstType = getStructuralType(first, /*keepSugar=*/false); + Type secondType = getStructuralType(second, /*keepSugar=*/false); auto inferredSameTypeSource = FloatingRequirementSource::viaProtocolRequirement( @@ -7707,7 +7695,7 @@ llvm::Expected InferredGenericSignatureRequest::evaluate( Evaluator &evaluator, ModuleDecl *parentModule, GenericSignature *parentSig, - SmallVector gpLists, + GenericParamList *gpl, SmallVector addedRequirements, SmallVector inferenceSources, bool allowConcreteGenericParams) const { @@ -7718,6 +7706,19 @@ InferredGenericSignatureRequest::evaluate( // from that context. builder.addGenericSignature(parentSig); + // Type check the generic parameters, treating all generic type + // parameters as dependent, unresolved. + SmallVector gpLists; + if (gpl->getOuterParameters() && !parentSig) { + for (auto *outerParams = gpl; + outerParams != nullptr; + outerParams = outerParams->getOuterParameters()) { + gpLists.push_back(outerParams); + } + } else { + gpLists.push_back(gpl); + } + // The generic parameter lists MUST appear from innermost to outermost. // We walk them backwards to order outer requirements before // inner requirements. diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index f3b0ae29a675c..a96fc809be283 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -193,6 +193,8 @@ static void recordShadowedDeclsAfterSignatureMatch( for (unsigned firstIdx : indices(decls)) { auto firstDecl = decls[firstIdx]; auto firstModule = firstDecl->getModuleContext(); + bool firstTopLevel = firstDecl->getDeclContext()->isModuleScopeContext(); + auto name = firstDecl->getBaseName(); auto isShadowed = [&](ArrayRef paths) { @@ -219,6 +221,29 @@ static void recordShadowedDeclsAfterSignatureMatch( // Determine whether one module takes precedence over another. auto secondDecl = decls[secondIdx]; auto secondModule = secondDecl->getModuleContext(); + bool secondTopLevel = secondDecl->getDeclContext()->isModuleScopeContext(); + + // For member types, we skip most of the below rules. Instead, we allow + // member types defined in a subclass to shadow member types defined in + // a superclass. + if (isa(firstDecl) && + isa(secondDecl) && + !firstTopLevel && + !secondTopLevel) { + auto *firstClass = firstDecl->getDeclContext()->getSelfClassDecl(); + auto *secondClass = secondDecl->getDeclContext()->getSelfClassDecl(); + if (firstClass && secondClass && firstClass != secondClass) { + if (firstClass->isSuperclassOf(secondClass)) { + shadowed.insert(firstDecl); + continue; + } else if (secondClass->isSuperclassOf(firstClass)) { + shadowed.insert(secondDecl); + continue; + } + } + + continue; + } // Top-level type declarations in a module shadow other declarations // visible through the module's imports. @@ -226,8 +251,7 @@ static void recordShadowedDeclsAfterSignatureMatch( // [Backward compatibility] Note that members of types have the same // shadowing check, but we do it after dropping unavailable members. if (firstModule != secondModule && - firstDecl->getDeclContext()->isModuleScopeContext() && - secondDecl->getDeclContext()->isModuleScopeContext()) { + firstTopLevel && secondTopLevel) { auto firstPaths = imports.getAllAccessPathsNotShadowedBy( firstModule, secondModule, dc); auto secondPaths = imports.getAllAccessPathsNotShadowedBy( @@ -304,8 +328,7 @@ static void recordShadowedDeclsAfterSignatureMatch( // shadowing check is performed after unavailable candidates have // already been dropped. if (firstModule != secondModule && - !firstDecl->getDeclContext()->isModuleScopeContext() && - !secondDecl->getDeclContext()->isModuleScopeContext()) { + !firstTopLevel && !secondTopLevel) { auto firstPaths = imports.getAllAccessPathsNotShadowedBy( firstModule, secondModule, dc); auto secondPaths = imports.getAllAccessPathsNotShadowedBy( @@ -478,9 +501,6 @@ static void recordShadowedDecls(ArrayRef decls, // type. This is layering a partial fix upon a total hack. if (auto asd = dyn_cast(decl)) signature = asd->getOverloadSignatureType(); - } else if (decl->getDeclContext()->isTypeContext()) { - // Do not apply shadowing rules for member types. - continue; } // Record this declaration based on its signature. diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index dce1e75fa83ab..b073e42ddfcef 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -74,17 +74,19 @@ Optional ExtendedNominalRequest::getCachedResult() const { // Note: if we fail to compute any nominal declaration, it's considered // a cache miss. This allows us to recompute the extended nominal types // during extension binding. + // This recomputation is also what allows you to extend types defined inside + // other extensions, regardless of source file order. See \c bindExtensions(), + // which uses a worklist algorithm that attempts to bind everything until + // fixed point. auto ext = std::get<0>(getStorage()); - if (ext->ExtendedNominal) - return ext->ExtendedNominal; - - return None; + if (!ext->hasBeenBound() || !ext->getExtendedNominal()) + return None; + return ext->getExtendedNominal(); } void ExtendedNominalRequest::cacheResult(NominalTypeDecl *value) const { auto ext = std::get<0>(getStorage()); - if (value) - ext->ExtendedNominal = value; + ext->setExtendedNominal(value); } //----------------------------------------------------------------------------// @@ -127,6 +129,25 @@ void GenericParamListRequest::cacheResult(GenericParamList *params) const { } +//----------------------------------------------------------------------------// +// LookupPrecedenceGroupRequest computation. +//----------------------------------------------------------------------------// + +SourceLoc LookupPrecedenceGroupRequest::getNearestLoc() const { + auto &desc = std::get<0>(getStorage()); + return desc.getLoc(); +} + +SourceLoc PrecedenceGroupDescriptor::getLoc() const { + return nameLoc; +} + +void swift::simple_display(llvm::raw_ostream &out, + const PrecedenceGroupDescriptor &desc) { + out << "precedence group " << desc.ident << " at "; + desc.nameLoc.print(out, desc.dc->getASTContext().SourceMgr); +} + // Define request evaluation functions for each of the name lookup requests. static AbstractRequestFunction *nameLookupRequestFunctions[] = { #define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \ diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index 81a2ad473baa5..447ba7fe0abbd 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -16,10 +16,11 @@ #include "swift/AST/Pattern.h" #include "swift/AST/ASTContext.h" -#include "swift/AST/Expr.h" #include "swift/AST/ASTWalker.h" +#include "swift/AST/Expr.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/TypeLoc.h" +#include "swift/AST/TypeRepr.h" #include "swift/Basic/Statistic.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/AST/PrettyStackTrace.cpp b/lib/AST/PrettyStackTrace.cpp index 0b07e1721d787..893a83502d1fd 100644 --- a/lib/AST/PrettyStackTrace.cpp +++ b/lib/AST/PrettyStackTrace.cpp @@ -24,6 +24,7 @@ #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Stmt.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/TypeRepr.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 9f7ffddc298e0..4c2bb30cb7d4c 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -170,7 +170,6 @@ bool CanType::isReferenceTypeImpl(CanType type, GenericSignature *sig, llvm_unreachable("sugared canonical type?"); // These types are always class references. - case TypeKind::BuiltinUnknownObject: case TypeKind::BuiltinNativeObject: case TypeKind::BuiltinBridgeObject: case TypeKind::Class: @@ -625,6 +624,28 @@ Type TypeBase::getAnyPointerElementType(PointerTypeKind &PTK) { return Type(); } +Type TypeBase::wrapInPointer(PointerTypeKind kind) { + ASTContext &ctx = getASTContext(); + NominalTypeDecl *pointerDecl = ([&ctx, kind] { + switch (kind) { + case PTK_UnsafeMutableRawPointer: + case PTK_UnsafeRawPointer: + llvm_unreachable("these pointer types don't take arguments"); + case PTK_UnsafePointer: + return ctx.getUnsafePointerDecl(); + case PTK_UnsafeMutablePointer: + return ctx.getUnsafeMutablePointerDecl(); + case PTK_AutoreleasingUnsafeMutablePointer: + return ctx.getAutoreleasingUnsafeMutablePointerDecl(); + } + llvm_unreachable("bad kind"); + }()); + + assert(pointerDecl); + return BoundGenericType::get(pointerDecl, /*parent*/nullptr, Type(this)); +} + + Type TypeBase::lookThroughAllOptionalTypes() { Type type(this); while (auto objType = type->getOptionalObjectType()) @@ -3261,7 +3282,23 @@ static Type substType(Type derivedType, boxTy->getLayout(), newSubMap); } - + + // Special-case TypeAliasType; we need to substitute conformances. + if (auto aliasTy = dyn_cast(type)) { + Type parentTy; + if (auto origParentTy = aliasTy->getParent()) + parentTy = substType(origParentTy, + substitutions, lookupConformances, options); + auto underlyingTy = substType(aliasTy->getSinglyDesugaredType(), + substitutions, lookupConformances, options); + if (parentTy && parentTy->isExistentialType()) + return underlyingTy; + auto subMap = aliasTy->getSubstitutionMap() + .subst(substitutions, lookupConformances, options); + return Type(TypeAliasType::get(aliasTy->getDecl(), parentTy, + subMap, underlyingTy)); + } + // We only substitute for substitutable types and dependent member types. // For dependent member types, we may need to look up the member if the @@ -3963,33 +4000,29 @@ case TypeKind::Id: Type oldParentType = alias->getParent(); Type newParentType; - if (oldParentType && !oldParentType->hasTypeParameter() && - !oldParentType->hasArchetype()) { + if (oldParentType) { newParentType = oldParentType.transformRec(fn); if (!newParentType) return newUnderlyingType; } auto subMap = alias->getSubstitutionMap(); for (Type oldReplacementType : subMap.getReplacementTypes()) { - if (oldReplacementType->hasTypeParameter() || - oldReplacementType->hasArchetype()) - return newUnderlyingType; - Type newReplacementType = oldReplacementType.transformRec(fn); if (!newReplacementType) return newUnderlyingType; // If anything changed with the replacement type, we lose the sugar. // FIXME: This is really unfortunate. - if (!newReplacementType->isEqual(oldReplacementType)) + if (newReplacementType.getPointer() != oldReplacementType.getPointer()) return newUnderlyingType; } - if (oldUnderlyingType.getPointer() == newUnderlyingType.getPointer()) + if (oldParentType.getPointer() == newParentType.getPointer() && + oldUnderlyingType.getPointer() == newUnderlyingType.getPointer()) return *this; return TypeAliasType::get(alias->getDecl(), newParentType, subMap, - newUnderlyingType); + newUnderlyingType); } case TypeKind::Paren: { @@ -4336,9 +4369,6 @@ ReferenceCounting TypeBase::getReferenceCounting() { case TypeKind::BuiltinBridgeObject: return ReferenceCounting::Bridge; - case TypeKind::BuiltinUnknownObject: - return ReferenceCounting::Unknown; - case TypeKind::Class: return getClassReferenceCounting(cast(type)->getDecl()); case TypeKind::BoundGenericClass: diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 7c9bf58563028..1925d4c2f88c5 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -576,11 +576,6 @@ void swift::simple_display( out << propertyWrapper.valueVar->printRef(); else out << "null"; - out << ", "; - if (propertyWrapper.wrappedValueInit) - out << propertyWrapper.wrappedValueInit->printRef(); - else - out << "null"; out << " }"; } @@ -844,7 +839,7 @@ void GenericSignatureRequest::cacheResult(GenericSignature *value) const { } //----------------------------------------------------------------------------// -// GenericSignatureRequest computation. +// InferredGenericSignatureRequest computation. //----------------------------------------------------------------------------// void InferredGenericSignatureRequest::noteCycleStep(DiagnosticEngine &d) const { diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index bf4ef9ee6b19b..a2657603e6f43 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -89,6 +89,7 @@ bool file_types::isTextual(ID Id) { case file_types::TY_RawSIB: case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: + case file_types::TY_SwiftSourceInfoFile: case file_types::TY_LLVM_BC: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: @@ -128,6 +129,7 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_RawSIB: case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: + case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: @@ -169,6 +171,7 @@ bool file_types::isPartOfSwiftCompilation(ID Id) { case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_SwiftSourceInfoFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index ad94f4bcc2b28..c42d8616af952 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -563,33 +563,9 @@ bool importer::isNSNotificationGlobal(const clang::NamedDecl *decl) { } bool importer::hasNativeSwiftDecl(const clang::Decl *decl) { - for (auto annotation : decl->specific_attrs()) { - if (annotation->getAnnotation() == SWIFT_NATIVE_ANNOTATION_STRING) { + if (auto *attr = decl->getAttr()) + if (attr->getGeneratedDeclaration() && attr->getLanguage() == "Swift") return true; - } - } - - if (auto *category = dyn_cast(decl)) { - clang::SourceLocation categoryNameLoc = category->getCategoryNameLoc(); - if (categoryNameLoc.isMacroID()) { - // Climb up to the top-most macro invocation. - clang::ASTContext &clangCtx = category->getASTContext(); - clang::SourceManager &SM = clangCtx.getSourceManager(); - - clang::SourceLocation macroCaller = - SM.getImmediateMacroCallerLoc(categoryNameLoc); - while (macroCaller.isMacroID()) { - categoryNameLoc = macroCaller; - macroCaller = SM.getImmediateMacroCallerLoc(categoryNameLoc); - } - - StringRef macroName = clang::Lexer::getImmediateMacroName( - categoryNameLoc, SM, clangCtx.getLangOpts()); - if (macroName == "SWIFT_EXTENSION") - return true; - } - } - return false; } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index d005364439c03..2509e7ce5bbdd 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -513,19 +513,6 @@ getNormalInvocationArguments(std::vector &invocationArgStrs, if (!triple.isOSDarwin()) invocationArgStrs.insert(invocationArgStrs.end(), {"-fobjc-runtime=ios-7.0"}); - - // Define macros that Swift bridging headers use. - invocationArgStrs.insert(invocationArgStrs.end(), { - "-DSWIFT_CLASS_EXTRA=__attribute__((__annotate__(" - "\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))", - "-DSWIFT_PROTOCOL_EXTRA=__attribute__((__annotate__(" - "\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))", - "-DSWIFT_EXTENSION_EXTRA=__attribute__((__annotate__(" - "\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))", - "-DSWIFT_ENUM_EXTRA=__attribute__((__annotate__(" - "\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))", - }); - } else { bool EnableCXXInterop = LangOpts.EnableCXXInterop; invocationArgStrs.insert(invocationArgStrs.end(), @@ -569,6 +556,10 @@ getNormalInvocationArguments(std::vector &invocationArgStrs, // Request new APIs from UIKit. "-DSWIFT_SDK_OVERLAY_UIKIT_EPOCH=2", + + // Backwards compatibility for headers that were checking this instead of + // '__swift__'. + "-DSWIFT_CLASS_EXTRA=", }); // Get the version of this compiler and pass it to C/Objective-C diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 7d37e91efaac8..1bf0e232b60b7 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3730,7 +3730,7 @@ namespace { } else { // Import the function type. If we have parameters, make sure their // names get into the resulting function type. - importedType = Impl.importFunctionType( + importedType = Impl.importFunctionParamsAndReturnType( dc, decl, {decl->param_begin(), decl->param_size()}, decl->isVariadic(), isInSystemModule(dc), name, bodyParams); @@ -4294,10 +4294,11 @@ namespace { prop->getSetterMethodDecl() != decl) return nullptr; importedType = - Impl.importAccessorMethodType(dc, prop, decl, isInSystemModule(dc), - importedName, &bodyParams); + Impl.importAccessorParamsAndReturnType(dc, prop, decl, + isInSystemModule(dc), + importedName, &bodyParams); } else { - importedType = Impl.importMethodType( + importedType = Impl.importMethodParamsAndReturnType( dc, decl, decl->parameters(), decl->isVariadic(), isInSystemModule(dc), &bodyParams, importedName, errorConvention, kind); @@ -4702,9 +4703,6 @@ namespace { /*TrailingWhere=*/nullptr); result->computeType(); - // FIXME: Kind of awkward that we have to do this here - result->getGenericParams()->getParams()[0]->setDepth(0); - addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier())); if (declaredNative) @@ -6258,7 +6256,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( // Import the type that this method will have. Optional errorConvention; ParameterList *bodyParams; - auto importedType = Impl.importMethodType( + auto importedType = Impl.importMethodParamsAndReturnType( dc, objcMethod, args, variadic, isInSystemModule(dc), &bodyParams, importedName, errorConvention, SpecialMethodKind::Constructor); if (!importedType) diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 4d7dc3581fe34..d573154117c16 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -25,8 +25,8 @@ #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" -#include "swift/AST/Types.h" #include "swift/AST/TypeRepr.h" +#include "swift/AST/Types.h" #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" @@ -1728,13 +1728,14 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } /// Returns true if it is expected that the macro is ignored. -static bool shouldIgnoreMacro(StringRef name, const clang::MacroInfo *macro) { +static bool shouldIgnoreMacro(StringRef name, const clang::MacroInfo *macro, + clang::Preprocessor &PP) { // Ignore include guards. Try not to ignore definitions of useful constants, // which may end up looking like include guards. if (macro->isUsedForHeaderGuard() && macro->getNumTokens() == 1) { auto tok = macro->tokens()[0]; - if (tok.isLiteral() - && StringRef(tok.getLiteralData(), tok.getLength()) == "1") + if (tok.is(clang::tok::numeric_constant) && tok.getLength() == 1 && + PP.getSpellingOfSingleCharacterNumericConstant(tok) == '1') return true; } @@ -1760,14 +1761,15 @@ static bool shouldIgnoreMacro(StringRef name, const clang::MacroInfo *macro) { bool ClangImporter::shouldIgnoreMacro(StringRef Name, const clang::MacroInfo *Macro) { - return ::shouldIgnoreMacro(Name, Macro); + return ::shouldIgnoreMacro(Name, Macro, Impl.getClangPreprocessor()); } Identifier NameImporter::importMacroName(const clang::IdentifierInfo *clangIdentifier, const clang::MacroInfo *macro) { // If we're supposed to ignore this macro, return an empty identifier. - if (::shouldIgnoreMacro(clangIdentifier->getName(), macro)) + if (::shouldIgnoreMacro(clangIdentifier->getName(), macro, + getClangPreprocessor())) return Identifier(); // No transformation is applied to the name. diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index a3feabe58fc2e..6cb9639f8d3a2 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -75,13 +75,16 @@ namespace { /// 'Bool'. Boolean, + /// The source type is 'NSUInteger'. + NSUInteger, + + /// The source type is 'va_list'. + VAList, + /// The source type is an Objective-C class type bridged to a Swift /// type. ObjCBridged, - /// The source type is 'NSUInteger'. - NSUInteger, - /// The source type is an Objective-C object pointer type. ObjCPointer, @@ -96,11 +99,6 @@ namespace { /// The source type is any other pointer type. OtherPointer, - - /// The source type created a new Swift type, using swift_newtype, of an - /// original underlying CFPointer. This distinction is necessary to - /// trigger audit-checking. - SwiftNewtypeFromCFPointer, }; ImportHintKind Kind; @@ -138,7 +136,7 @@ namespace { case ImportHint::ObjCPointer: case ImportHint::CFunctionPointer: case ImportHint::OtherPointer: - case ImportHint::SwiftNewtypeFromCFPointer: + case ImportHint::VAList: return true; } @@ -404,28 +402,35 @@ namespace { }; } + PointerTypeKind pointerKind; if (quals.hasConst()) { - return {Impl.getNamedSwiftTypeSpecialization(Impl.getStdlibModule(), - "UnsafePointer", - pointeeType), - ImportHint::OtherPointer}; - } + pointerKind = PTK_UnsafePointer; + } else { + switch (quals.getObjCLifetime()) { + case clang::Qualifiers::OCL_Autoreleasing: + case clang::Qualifiers::OCL_ExplicitNone: + // Mutable pointers with __autoreleasing or __unsafe_unretained + // ownership map to AutoreleasingUnsafeMutablePointer. + pointerKind = PTK_AutoreleasingUnsafeMutablePointer; + + // FIXME: We have tests using a non-Apple stdlib that nevertheless + // exercise ObjC interop. Fail softly for those tests. + if (!Impl.SwiftContext.getAutoreleasingUnsafeMutablePointerDecl()) + return Type(); + break; - // Mutable pointers with __autoreleasing or __unsafe_unretained - // ownership map to AutoreleasingUnsafeMutablePointer. - if (quals.getObjCLifetime() == clang::Qualifiers::OCL_Autoreleasing || - quals.getObjCLifetime() == clang::Qualifiers::OCL_ExplicitNone) { - return { - Impl.getNamedSwiftTypeSpecialization( - Impl.getStdlibModule(), "AutoreleasingUnsafeMutablePointer", - pointeeType), - ImportHint::OtherPointer}; + case clang::Qualifiers::OCL_Weak: + // FIXME: We should refuse to import this. + LLVM_FALLTHROUGH; + + case clang::Qualifiers::OCL_None: + case clang::Qualifiers::OCL_Strong: + // All other mutable pointers map to UnsafeMutablePointer. + pointerKind = PTK_UnsafeMutablePointer; + } } - // All other mutable pointers map to UnsafeMutablePointer. - return {Impl.getNamedSwiftTypeSpecialization(Impl.getStdlibModule(), - "UnsafeMutablePointer", - pointeeType), + return {pointeeType->wrapInPointer(pointerKind), ImportHint::OtherPointer}; } @@ -641,10 +646,6 @@ namespace { Type mappedType = decl->getDeclaredInterfaceType(); if (getSwiftNewtypeAttr(type->getDecl(), Impl.CurrentVersion)) { - if (isCFTypeDecl(type->getDecl())) { - return {mappedType, ImportHint::SwiftNewtypeFromCFPointer}; - } - auto underlying = Visit(type->getDecl()->getUnderlyingType()); switch (underlying.Hint) { case ImportHint::None: @@ -654,7 +655,7 @@ namespace { case ImportHint::ObjCPointer: case ImportHint::CFunctionPointer: case ImportHint::OtherPointer: - case ImportHint::SwiftNewtypeFromCFPointer: + case ImportHint::VAList: return {mappedType, underlying.Hint}; case ImportHint::Boolean: @@ -684,6 +685,10 @@ namespace { break; } + static const llvm::StringLiteral vaListNames[] = { + "va_list", "__gnuc_va_list", "__va_list" + }; + ImportHint hint = ImportHint::None; if (type->getDecl()->getName() == "BOOL") { hint = ImportHint::Boolean; @@ -692,6 +697,9 @@ namespace { hint = ImportHint::Boolean; } else if (type->getDecl()->getName() == "NSUInteger") { hint = ImportHint::NSUInteger; + } else if (llvm::is_contained(vaListNames, + type->getDecl()->getName())) { + hint = ImportHint::VAList; } else if (isImportedCFPointer(type->desugar(), mappedType)) { hint = ImportHint::CFPointer; } else if (mappedType->isAnyExistentialType()) { // id, Class @@ -770,8 +778,11 @@ namespace { ImportResult VisitDecayedType(const clang::DecayedType *type) { clang::ASTContext &clangCtx = Impl.getClangASTContext(); if (clangCtx.hasSameType(type->getOriginalType(), - clangCtx.getBuiltinVaListType())) - return Impl.getNamedSwiftType(Impl.getStdlibModule(), "CVaListPointer"); + clangCtx.getBuiltinVaListType())) { + return {Impl.getNamedSwiftType(Impl.getStdlibModule(), + "CVaListPointer"), + ImportHint::VAList}; + } return Visit(type->desugar()); } @@ -870,20 +881,23 @@ namespace { unsigned typeParamCount = imported->getGenericParams()->size(); auto typeArgs = type->getObjectType()->getTypeArgs(); assert(typeArgs.empty() || typeArgs.size() == typeParamCount); - llvm::SmallVector importedTypeArgs; - for (unsigned i = 0; i < typeParamCount; i++) { - Type importedTypeArg; - auto typeParam = imported->getGenericParams()->getParams()[i]; - if (!typeArgs.empty()) { - auto subresult = Visit(typeArgs[i]); - if (!subresult) { + SmallVector importedTypeArgs; + importedTypeArgs.reserve(typeParamCount); + if (!typeArgs.empty()) { + for (auto typeArg : typeArgs) { + Type importedTypeArg = Visit(typeArg).AbstractType; + if (!importedTypeArg) return nullptr; + importedTypeArgs.push_back(importedTypeArg); + } + } else { + for (auto typeParam : imported->getGenericParams()->getParams()) { + if (typeParam->getSuperclass() && + typeParam->getConformingProtocols().empty()) { + importedTypeArgs.push_back(typeParam->getSuperclass()); + continue; } - importedTypeArg = subresult.AbstractType; - } else if (typeParam->getSuperclass() && - typeParam->getConformingProtocols().empty()) { - importedTypeArg = typeParam->getSuperclass(); - } else { + SmallVector memberTypes; if (auto superclassType = typeParam->getSuperclass()) @@ -896,11 +910,11 @@ namespace { if (memberTypes.empty()) hasExplicitAnyObject = true; - importedTypeArg = ProtocolCompositionType::get( + Type importedTypeArg = ProtocolCompositionType::get( Impl.SwiftContext, memberTypes, hasExplicitAnyObject); + importedTypeArgs.push_back(importedTypeArg); } - importedTypeArgs.push_back(importedTypeArg); } assert(importedTypeArgs.size() == typeParamCount); importedType = BoundGenericClassType::get( @@ -918,27 +932,32 @@ namespace { return {}; } if (nsObjectTy && importedType->isEqual(nsObjectTy)) { - SmallVector protocols{ - type->qual_begin(), type->qual_end() - }; - auto *nsObjectProto = - Impl.getNSObjectProtocolType()->getAnyNominal(); - if (!nsObjectProto) { - // Input is malformed - return {}; + // Skip if there is no NSObject protocol. + auto nsObjectProtoType = + Impl.getNSObjectProtocolType(); + if (nsObjectProtoType) { + auto *nsObjectProto = nsObjectProtoType->getAnyNominal(); + if (!nsObjectProto) { + // Input is malformed + return {}; + } + + SmallVector protocols{ + type->qual_begin(), type->qual_end() + }; + auto *clangProto = + cast(nsObjectProto->getClangDecl()); + protocols.push_back( + const_cast(clangProto)); + + clang::ASTContext &clangCtx = Impl.getClangASTContext(); + clang::QualType protosOnlyType = + clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, + /*type args*/{}, + protocols, + /*kindof*/false); + return Visit(clangCtx.getObjCObjectPointerType(protosOnlyType)); } - auto *clangProto = - cast(nsObjectProto->getClangDecl()); - protocols.push_back( - const_cast(clangProto)); - - clang::ASTContext &clangCtx = Impl.getClangASTContext(); - clang::QualType protosOnlyType = - clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, - /*type args*/{}, - protocols, - /*kindof*/false); - return Visit(clangCtx.getObjCObjectPointerType(protosOnlyType)); } } @@ -1152,208 +1171,240 @@ static bool isNSString(Type type) { return false; } -static ImportedType adjustTypeForConcreteImport( - ClangImporter::Implementation &impl, - ImportResult importResult, ImportTypeKind importKind, - bool allowNSUIntegerAsInt, Bridgeability bridging, OptionalTypeKind optKind, - bool resugarNSErrorPointer) { - Type importedType = importResult.AbstractType; - ImportHint hint = importResult.Hint; - - if (importKind == ImportTypeKind::Abstract) { - return {importedType, false}; - } - - // 'void' can only be imported as a function result type. - if (hint == ImportHint::Void && - (importKind == ImportTypeKind::AuditedResult || - importKind == ImportTypeKind::Result)) { - return {impl.getNamedSwiftType(impl.getStdlibModule(), "Void"), false}; - } - - // Import NSString * globals as String. - if (hint == ImportHint::ObjCBridged && isNSString(importedType) && - (importKind == ImportTypeKind::Variable || - importKind == ImportTypeKind::AuditedVariable)) { - return {hint.BridgedType, false}; - } +static Type maybeImportNSErrorOutParameter(ClangImporter::Implementation &impl, + Type importedType, + bool resugarNSErrorPointer) { + PointerTypeKind PTK; + auto elementType = importedType->getAnyPointerElementType(PTK); + if (!elementType || PTK != PTK_AutoreleasingUnsafeMutablePointer) + return Type(); - // For anything else, if we completely failed to import the type - // abstractly, give up now. - if (!importedType) - return {Type(), false}; + auto elementObj = elementType->getOptionalObjectType(); + if (!elementObj) + return Type(); - // Special case AutoreleasingUnsafeMutablePointer parameters. - auto maybeImportNSErrorPointer = [&]() -> Type { - if (importKind != ImportTypeKind::Parameter) - return Type(); + auto elementClass = elementObj->getClassOrBoundGenericClass(); + if (!elementClass) + return Type(); - PointerTypeKind PTK; - auto elementType = importedType->getAnyPointerElementType(PTK); - if (!elementType || PTK != PTK_AutoreleasingUnsafeMutablePointer) - return Type(); + // FIXME: Avoid string comparison by caching this identifier. + if (elementClass->getName().str() != + impl.SwiftContext.getSwiftName(KnownFoundationEntity::NSError)) + return Type(); - auto elementObj = elementType->getOptionalObjectType(); - if (!elementObj) - return Type(); + ModuleDecl *foundationModule = impl.tryLoadFoundationModule(); + if (!foundationModule || + foundationModule->getName() + != elementClass->getModuleContext()->getName()) + return Type(); - auto elementClass = elementObj->getClassOrBoundGenericClass(); - if (!elementClass) - return Type(); - // FIXME: Avoid string comparison by caching this identifier. - if (elementClass->getName().str() != - impl.SwiftContext.getSwiftName(KnownFoundationEntity::NSError)) - return Type(); + if (resugarNSErrorPointer) + return impl.getNamedSwiftType( + foundationModule, + impl.SwiftContext.getSwiftName( + KnownFoundationEntity::NSErrorPointer)); - ModuleDecl *foundationModule = impl.tryLoadFoundationModule(); - if (!foundationModule || - foundationModule->getName() - != elementClass->getModuleContext()->getName()) - return Type(); + // The imported type is AUMP, but the typealias is AUMP? + // so we have to manually make them match. We also want to assume this in + // general for error out-parameters even if they weren't marked nullable in C. + // Or at least we do for source-compatibility reasons... + return OptionalType::get(importedType); +} +static Type maybeImportCFOutParameter(ClangImporter::Implementation &impl, + Type importedType, + ImportTypeKind importKind) { + PointerTypeKind PTK; + auto elementType = importedType->getAnyPointerElementType(PTK); + if (!elementType || PTK != PTK_UnsafeMutablePointer) + return Type(); - if (resugarNSErrorPointer) - return impl.getNamedSwiftType( - foundationModule, - impl.SwiftContext.getSwiftName( - KnownFoundationEntity::NSErrorPointer)); + auto insideOptionalType = elementType->getOptionalObjectType(); + bool isOptional = (bool) insideOptionalType; + if (!insideOptionalType) + insideOptionalType = elementType; - // The imported type is AUMP, but the typealias is AUMP? - // so we have to manually make them match. - return OptionalType::get(importedType); - }; + auto boundGenericTy = insideOptionalType->getAs(); + if (!boundGenericTy) + return Type(); - if (Type result = maybeImportNSErrorPointer()) { - return {result, false}; - } + auto boundGenericBase = boundGenericTy->getDecl(); + if (boundGenericBase != impl.SwiftContext.getUnmanagedDecl()) + return Type(); - auto maybeImportCFOutParameter = [&]() -> Type { - if (importKind != ImportTypeKind::CFRetainedOutParameter && - importKind != ImportTypeKind::CFUnretainedOutParameter) { - return Type(); - } + assert(boundGenericTy->getGenericArgs().size() == 1 && + "signature of Unmanaged has changed"); - PointerTypeKind PTK; - auto elementType = importedType->getAnyPointerElementType(PTK); - if (!elementType || PTK != PTK_UnsafeMutablePointer) - return Type(); + auto resultTy = boundGenericTy->getGenericArgs().front(); + if (isOptional) + resultTy = OptionalType::get(resultTy); - auto insideOptionalType = elementType->getOptionalObjectType(); - bool isOptional = (bool) insideOptionalType; - if (!insideOptionalType) - insideOptionalType = elementType; + PointerTypeKind pointerKind; + if (importKind == ImportTypeKind::CFRetainedOutParameter) + pointerKind = PTK_UnsafeMutablePointer; + else + pointerKind = PTK_AutoreleasingUnsafeMutablePointer; - auto boundGenericTy = insideOptionalType->getAs(); - if (!boundGenericTy) - return Type(); + resultTy = resultTy->wrapInPointer(pointerKind); + return resultTy; +} - auto boundGenericBase = boundGenericTy->getDecl(); - if (boundGenericBase != impl.SwiftContext.getUnmanagedDecl()) - return Type(); +static ImportedType adjustTypeForConcreteImport( + ClangImporter::Implementation &impl, + ImportResult importResult, ImportTypeKind importKind, + bool allowNSUIntegerAsInt, Bridgeability bridging, OptionalTypeKind optKind, + bool resugarNSErrorPointer) { + Type importedType = importResult.AbstractType; + ImportHint hint = importResult.Hint; - assert(boundGenericTy->getGenericArgs().size() == 1 && - "signature of Unmanaged has changed"); + if (importKind == ImportTypeKind::Abstract) { + return {importedType, false}; + } - auto resultTy = boundGenericTy->getGenericArgs().front(); - if (isOptional) - resultTy = OptionalType::get(resultTy); + // If we completely failed to import the type, give up now. + // Special-case for 'void' which is valid in result positions. + if (!importedType && hint != ImportHint::Void) + return {Type(), false}; - StringRef pointerName; - if (importKind == ImportTypeKind::CFRetainedOutParameter) - pointerName = "UnsafeMutablePointer"; - else - pointerName = "AutoreleasingUnsafeMutablePointer"; + switch (hint) { + case ImportHint::None: + break; - resultTy = impl.getNamedSwiftTypeSpecialization(impl.getStdlibModule(), - pointerName, - resultTy); - return resultTy; - }; - if (Type outParamTy = maybeImportCFOutParameter()) { - importedType = outParamTy; - } + case ImportHint::ObjCPointer: + case ImportHint::CFunctionPointer: + break; - // SwiftTypeConverter turns block pointers into @convention(block) types. - // In some contexts, we bridge them to use the Swift function type - // representation. This includes typedefs of block types, which use the - // Swift function type representation. - if (hint == ImportHint::Block) { - if (canBridgeTypes(importKind)) { - // Determine the function type representation we need. - // - // For Objective-C collection arguments, we cannot bridge from a block - // to a Swift function type, so force the block representation. Normally - // the mapped type will have a block representation (making this a no-op), - // but in cases where the Clang type was written as a typedef of a - // block type, that typedef will have a Swift function type - // representation. This code will then break down the imported type - // alias and produce a function type with block representation. - auto requiredFunctionTypeRepr = FunctionTypeRepresentation::Swift; - if (importKind == ImportTypeKind::ObjCCollectionElement) { - requiredFunctionTypeRepr = FunctionTypeRepresentation::Block; + case ImportHint::Void: + // 'void' can only be imported as a function result type. + if (importKind != ImportTypeKind::AuditedResult && + importKind != ImportTypeKind::Result) { + return {Type(), false}; + } + importedType = impl.getNamedSwiftType(impl.getStdlibModule(), "Void"); + break; + + case ImportHint::ObjCBridged: + // Import NSString * globals as non-optional String. + if (isNSString(importedType)) { + if (importKind == ImportTypeKind::Variable || + importKind == ImportTypeKind::AuditedVariable) { + importedType = hint.BridgedType; + optKind = OTK_None; + break; } + } - auto fTy = importedType->castTo(); - FunctionType::ExtInfo einfo = fTy->getExtInfo(); - if (einfo.getRepresentation() != requiredFunctionTypeRepr) { - einfo = einfo.withRepresentation(requiredFunctionTypeRepr); - importedType = fTy->withExtInfo(einfo); + // If we have a bridged Objective-C type and we are allowed to + // bridge, do so. + if (canBridgeTypes(importKind) && + importKind != ImportTypeKind::PropertyWithReferenceSemantics && + !(importKind == ImportTypeKind::Typedef && + bridging == Bridgeability::None)) { + // id and Any can be bridged without Foundation. There would be + // bootstrapping issues with the ObjectiveC module otherwise. + if (hint.BridgedType->isAny() + || impl.tryLoadFoundationModule() + || impl.ImportForwardDeclarations) { + + // Set the bridged type if it wasn't done already. + if (!importedType->isEqual(hint.BridgedType)) + importedType = hint.BridgedType; } } - } - - // Turn BOOL and DarwinBoolean into Bool in contexts that can bridge types - // losslessly. - if (hint == ImportHint::Boolean && bridging == Bridgeability::Full && - canBridgeTypes(importKind)) { - return {impl.SwiftContext.getBoolDecl()->getDeclaredType(), false}; - } + break; + + case ImportHint::Block: { + // SwiftTypeConverter turns block pointers into @convention(block) types. + // In some contexts, we bridge them to use the Swift function type + // representation. This includes typedefs of block types, which use the + // Swift function type representation. + if (!canBridgeTypes(importKind)) + break; - // When NSUInteger is used as an enum's underlying type or if it does not come - // from a system module, make sure it stays unsigned. - if (hint == ImportHint::NSUInteger) { - if (importKind == ImportTypeKind::Enum || !allowNSUIntegerAsInt) { - return {impl.SwiftContext.getUIntDecl()->getDeclaredType(), false}; + // Determine the function type representation we need. + // + // For Objective-C collection arguments, we cannot bridge from a block + // to a Swift function type, so force the block representation. Normally + // the mapped type will have a block representation (making this a no-op), + // but in cases where the Clang type was written as a typedef of a + // block type, that typedef will have a Swift function type + // representation. This code will then break down the imported type + // alias and produce a function type with block representation. + auto requiredFunctionTypeRepr = FunctionTypeRepresentation::Swift; + if (importKind == ImportTypeKind::ObjCCollectionElement) { + requiredFunctionTypeRepr = FunctionTypeRepresentation::Block; } - } - // Wrap CF pointers up as unmanaged types, unless this is an audited - // context. - if (hint == ImportHint::CFPointer && !isCFAudited(importKind)) { - importedType = getUnmanagedType(impl, importedType); + auto fTy = importedType->castTo(); + FunctionType::ExtInfo einfo = fTy->getExtInfo(); + if (einfo.getRepresentation() != requiredFunctionTypeRepr) { + einfo = einfo.withRepresentation(requiredFunctionTypeRepr); + importedType = fTy->withExtInfo(einfo); + } + break; } - // For types we import as new types in Swift, if the use is CF un-audited, - // then we have to force it to be unmanaged - if (hint == ImportHint::SwiftNewtypeFromCFPointer && - !isCFAudited(importKind)) { - auto underlyingType = importedType->getSwiftNewtypeUnderlyingType(); - if (underlyingType) + case ImportHint::Boolean: + // Turn BOOL and DarwinBoolean into Bool in contexts that can bridge types + // losslessly. + if (bridging == Bridgeability::Full && canBridgeTypes(importKind)) + importedType = impl.SwiftContext.getBoolDecl()->getDeclaredType(); + break; + + case ImportHint::NSUInteger: + // When NSUInteger is used as an enum's underlying type or if it does not + // come from a system module, make sure it stays unsigned. + if (importKind == ImportTypeKind::Enum || !allowNSUIntegerAsInt) + importedType = impl.SwiftContext.getUIntDecl()->getDeclaredType(); + break; + + case ImportHint::CFPointer: + // Wrap CF pointers up as unmanaged types, unless this is an audited + // context. + if (!isCFAudited(importKind)) { + Type underlyingType = importedType->getSwiftNewtypeUnderlyingType(); + if (!underlyingType) + underlyingType = importedType; importedType = getUnmanagedType(impl, underlyingType); - } + } + break; + + case ImportHint::VAList: + // Treat va_list specially: null-unspecified va_list parameters should be + // assumed to be non-optional. (Most people don't even think of va_list as a + // pointer, and it's not a portable assumption anyway.) + if (importKind == ImportTypeKind::Parameter && + optKind == OTK_ImplicitlyUnwrappedOptional) { + optKind = OTK_None; + } + break; + + case ImportHint::OtherPointer: + // Special-case AutoreleasingUnsafeMutablePointer parameters. + if (importKind == ImportTypeKind::Parameter) { + if (Type result = maybeImportNSErrorOutParameter(impl, importedType, + resugarNSErrorPointer)) { + importedType = result; + optKind = OTK_None; + break; + } + } - // If we have a bridged Objective-C type and we are allowed to - // bridge, do so. - if (hint == ImportHint::ObjCBridged && - canBridgeTypes(importKind) && - importKind != ImportTypeKind::PropertyWithReferenceSemantics && - !(importKind == ImportTypeKind::Typedef && - bridging == Bridgeability::None)) { - // id and Any can be bridged without Foundation. There would be - // bootstrapping issues with the ObjectiveC module otherwise. - if (hint.BridgedType->isAny() - || impl.tryLoadFoundationModule() - || impl.ImportForwardDeclarations) { - - // Set the bridged type if it wasn't done already. - if (!importedType->isEqual(hint.BridgedType)) - importedType = hint.BridgedType; + // Remove 'Unmanaged' from audited CF out-parameters. + if (importKind == ImportTypeKind::CFRetainedOutParameter || + importKind == ImportTypeKind::CFUnretainedOutParameter) { + if (Type outParamTy = maybeImportCFOutParameter(impl, importedType, + importKind)) { + importedType = outParamTy; + break; + } } + + break; } - if (!importedType) - return {importedType, false}; + assert(importedType); if (importKind == ImportTypeKind::RecordField && importedType->isAnyClassReferenceType()) { @@ -1366,26 +1417,13 @@ static ImportedType adjustTypeForConcreteImport( importedType = getUnmanagedType(impl, importedType); } - // Treat va_list specially: null-unspecified va_list parameters should be - // assumed to be non-optional. (Most people don't even think of va_list as a - // pointer, and it's not a portable assumption anyway.) - if (importKind == ImportTypeKind::Parameter && - optKind == OTK_ImplicitlyUnwrappedOptional) { - if (auto *nominal = importedType->getNominalOrBoundGenericNominal()) { - if (nominal->getName().str() == "CVaListPointer" && - nominal->getParentModule()->isStdlibModule()) { - optKind = OTK_None; - } - } - } - // Wrap class, class protocol, function, and metatype types in an // optional type. bool isIUO = false; - if (importKind != ImportTypeKind::Typedef && canImportAsOptional(hint)) { + if (importKind != ImportTypeKind::Typedef && optKind != OTK_None && + canImportAsOptional(hint)) { isIUO = optKind == OTK_ImplicitlyUnwrappedOptional; - if (optKind != OTK_None) - importedType = OptionalType::get(importedType); + importedType = OptionalType::get(importedType); } return {importedType, isIUO}; @@ -1579,7 +1617,7 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType( OptionalityOfReturn); } -ImportedType ClangImporter::Implementation::importFunctionType( +ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType( DeclContext *dc, const clang::FunctionDecl *clangDecl, ArrayRef params, bool isVariadic, bool isFromSystemModule, DeclName name, ParameterList *¶meterList) { @@ -1871,7 +1909,7 @@ static Type mapGenericArgs(const DeclContext *fromDC, return type.subst(subs); } -ImportedType ClangImporter::Implementation::importMethodType( +ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( const DeclContext *dc, const clang::ObjCMethodDecl *clangDecl, ArrayRef params, bool isVariadic, bool isFromSystemModule, ParameterList **bodyParams, @@ -2165,7 +2203,7 @@ ImportedType ClangImporter::Implementation::importMethodType( importedType.isImplicitlyUnwrapped()}; } -ImportedType ClangImporter::Implementation::importAccessorMethodType( +ImportedType ClangImporter::Implementation::importAccessorParamsAndReturnType( const DeclContext *dc, const clang::ObjCPropertyDecl *property, const clang::ObjCMethodDecl *clangDecl, bool isFromSystemModule, ImportedName functionName, swift::ParameterList **params) { @@ -2184,7 +2222,7 @@ ImportedType ClangImporter::Implementation::importAccessorMethodType( // The member was defined in 'origDC', but is being imported into 'dc'. // 'dc' must be a subclass or a type conforming to protocol. - // FIXME: Duplicated from importMethodType. + // FIXME: Duplicated from importMethodParamsAndReturnType. DeclContext *origDC = importDeclContextOf(property, property->getDeclContext()); assert(origDC); @@ -2309,33 +2347,6 @@ Type ClangImporter::Implementation::getNamedSwiftType(StringRef moduleName, return getNamedSwiftType(module, name); } -Type -ClangImporter::Implementation:: -getNamedSwiftTypeSpecialization(ModuleDecl *module, StringRef name, - ArrayRef args) { - if (!module) - return Type(); - - // Look for the type. - SmallVector results; - module->lookupValue(SwiftContext.getIdentifier(name), - NLKind::UnqualifiedLookup, results); - if (results.size() == 1) { - if (auto nominalDecl = dyn_cast(results.front())) { - if (auto params = nominalDecl->getGenericParams()) { - if (params->size() == args.size()) { - // When we form the bound generic type, make sure we get the - // substitutions. - auto *BGT = BoundGenericType::get(nominalDecl, Type(), args); - return BGT; - } - } - } - } - - return Type(); -} - Decl *ClangImporter::Implementation::importDeclByName(StringRef name) { auto &sema = Instance->getSema(); diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 5e5fc64330657..f21d2b84adc82 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -220,8 +220,6 @@ enum class SpecialMethodKind { NSDictionarySubscriptGetter }; -#define SWIFT_NATIVE_ANNOTATION_STRING "__swift native" - #define SWIFT_PROTOCOL_SUFFIX "Protocol" #define SWIFT_CFTYPE_SUFFIX "Ref" @@ -916,19 +914,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// \returns The named type, or null if the type could not be found. Type getNamedSwiftType(ModuleDecl *module, StringRef name); - /// Retrieve a specialization of the named Swift type, e.g., - /// UnsafeMutablePointer. - /// - /// \param module The name of the module in which the type should occur. - /// - /// \param name The name of the type to find. - /// - /// \param args The arguments to use in the specialization. - /// - /// \returns The named type, or null if the type could not be found. - Type getNamedSwiftTypeSpecialization(ModuleDecl *module, StringRef name, - ArrayRef args); - /// Retrieve the NSObject type. Type getNSObjectType(); @@ -1038,11 +1023,13 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// to system APIs. /// \param name The name of the function. /// \param[out] parameterList The parameters visible inside the function body. - ImportedType importFunctionType(DeclContext *dc, - const clang::FunctionDecl *clangDecl, - ArrayRef params, - bool isVariadic, bool isFromSystemModule, - DeclName name, ParameterList *¶meterList); + ImportedType + importFunctionParamsAndReturnType(DeclContext *dc, + const clang::FunctionDecl *clangDecl, + ArrayRef params, + bool isVariadic, bool isFromSystemModule, + DeclName name, + ParameterList *¶meterList); /// Import the given function return type. /// @@ -1093,7 +1080,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// the return type of this method. /// /// Note that this is not appropriate to use for property accessor methods. - /// Use #importAccessorMethodType instead. + /// Use #importAccessorParamsAndReturnType instead. /// /// \param dc The context the method is being imported into. /// \param clangDecl The underlying declaration. @@ -1104,20 +1091,22 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// to system APIs. /// \param[out] bodyParams The patterns visible inside the function body. /// \param importedName How to import the name of the method. - /// \param[out] errorConvention Whether and how the method throws NSErrors. + /// \param[out] errorConv Whether and how the method throws NSErrors. /// \param kind Controls whether we're building a type for a method that /// needs special handling. /// /// \returns the imported result type, or null if the type cannot be /// imported. ImportedType - importMethodType(const DeclContext *dc, - const clang::ObjCMethodDecl *clangDecl, - ArrayRef params, bool isVariadic, - bool isFromSystemModule, ParameterList **bodyParams, - importer::ImportedName importedName, - Optional &errorConvention, - SpecialMethodKind kind); + importMethodParamsAndReturnType(const DeclContext *dc, + const clang::ObjCMethodDecl *clangDecl, + ArrayRef params, + bool isVariadic, + bool isFromSystemModule, + ParameterList **bodyParams, + importer::ImportedName importedName, + Optional &errorConv, + SpecialMethodKind kind); /// Import the type of an Objective-C method that will be imported as an /// accessor for \p property. @@ -1137,12 +1126,13 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// /// \returns the imported result type, or null if the type cannot be /// imported. - ImportedType importAccessorMethodType(const DeclContext *dc, - const clang::ObjCPropertyDecl *property, - const clang::ObjCMethodDecl *clangDecl, - bool isFromSystemModule, - importer::ImportedName importedName, - ParameterList **params); + ImportedType + importAccessorParamsAndReturnType(const DeclContext *dc, + const clang::ObjCPropertyDecl *property, + const clang::ObjCMethodDecl *clangDecl, + bool isFromSystemModule, + importer::ImportedName importedName, + ParameterList **params); /// Determine whether the given typedef-name is "special", meaning /// that it has performed some non-trivial mapping of its underlying type diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 9cde253cadaf8..10fa86b7d96b3 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1577,6 +1577,7 @@ bool Demangle::nodeConsumesGenericArgs(Node *node) { case Node::Kind::ExplicitClosure: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::Initializer: + case Node::Kind::PropertyWrapperBackingInitializer: return false; default: return true; @@ -2952,6 +2953,10 @@ NodePointer Demangler::demangleFunctionEntity() { case 'u': Args = TypeAndIndex; Kind = Node::Kind::ImplicitClosure; break; case 'A': Args = Index; Kind = Node::Kind::DefaultArgumentInitializer; break; case 'p': return demangleEntity(Node::Kind::GenericTypeParamDecl); + case 'P': + Args = None; + Kind = Node::Kind::PropertyWrapperBackingInitializer; + break; default: return nullptr; } diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index c67810f2d91f9..28af0b9a3005e 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -79,19 +79,18 @@ static DemanglerPrinter &operator<<(DemanglerPrinter &printer, case '\n': printer << "\\n"; break; case '\r': printer << "\\r"; break; case '"': printer << "\\\""; break; - case '\'': printer << '\''; break; // no need to escape these case '\0': printer << "\\0"; break; default: - auto c = static_cast(C); - // Other ASCII control characters should get escaped. - if (c < 0x20 || c == 0x7F) { + auto c = static_cast(C); + // Other control or high-bit characters should get escaped. + if (c < 0x20 || c >= 0x7F) { static const char Hexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; printer << "\\x" << Hexdigit[c >> 4] << Hexdigit[c & 0xF]; } else { - printer << c; + printer << (char)c; } break; } @@ -408,6 +407,7 @@ class NodePrinter { case Node::Kind::InOut: case Node::Kind::InfixOperator: case Node::Kind::Initializer: + case Node::Kind::PropertyWrapperBackingInitializer: case Node::Kind::KeyPathGetterThunkHelper: case Node::Kind::KeyPathSetterThunkHelper: case Node::Kind::KeyPathEqualsThunkHelper: @@ -1135,6 +1135,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { case Node::Kind::Initializer: return printEntity(Node, asPrefixContext, TypePrinting::NoType, /*hasName*/false, "variable initialization expression"); + case Node::Kind::PropertyWrapperBackingInitializer: + return printEntity( + Node, asPrefixContext, TypePrinting::NoType, + /*hasName*/false, "property wrapper backing initializer"); case Node::Kind::DefaultArgumentInitializer: return printEntity(Node, asPrefixContext, TypePrinting::NoType, /*hasName*/false, "default argument ", @@ -2485,7 +2489,8 @@ printEntity(NodePointer Entity, bool asPrefixContext, TypePrinting TypePr, if (!asPrefixContext && PostfixContext) { // Print any left over context which couldn't be printed in prefix form. if (Entity->getKind() == Node::Kind::DefaultArgumentInitializer || - Entity->getKind() == Node::Kind::Initializer) { + Entity->getKind() == Node::Kind::Initializer || + Entity->getKind() == Node::Kind::PropertyWrapperBackingInitializer) { Printer << " of "; } else { Printer << " in "; diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index b3311464204d5..53c4477d127f9 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -796,6 +796,11 @@ void Remangler::mangleInitializer(Node *node, EntityContext &ctx) { mangleSimpleEntity(node, 'I', "i", ctx); } +void Remangler::manglePropertyWrapperBackingInitializer(Node *node, + EntityContext &ctx) { + mangleSimpleEntity(node, 'I', "P", ctx); +} + void Remangler::mangleDefaultArgumentInitializer(Node *node, EntityContext &ctx) { mangleNamedEntity(node, 'I', "A", ctx); diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 79c3e5e81f87e..341f3c0b34d11 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -518,6 +518,7 @@ void Remangler::mangleGenericArgs(Node *node, char &Separator, case Node::Kind::ImplicitClosure: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::Initializer: + case Node::Kind::PropertyWrapperBackingInitializer: if (!fullSubstitutionMap) break; @@ -1565,6 +1566,11 @@ void Remangler::mangleInitializer(Node *node) { Buffer << "fi"; } +void Remangler::manglePropertyWrapperBackingInitializer(Node *node) { + mangleChildNodes(node); + Buffer << "fP"; +} + void Remangler::mangleLazyProtocolWitnessTableAccessor(Node *node) { mangleChildNodes(node); Buffer << "Wl"; @@ -2522,6 +2528,7 @@ bool Demangle::isSpecialized(Node *node) { case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: case Node::Kind::Initializer: + case Node::Kind::PropertyWrapperBackingInitializer: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::Getter: case Node::Kind::Setter: @@ -2561,6 +2568,7 @@ NodePointer Demangle::getUnspecialized(Node *node, NodeFactory &Factory) { case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: case Node::Kind::Initializer: + case Node::Kind::PropertyWrapperBackingInitializer: case Node::Kind::DefaultArgumentInitializer: NumToCopy = node->getNumChildren(); LLVM_FALLTHROUGH; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index a5684562b96b3..4d53646386ce8 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1782,6 +1782,7 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, } case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: + case file_types::TY_SwiftSourceInfoFile: if (OI.ShouldGenerateModule && !OI.shouldLink()) { // When generating a .swiftmodule as a top-level output (as opposed // to, for example, linking an image), treat .swiftmodule files as @@ -2541,9 +2542,10 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA, chooseSwiftModuleOutputPath(C, OutputMap, workingDirectory, Output.get()); if (OI.ShouldGenerateModule && - (isa(JA) || isa(JA))) - chooseSwiftModuleDocOutputPath(C, OutputMap, workingDirectory, - Output.get()); + (isa(JA) || isa(JA))) { + chooseSwiftModuleDocOutputPath(C, OutputMap, workingDirectory, Output.get()); + chooseSwiftSourceInfoOutputPath(C, OutputMap, workingDirectory, Output.get()); + } if (C.getArgs().hasArg(options::OPT_emit_module_interface, options::OPT_emit_module_interface_path)) @@ -2786,37 +2788,69 @@ void Driver::chooseSwiftModuleOutputPath(Compilation &C, } } -void Driver::chooseSwiftModuleDocOutputPath(Compilation &C, - const TypeToPathMap *OutputMap, - StringRef workingDirectory, - CommandOutput *Output) const { - - if (hasExistingAdditionalOutput(*Output, file_types::TY_SwiftModuleDocFile)) +static void chooseModuleAuxiliaryOutputFilePath(Compilation &C, + const TypeToPathMap *OutputMap, + StringRef workingDirectory, + CommandOutput *Output, + file_types::ID fileID, + bool isPrivate, + Optional optId = llvm::None) { + if (hasExistingAdditionalOutput(*Output, fileID)) return; + // Honor driver option for this path if it's given + if (optId.hasValue()) { + if (const Arg *A = C.getArgs().getLastArg(*optId)) { + Output->setAdditionalOutputForType(fileID, StringRef(A->getValue())); + return; + } + } - StringRef OFMModuleDocOutputPath; + StringRef OFMOutputPath; if (OutputMap) { - auto iter = OutputMap->find(file_types::TY_SwiftModuleDocFile); + auto iter = OutputMap->find(fileID); if (iter != OutputMap->end()) - OFMModuleDocOutputPath = iter->second; + OFMOutputPath = iter->second; } - if (!OFMModuleDocOutputPath.empty()) { + if (!OFMOutputPath.empty()) { // Prefer a path from the OutputMap. - Output->setAdditionalOutputForType(file_types::TY_SwiftModuleDocFile, - OFMModuleDocOutputPath); + Output->setAdditionalOutputForType(fileID, OFMOutputPath); } else if (Output->getPrimaryOutputType() != file_types::TY_Nothing) { - // Otherwise, put it next to the swiftmodule file. - llvm::SmallString<128> Path( - Output->getAnyOutputForType(file_types::TY_SwiftModuleFile)); - bool isTempFile = C.isTemporaryFile(Path); - llvm::sys::path::replace_extension( - Path, file_types::getExtension(file_types::TY_SwiftModuleDocFile)); - Output->setAdditionalOutputForType(file_types::TY_SwiftModuleDocFile, Path); + auto ModulePath = Output->getAnyOutputForType(file_types::TY_SwiftModuleFile); + bool isTempFile = C.isTemporaryFile(ModulePath); + auto ModuleName = llvm::sys::path::filename(ModulePath); + llvm::SmallString<128> Path(llvm::sys::path::parent_path(ModulePath)); + if (isPrivate) { + llvm::sys::path::append(Path, "Private"); + // If the build system has created a Private dir for us to include the file, use it. + if (!llvm::sys::fs::exists(Path)) { + llvm::sys::path::remove_filename(Path); + } + } + llvm::sys::path::append(Path, ModuleName); + llvm::sys::path::replace_extension(Path, file_types::getExtension(fileID)); + Output->setAdditionalOutputForType(fileID, Path); if (isTempFile) C.addTemporaryFile(Path); } } +void Driver::chooseSwiftSourceInfoOutputPath(Compilation &C, + const TypeToPathMap *OutputMap, + StringRef workingDirectory, + CommandOutput *Output) const { + chooseModuleAuxiliaryOutputFilePath(C, OutputMap, workingDirectory, Output, + file_types::TY_SwiftSourceInfoFile, + /*isPrivate*/true, options::OPT_emit_module_source_info_path); +} + +void Driver::chooseSwiftModuleDocOutputPath(Compilation &C, + const TypeToPathMap *OutputMap, + StringRef workingDirectory, + CommandOutput *Output) const { + chooseModuleAuxiliaryOutputFilePath(C, OutputMap, workingDirectory, Output, + file_types::TY_SwiftModuleDocFile, /*isPrivate*/false); +} + void Driver::chooseRemappingOutputPath(Compilation &C, const TypeToPathMap *OutputMap, CommandOutput *Output) const { diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 07e5f113021c5..efd41ed193821 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -533,6 +533,7 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_TBD: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_SwiftSourceInfoFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: llvm_unreachable("Invalid type ID"); @@ -641,6 +642,9 @@ void ToolChain::JobContext::addFrontendSupplementaryOutputArguments( addOutputsOfType(arguments, Output, Args, file_types::TY_SwiftModuleDocFile, "-emit-module-doc-path"); + addOutputsOfType(arguments, Output, Args, file_types::TY_SwiftSourceInfoFile, + "-emit-module-source-info-path"); + addOutputsOfType(arguments, Output, Args, file_types::ID::TY_SwiftModuleInterfaceFile, "-emit-module-interface-path"); @@ -772,6 +776,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_ModuleTrace: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_SwiftSourceInfoFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: llvm_unreachable("Invalid type ID"); @@ -909,6 +914,9 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job, addOutputsOfType(Arguments, context.Output, context.Args, file_types::TY_SwiftModuleDocFile, "-emit-module-doc-path"); + addOutputsOfType(Arguments, context.Output, context.Args, + file_types::TY_SwiftSourceInfoFile, + "-emit-module-source-info-path"); addOutputsOfType(Arguments, context.Output, context.Args, file_types::ID::TY_SwiftModuleInterfaceFile, "-emit-module-interface-path"); diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 931bb5ef28d19..6bbd2d8f9d4a7 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -161,6 +161,12 @@ bool ArgsToFrontendOptionsConverter::convert( if (checkUnusedSupplementaryOutputPaths()) return true; + if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction) + && Opts.SkipNonInlinableFunctionBodies) { + Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies); + return true; + } + if (const Arg *A = Args.getLastArg(OPT_module_link_name)) Opts.ModuleLinkName = A->getValue(); @@ -219,6 +225,8 @@ void ArgsToFrontendOptionsConverter::computeDebugTimeOptions() { Opts.DebugTimeExpressionTypeChecking |= Args.hasArg(OPT_debug_time_expression_type_checking); Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation); + Opts.SkipNonInlinableFunctionBodies |= + Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies); if (const Arg *A = Args.getLastArg(OPT_stats_output_dir)) { Opts.StatsOutputDir = A->getValue(); if (Args.getLastArg(OPT_trace_stats_events)) { @@ -535,6 +543,12 @@ bool ArgsToFrontendOptionsConverter::checkUnusedSupplementaryOutputPaths() Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_doc); return true; } + // If we cannot emit module doc, we cannot emit source information file either. + if (!FrontendOptions::canActionEmitModuleDoc(Opts.RequestedAction) && + Opts.InputsAndOutputs.hasModuleSourceInfoOutputPath()) { + Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_source_info); + return true; + } if (!FrontendOptions::canActionEmitInterface(Opts.RequestedAction) && Opts.InputsAndOutputs.hasModuleInterfaceOutputPath()) { Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_interface); diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp index c18818a4daf5c..cec2a86ec45d1 100644 --- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp @@ -296,11 +296,13 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() auto TBD = getSupplementaryFilenamesFromArguments(options::OPT_emit_tbd_path); auto moduleInterfaceOutput = getSupplementaryFilenamesFromArguments( options::OPT_emit_module_interface_path); + auto moduleSourceInfoOutput = getSupplementaryFilenamesFromArguments( + options::OPT_emit_module_source_info_path); if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput || !dependenciesFile || !referenceDependenciesFile || !serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD || - !moduleInterfaceOutput) { + !moduleInterfaceOutput || !moduleSourceInfoOutput) { return None; } std::vector result; @@ -319,7 +321,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() sop.LoadedModuleTracePath = (*loadedModuleTrace)[i]; sop.TBDPath = (*TBD)[i]; sop.ModuleInterfaceOutputPath = (*moduleInterfaceOutput)[i]; - + sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i]; result.push_back(sop); } return result; @@ -394,6 +396,11 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( file_types::TY_SwiftModuleDocFile, "", defaultSupplementaryOutputPathExcludingExtension); + auto moduleSourceInfoOutputPath = determineSupplementaryOutputFilename( + OPT_emit_module_source_info, pathsFromArguments.ModuleSourceInfoOutputPath, + file_types::TY_SwiftSourceInfoFile, "", + defaultSupplementaryOutputPathExcludingExtension); + // There is no non-path form of -emit-interface-path auto ModuleInterfaceOutputPath = pathsFromArguments.ModuleInterfaceOutputPath; @@ -420,6 +427,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( sop.LoadedModuleTracePath = loadedModuleTracePath; sop.TBDPath = tbdPath; sop.ModuleInterfaceOutputPath = ModuleInterfaceOutputPath; + sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath; return sop; } @@ -489,6 +497,7 @@ createFromTypeToPathMap(const TypeToPathMap *map) { {file_types::TY_ObjCHeader, paths.ObjCHeaderOutputPath}, {file_types::TY_SwiftModuleFile, paths.ModuleOutputPath}, {file_types::TY_SwiftModuleDocFile, paths.ModuleDocOutputPath}, + {file_types::TY_SwiftSourceInfoFile, paths.ModuleSourceInfoOutputPath}, {file_types::TY_Dependencies, paths.DependenciesFilePath}, {file_types::TY_SwiftDeps, paths.ReferenceDependenciesFilePath}, {file_types::TY_SerializedDiagnostics, paths.SerializedDiagnosticsPath}, @@ -516,6 +525,7 @@ SupplementaryOutputPathsComputer::readSupplementaryOutputFileMap() const { options::OPT_serialize_diagnostics_path, options::OPT_emit_loaded_module_trace_path, options::OPT_emit_module_interface_path, + options::OPT_emit_module_source_info_path, options::OPT_emit_tbd_path)) { Diags.diagnose(SourceLoc(), diag::error_cannot_have_supplementary_outputs, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 59c936c298753..d2b96169f1b12 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -769,6 +769,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_sil_merge_partial_modules)) Opts.MergePartialModules = true; + if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies)) + Opts.SkipNonInlinableFunctionBodies = true; + // Parse the optimization level. // Default to Onone settings if no option is passed. Opts.OptMode = OptimizationMode::NoOptimization; diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index f656c416df05e..13952af1d0495 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -129,6 +129,7 @@ SerializationOptions CompilerInvocation::computeSerializationOptions( SerializationOptions serializationOpts; serializationOpts.OutputPath = outs.ModuleOutputPath.c_str(); serializationOpts.DocOutputPath = outs.ModuleDocOutputPath.c_str(); + serializationOpts.SourceInfoOutputPath = outs.ModuleSourceInfoOutputPath.c_str(); serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str(); if (opts.SerializeBridgingHeader && !outs.ModuleOutputPath.empty()) serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; @@ -885,6 +886,9 @@ OptionSet CompilerInstance::computeTypeCheckingOptions() { if (options.DebugTimeExpressionTypeChecking) { TypeCheckOptions |= TypeCheckingFlags::DebugTimeExpressions; } + if (options.SkipNonInlinableFunctionBodies) { + TypeCheckOptions |= TypeCheckingFlags::SkipNonInlinableFunctionBodies; + } return TypeCheckOptions; } diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp index ed018a0e4fa5e..e5e94ec621de9 100644 --- a/lib/Frontend/FrontendInputsAndOutputs.cpp +++ b/lib/Frontend/FrontendInputsAndOutputs.cpp @@ -15,6 +15,7 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/FileTypes.h" #include "swift/Basic/PrimarySpecificPaths.h" +#include "swift/Basic/Range.h" #include "swift/Frontend/FrontendOptions.h" #include "swift/Option/Options.h" #include "swift/Parse/Lexer.h" @@ -435,6 +436,12 @@ bool FrontendInputsAndOutputs::hasModuleDocOutputPath() const { return outs.ModuleDocOutputPath; }); } +bool FrontendInputsAndOutputs::hasModuleSourceInfoOutputPath() const { + return hasSupplementaryOutputPath( + [](const SupplementaryOutputPaths &outs) -> const std::string & { + return outs.ModuleSourceInfoOutputPath; + }); +} bool FrontendInputsAndOutputs::hasModuleInterfaceOutputPath() const { return hasSupplementaryOutputPath( [](const SupplementaryOutputPaths &outs) -> const std::string & { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 605fd1c34ae3b..46e60edfb27c6 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -127,7 +127,8 @@ void FrontendOptions::forAllOutputPaths( const std::string *outputs[] = {&outs.ModuleOutputPath, &outs.ModuleDocOutputPath, &outs.ModuleInterfaceOutputPath, - &outs.ObjCHeaderOutputPath}; + &outs.ObjCHeaderOutputPath, + &outs.ModuleSourceInfoOutputPath}; for (const std::string *next : outputs) { if (!next->empty()) fn(*next); @@ -519,6 +520,41 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { llvm_unreachable("unhandled action"); } +bool FrontendOptions::doesActionGenerateIR(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::DumpInterfaceHash: + case ActionType::DumpAST: + case ActionType::EmitSyntax: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::DumpTypeInfo: + case ActionType::CompileModuleFromInterface: + case ActionType::Typecheck: + case ActionType::ResolveImports: + case ActionType::MergeModules: + case ActionType::EmitModuleOnly: + case ActionType::EmitPCH: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::EmitImportedModules: + return false; + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitAssembly: + case ActionType::EmitObject: + return true; + } + llvm_unreachable("unhandled action"); +} + const PrimarySpecificPaths & FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const { diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 978fb5278f228..f1bfcea821bc6 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -366,7 +366,9 @@ bool ModuleInterfaceBuilder::buildSwiftModule( // We don't want to serialize module docs in the cache -- they // will be serialized beside the interface file. serializeToBuffers(Mod, SerializationOpts, ModuleBuffer, - /*ModuleDocBuffer*/nullptr, SILMod.get()); + /*ModuleDocBuffer*/nullptr, + /*SourceInfoBuffer*/nullptr, + SILMod.get()); }); LLVM_DEBUG(llvm::dbgs() << "Running SIL processing passes\n"); diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 60746c1f8b375..33f07fbcd2f69 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -525,13 +525,7 @@ std::pair ModelASTWalker::walkToExprPre(Expr *E) { pushStructureNode(SN, E); } else if (auto *Tup = dyn_cast(E)) { auto *ParentE = Parent.getAsExpr(); - if (isCurrentCallArgExpr(Tup)) { - for (unsigned I = 0; I < Tup->getNumElements(); ++ I) { - SourceLoc NameLoc = Tup->getElementNameLoc(I); - if (NameLoc.isValid()) - passTokenNodesUntil(NameLoc, PassNodesBehavior::ExcludeNodeAtLocation); - } - } else if (!ParentE || !isa(ParentE)) { + if (!isCurrentCallArgExpr(Tup) && (!ParentE || !isa(ParentE))) { SyntaxStructureNode SN; SN.Kind = SyntaxStructureKind::TupleExpression; SN.Range = charSourceRangeFromSourceRange(SM, Tup->getSourceRange()); @@ -792,6 +786,9 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { pushStructureNode(SN, NTD); } else if (auto *ED = dyn_cast(D)) { + // Normally bindExtension() would take care of computing the extended + // nominal. It must be done before asking for generic parameters. + ED->computeExtendedNominal(); SyntaxStructureNode SN; setDecl(SN, D); SN.Kind = SyntaxStructureKind::Extension; diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 54130f1605a37..8201d329ca6c5 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -156,8 +156,6 @@ class GenClangType : public CanTypeVisitor { clang::CanQualType visitBuiltinRawPointerType(CanBuiltinRawPointerType type); clang::CanQualType visitBuiltinIntegerType(CanBuiltinIntegerType type); clang::CanQualType visitBuiltinFloatType(CanBuiltinFloatType type); - clang::CanQualType visitBuiltinUnknownObjectType( - CanBuiltinUnknownObjectType type); clang::CanQualType visitArchetypeType(CanArchetypeType type); clang::CanQualType visitSILFunctionType(CanSILFunctionType type); clang::CanQualType visitGenericTypeParamType(CanGenericTypeParamType type); @@ -703,13 +701,6 @@ clang::CanQualType GenClangType::visitBuiltinFloatType( llvm_unreachable("cannot translate floating-point format to C"); } -clang::CanQualType GenClangType::visitBuiltinUnknownObjectType( - CanBuiltinUnknownObjectType type) { - auto &clangCtx = getClangASTContext(); - auto ptrTy = clangCtx.getObjCObjectPointerType(clangCtx.VoidTy); - return clangCtx.getCanonicalType(ptrTy); -} - clang::CanQualType GenClangType::visitArchetypeType(CanArchetypeType type) { // We see these in the case where we invoke an @objc function // through a protocol. diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index dd3a00a63c3f4..89961bea1b469 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2614,7 +2614,7 @@ namespace { case ClassMetadataStrategy::Fixed: { // FIXME: Should this check HasImported instead? auto type = (Target->checkAncestry(AncestryFlags::ObjC) - ? IGM.Context.TheUnknownObjectType + ? IGM.Context.getAnyObjectType() : IGM.Context.TheNativeObjectType); auto wtable = IGM.getAddrOfValueWitnessTable(type); B.add(wtable); @@ -4011,7 +4011,7 @@ namespace { // Without Objective-C interop, foreign classes must still use // Swift native reference counting. auto type = (IGM.ObjCInterop - ? IGM.Context.TheUnknownObjectType + ? IGM.Context.getAnyObjectType() : IGM.Context.TheNativeObjectType); auto wtable = IGM.getAddrOfValueWitnessTable(type); B.add(wtable); diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index 98ae4cfec3b95..ec7d69af9062b 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -184,7 +184,8 @@ llvm::Value *irgen::emitObjCAutoreleaseReturnValue(IRGenFunction &IGF, } namespace { - /// A type-info implementation suitable for Builtin.UnknownObject. + /// A type-info implementation suitable for AnyObject on platforms with ObjC + /// interop. class UnknownTypeInfo : public HeapTypeInfo { public: UnknownTypeInfo(llvm::PointerType *storageType, Size size, @@ -192,7 +193,7 @@ namespace { : HeapTypeInfo(storageType, size, spareBits, align) { } - /// Builtin.UnknownObject requires ObjC reference-counting. + /// AnyObject requires ObjC reference-counting. ReferenceCounting getReferenceCounting() const { return ReferenceCounting::Unknown; } @@ -458,6 +459,7 @@ namespace { case SILDeclRef::Kind::StoredPropertyInitializer: case SILDeclRef::Kind::EnumElement: case SILDeclRef::Kind::GlobalAccessor: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: llvm_unreachable("Method does not have a selector"); case SILDeclRef::Kind::Destroyer: diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 93110ba059c3b..004714c174d79 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -864,7 +864,7 @@ static bool hasDependentTypeWitness( return false; // RESILIENCE: this could be an opaque conformance - return type->hasTypeParameter(); + return type->getCanonicalType()->hasTypeParameter(); }, /*useResolver=*/true)) { return true; diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 7cbc9e684983f..a896e1d5cf57b 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -847,7 +847,14 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder { } void layout() override { - addTypeRef(type, CanGenericSignature()); + if (type->isAnyObject()) { + // AnyObject isn't actually a builtin type; we're emitting it as the old + // Builtin.UnknownObject type for ABI compatibility. + B.addRelativeAddress( + IGM.getAddrOfStringForTypeRef("BO", MangledTypeRefRole::Reflection)); + } else { + addTypeRef(type, CanGenericSignature()); + } B.addInt32(ti->getFixedSize().getValue()); @@ -1251,7 +1258,7 @@ emitAssociatedTypeMetadataRecord(const RootProtocolConformance *conformance) { void IRGenModule::emitBuiltinReflectionMetadata() { if (getSwiftModule()->isStdlibModule()) { BuiltinTypes.insert(Context.TheNativeObjectType); - BuiltinTypes.insert(Context.TheUnknownObjectType); + BuiltinTypes.insert(Context.getAnyObjectType()); BuiltinTypes.insert(Context.TheBridgeObjectType); BuiltinTypes.insert(Context.TheRawPointerType); BuiltinTypes.insert(Context.TheUnsafeValueBufferType); diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index b9d336e2c069d..92a492daa5905 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1788,8 +1788,6 @@ const TypeInfo *TypeConverter::convertType(CanType ty) { } case TypeKind::BuiltinNativeObject: return &getNativeObjectTypeInfo(); - case TypeKind::BuiltinUnknownObject: - return &getUnknownObjectTypeInfo(); case TypeKind::BuiltinBridgeObject: return &getBridgeObjectTypeInfo(); case TypeKind::BuiltinUnsafeValueBuffer: diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp index 95627a9f0a840..05024f6abd84e 100644 --- a/lib/IRGen/GenValueWitness.cpp +++ b/lib/IRGen/GenValueWitness.cpp @@ -1001,7 +1001,7 @@ getAddrOfKnownValueWitnessTable(IRGenModule &IGM, CanType type, case ReferenceCounting::ObjC: case ReferenceCounting::Block: case ReferenceCounting::Unknown: - witnessSurrogate = C.TheUnknownObjectType; + witnessSurrogate = C.getAnyObjectType(); break; case ReferenceCounting::Bridge: witnessSurrogate = C.TheBridgeObjectType; diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 17123e9b5daa0..75812053a56cc 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1207,18 +1207,6 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { break; } - case TypeKind::BuiltinUnknownObject: { - // The builtin opaque Objective-C pointer type. Useful for pushing - // an Objective-C type through swift. - unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); - auto IdTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - MangledName, Scope, File, 0, - llvm::dwarf::DW_LANG_ObjC, 0, 0); - return DBuilder.createPointerType(IdTy, PtrSize, 0, - /* DWARFAddressSpace */ None, - MangledName); - } - case TypeKind::BuiltinNativeObject: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); auto PTy = diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h index 2018dd3738fa8..57125fc7950db 100644 --- a/lib/IRGen/IRGenMangler.h +++ b/lib/IRGen/IRGenMangler.h @@ -80,7 +80,16 @@ class IRGenMangler : public Mangle::ASTMangler { std::string mangleValueWitness(Type type, ValueWitness witness); std::string mangleValueWitnessTable(Type type) { - return mangleTypeSymbol(type, "WV"); + const char * const witnessTableOp = "WV"; + if (type->isAnyObject()) { + // Special-case for AnyObject, whose witness table is under the old name + // Builtin.UnknownObject, even though we don't use that as a Type anymore. + beginMangling(); + appendOperator("BO"); + appendOperator(witnessTableOp); + return finalize(); + } + return mangleTypeSymbol(type, witnessTableOp); } std::string mangleTypeMetadataAccessFunction(Type type) { @@ -382,7 +391,17 @@ class IRGenMangler : public Mangle::ASTMangler { } std::string mangleReflectionBuiltinDescriptor(Type type) { - return mangleTypeSymbol(type, "MB"); + const char * const reflectionDescriptorOp = "MB"; + if (type->isAnyObject()) { + // Special-case for AnyObject, whose reflection descriptor is under the + // old name Builtin.UnknownObject, even though we don't use that as a Type + // anymore. + beginMangling(); + appendOperator("BO"); + appendOperator(reflectionDescriptorOp); + return finalize(); + } + return mangleTypeSymbol(type, reflectionDescriptorOp); } std::string mangleReflectionFieldDescriptor(Type type) { diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 43d53e6e3a369..239c5753e8e4c 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -22,6 +22,7 @@ #include "swift/Basic/Dwarf.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/ClangImporter/ClangImporter.h" +#include "swift/IRGen/IRGenPublic.h" #include "swift/IRGen/Linking.h" #include "swift/Runtime/RuntimeFnWrappersGen.h" #include "swift/Runtime/Config.h" @@ -1366,6 +1367,10 @@ IRGenModule *IRGenerator::getGenModule(SILFunction *f) { return getPrimaryIGM(); } +uint32_t swift::irgen::getSwiftABIVersion() { + return IRGenModule::swiftVersion; +} + llvm::Triple IRGenerator::getEffectiveClangTriple() { auto CI = static_cast( &*SIL.getASTContext().getClangModuleLoader()); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 8d3026c1a7132..c461efdaa65d8 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -3970,8 +3970,7 @@ static bool hasReferenceSemantics(IRGenSILFunction &IGF, return (objType->mayHaveSuperclass() || objType->isClassExistentialType() || objType->is() - || objType->is() - || objType->is()); + || objType->is()); } static llvm::Value *emitIsUnique(IRGenSILFunction &IGF, SILValue operand, @@ -4112,6 +4111,8 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) { if (!Decl) return; + assert(i->getVarInfo() && "alloc_stack without debug info"); + Type Desugared = Decl->getType()->getDesugaredType(); if (Desugared->getClassOrBoundGenericClass() || Desugared->getStructOrBoundGenericStruct()) @@ -4271,6 +4272,9 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { if (!Decl) return; + + assert(i->getVarInfo() && "alloc_box without debug info"); + // FIXME: This is a workaround to not produce local variables for // capture list arguments like "[weak self]". The better solution // would be to require all variables to be described with a diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index c8cbd168f7cf6..63fe8331d7e10 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -1040,18 +1040,23 @@ class LoadableStorageAllocation { }; } // end anonymous namespace -static AllocStackInst *allocate(StructLoweringState &pass, - SILLocation loc, SILType type) { +static AllocStackInst *allocate(StructLoweringState &pass, SILType type) { assert(type.isObject()); // Insert an alloc_stack at the beginning of the function. SILBuilderWithScope allocBuilder(&*pass.F->begin()); - AllocStackInst *alloc = allocBuilder.createAllocStack(loc, type); + // Don't put any variable debug info into the alloc_stack, there will be a + // debug_value_addr insterted later. TODO: It may be more elegant to insert + // the variable info into the alloc_stack instead of additionally generating a + // debug_value_addr. + AllocStackInst *alloc = allocBuilder.createAllocStack( + RegularLocation::getAutoGeneratedLocation(), type); // Insert dealloc_stack at the end(s) of the function. for (TermInst *termInst : pass.returnInsts) { SILBuilderWithScope deallocBuilder(termInst); - deallocBuilder.createDeallocStack(loc, alloc); + deallocBuilder.createDeallocStack( + RegularLocation::getAutoGeneratedLocation(), alloc); } return alloc; @@ -1091,8 +1096,7 @@ void LoadableStorageAllocation::replaceLoadWithCopyAddr( LoadInst *optimizableLoad) { SILValue value = optimizableLoad->getOperand(); - auto allocInstr = allocate(pass, value.getLoc(), - value->getType().getObjectType()); + auto allocInstr = allocate(pass, value->getType().getObjectType()); SILBuilderWithScope outlinedBuilder(optimizableLoad); createOutlinedCopyCall(outlinedBuilder, value, allocInstr, pass); @@ -1214,8 +1218,7 @@ void LoadableStorageAllocation::replaceLoadWithCopyAddrForModifiable( } SILValue value = unoptimizableLoad->getOperand(); - AllocStackInst *alloc = allocate(pass, value.getLoc(), - value->getType().getObjectType()); + AllocStackInst *alloc = allocate(pass, value->getType().getObjectType()); SILBuilderWithScope outlinedBuilder(unoptimizableLoad); createOutlinedCopyCall(outlinedBuilder, value, alloc, pass); @@ -1577,8 +1580,8 @@ void LoadableStorageAllocation::allocateForArg(SILValue value) { SILBuilderWithScope allocBuilder(&*pass.F->begin()->begin(), FirstNonAllocStack); - AllocStackInst *allocInstr = - allocBuilder.createAllocStack(value.getLoc(), value->getType()); + AllocStackInst *allocInstr = allocBuilder.createAllocStack( + RegularLocation::getAutoGeneratedLocation(), value->getType()); LoadInst *loadCopy = nullptr; auto *applyOutlinedCopy = @@ -1604,7 +1607,12 @@ AllocStackInst * LoadableStorageAllocation::allocateForApply(SILInstruction *apply, SILType type) { SILBuilderWithScope allocBuilder(&*pass.F->begin()); - auto *allocInstr = allocBuilder.createAllocStack(apply->getLoc(), type); + SILLocation Loc = apply->getLoc(); + if (dyn_cast_or_null(Loc.getAsASTNode())) + // FIXME: Remove this. This is likely indicative of a bug earlier in the + // pipeline. An apply instruction should not have a VarDecl as location. + Loc = RegularLocation::getAutoGeneratedLocation(); + auto *allocInstr = allocBuilder.createAllocStack(Loc, type); pass.largeLoadableArgs.push_back(allocInstr); pass.allocToApplyRetMap[allocInstr] = apply; @@ -1713,7 +1721,7 @@ static void rewriteUsesOfSscalar(StructLoweringState &pass, static void allocateAndSetForInstResult(StructLoweringState &pass, SILValue instResult, SILInstruction *inst) { - auto alloc = allocate(pass, inst->getLoc(), instResult->getType()); + auto alloc = allocate(pass, instResult->getType()); auto II = inst->getIterator(); ++II; @@ -1726,7 +1734,7 @@ static void allocateAndSetForInstResult(StructLoweringState &pass, static void allocateAndSetForArgument(StructLoweringState &pass, SILArgument *value, SILInstruction *user) { - AllocStackInst *alloc = allocate(pass, user->getLoc(), value->getType()); + AllocStackInst *alloc = allocate(pass, value->getType()); SILLocation loc = user->getLoc(); loc.markAutoGenerated(); @@ -1871,12 +1879,12 @@ static SILValue createCopyOfEnum(StructLoweringState &pass, auto type = value->getType(); if (type.isObject()) { // support for non-address operands / enums - auto *alloc = allocate(pass, orig->getLoc(), type); + auto *alloc = allocate(pass, type); createStoreInit(pass, orig->getIterator(), orig->getLoc(), value, alloc); return alloc; } - auto alloc = allocate(pass, value.getLoc(), type.getObjectType()); + auto alloc = allocate(pass, type.getObjectType()); SILBuilderWithScope copyBuilder(orig); createOutlinedCopyCall(copyBuilder, value, alloc, pass); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index e4b163001f656..397355e79d70a 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -993,12 +993,6 @@ namespace { return emitDirectMetadataRef(type); } - MetadataResponse - visitBuiltinUnknownObjectType(CanBuiltinUnknownObjectType type, - DynamicMetadataRequest request) { - return emitDirectMetadataRef(type); - } - MetadataResponse visitBuiltinUnsafeValueBufferType(CanBuiltinUnsafeValueBufferType type, DynamicMetadataRequest request) { @@ -2517,7 +2511,7 @@ namespace { DynamicMetadataRequest request) { // All function types have the same layout regardless of arguments or // abstraction level. Use the metadata for () -> () for thick functions, - // or Builtin.UnknownObject for block functions. + // or AnyObject for block functions. auto &C = type->getASTContext(); switch (type->getRepresentation()) { case SILFunctionType::Representation::Thin: @@ -2537,8 +2531,8 @@ namespace { CanFunctionType::get({}, C.TheEmptyTupleType), request).getMetadata(); case SILFunctionType::Representation::Block: - // All block types look like Builtin.UnknownObject. - return emitDirectMetadataRef(C.TheUnknownObjectType, request); + // All block types look like AnyObject. + return emitDirectMetadataRef(C.getAnyObjectType(), request); } llvm_unreachable("Not a valid SILFunctionType."); @@ -2667,9 +2661,9 @@ namespace { auto &C = IGF.IGM.Context; if (t == C.TheEmptyTupleType || t == C.TheNativeObjectType - || t == C.TheUnknownObjectType || t == C.TheBridgeObjectType - || t == C.TheRawPointerType) + || t == C.TheRawPointerType + || t == C.getAnyObjectType()) return true; if (auto intTy = dyn_cast(t)) { auto width = intTy->getWidth(); @@ -2747,8 +2741,8 @@ namespace { return emitFromValueWitnessTable( CanFunctionType::get({}, C.TheEmptyTupleType)); case SILFunctionType::Representation::Block: - // All block types look like Builtin.UnknownObject. - return emitFromValueWitnessTable(C.TheUnknownObjectType); + // All block types look like AnyObject. + return emitFromValueWitnessTable(C.getAnyObjectType()); } llvm_unreachable("Not a valid SILFunctionType."); @@ -2791,7 +2785,7 @@ namespace { case ReferenceCounting::ObjC: case ReferenceCounting::Block: case ReferenceCounting::Unknown: - return emitFromValueWitnessTable(IGF.IGM.Context.TheUnknownObjectType); + return emitFromValueWitnessTable(IGF.IGM.Context.getAnyObjectType()); case ReferenceCounting::Bridge: case ReferenceCounting::Error: diff --git a/lib/IRGen/TypeVisitor.h b/lib/IRGen/TypeVisitor.h index 3beec9dca8a0a..e6ccb703ba107 100644 --- a/lib/IRGen/TypeVisitor.h +++ b/lib/IRGen/TypeVisitor.h @@ -48,7 +48,6 @@ class ReferenceTypeVisitor : public CanTypeVisitor { // BuiltinNativeObject // BuiltinBridgeObject - // BuiltinUnknownObject // Class // BoundGenericClass // Protocol diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 5f8a33ee410e3..f01b7e60000ae 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SourceFile.h" +#include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/Parse/ASTGen.cpp b/lib/Parse/ASTGen.cpp index 8ff9a94f7f174..9681134650daa 100644 --- a/lib/Parse/ASTGen.cpp +++ b/lib/Parse/ASTGen.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "swift/Parse/ASTGen.h" +#include "swift/AST/TypeRepr.h" +#include "swift/Basic/SourceManager.h" #include "swift/Basic/SourceManager.h" #include "swift/Parse/CodeCompletionCallbacks.h" @@ -574,8 +576,11 @@ GenericParamList *ASTGen::generate(const GenericParameterClauseSyntax &clause, DeclAttributes attrs; if (auto attrsSyntax = elem.getAttributes()) { - auto attrsLoc = advanceLocBegin(Loc, *attrsSyntax->getFirstToken()); - attrs = getDeclAttributes(attrsLoc); + if (auto firstTok = attrsSyntax->getFirstToken()) { + auto attrsLoc = advanceLocBegin(Loc, *firstTok); + if (hasDeclAttributes(attrsLoc)) + attrs = getDeclAttributes(attrsLoc); + } } Identifier name = Context.getIdentifier(elem.getName().getIdentifierText()); SourceLoc nameLoc = advanceLocBegin(Loc, elem.getName()); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 9ec2aae577909..028f7cc89a0c8 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -16,6 +16,7 @@ #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/TypeRepr.h" #include "swift/Basic/EditorPlaceholder.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/ParsedSyntaxRecorder.h" @@ -1497,8 +1498,8 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { ParsedSyntaxRecorder::makeIdentifierPattern( SyntaxContext->popToken(), *SyntaxContext); ParsedExprSyntax ExprNode = - ParsedSyntaxRecorder::deferUnresolvedPatternExpr(std::move(PatternNode), - *SyntaxContext); + ParsedSyntaxRecorder::makeUnresolvedPatternExpr(std::move(PatternNode), + *SyntaxContext); SyntaxContext->addSyntax(std::move(ExprNode)); return makeParserResult(new (Context) UnresolvedPatternExpr(pattern)); } diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index ee00e32c6aad8..b2edfebb3d10f 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -16,6 +16,7 @@ #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/TypeRepr.h" #include "swift/Parse/ParsedSyntaxBuilders.h" #include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/SyntaxParsingContext.h" @@ -73,12 +74,17 @@ Parser::parseGenericParameterClauseSyntax() { // Parse attributes. // TODO: Implement syntax attribute parsing. - DeclAttributes attrsAST; - parseDeclAttributeList(attrsAST); - auto attrs = SyntaxContext->popIf(); - if (attrs) { - paramBuilder.useAttributes(std::move(*attrs)); - Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); + if (Tok.is(tok::at_sign)) { + SyntaxParsingContext TmpCtxt(SyntaxContext); + TmpCtxt.setTransparent(); + + DeclAttributes attrsAST; + parseDeclAttributeList(attrsAST); + if (!attrsAST.isEmpty()) + Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); + auto attrs = SyntaxContext->popIf(); + if (attrs) + paramBuilder.useAttributes(std::move(*attrs)); } // Parse the name of the parameter. diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 908cedcd5ab27..6a50e1e2f44a0 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Initializer.h" #include "swift/AST/Module.h" #include "swift/AST/SourceFile.h" +#include "swift/AST/TypeRepr.h" #include "swift/Basic/StringExtras.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/ParsedSyntaxRecorder.h" diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index f06ab36b3ad27..80f2f3630427f 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" #include "swift/AST/TypeLoc.h" +#include "swift/AST/TypeRepr.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/SyntaxParsingContext.h" @@ -398,7 +399,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, diagnose(Tok.getLoc(), DiagID) .fixItInsert(ArrowLoc, "throws ") .fixItRemove(Tok.getLoc()); - Throws = consumeTokenSyntax(); + ignoreToken(); } ParserResult SecondHalf = parseType(diag::expected_type_function_result); @@ -991,7 +992,8 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { replacement = "Any"; } else { auto extractText = [&](ParsedTypeSyntax &Type) -> StringRef { - auto SourceRange = Type.getRaw().getDeferredRange(); + auto SourceRange = Type.getRaw() + .getDeferredRange(/*includeTrivia=*/false); return SourceMgr.extractText(SourceRange); }; auto Begin = Protocols.begin(); @@ -1108,18 +1110,15 @@ Parser::TypeResult Parser::parseTypeTupleBody() { // Consume a name. NameLoc = Tok.getLoc(); Name = consumeArgumentLabelSyntax(); - LocalJunk.push_back(Name->copyDeferred()); // If there is a second name, consume it as well. if (Tok.canBeArgumentLabel()) { SecondNameLoc = Tok.getLoc(); SecondName = consumeArgumentLabelSyntax(); - LocalJunk.push_back(SecondName->copyDeferred()); } // Consume the ':'. if ((Colon = consumeTokenSyntaxIf(tok::colon))) { - LocalJunk.push_back(Colon->copyDeferred()); // If we succeed, then we successfully parsed a label. if (Backtracking) Backtracking->cancelBacktrack(); @@ -1136,6 +1135,18 @@ Parser::TypeResult Parser::parseTypeTupleBody() { IsInOutObsoleted = false; } + if (!Backtracking || !Backtracking->willBacktrack()) { + if (Name) + LocalJunk.push_back(Name->copyDeferred()); + if (SecondName) + LocalJunk.push_back(SecondName->copyDeferred()); + if (Colon) + LocalJunk.push_back(Colon->copyDeferred()); + } else if (Backtracking && Backtracking->willBacktrack()) { + Name.reset(); + SecondName.reset(); + assert(!Colon.hasValue()); + } Backtracking.reset(); // Parse the type annotation. diff --git a/lib/Parse/ParsedRawSyntaxRecorder.cpp b/lib/Parse/ParsedRawSyntaxRecorder.cpp index 09e81834ded7e..17ef251a8e3eb 100644 --- a/lib/Parse/ParsedRawSyntaxRecorder.cpp +++ b/lib/Parse/ParsedRawSyntaxRecorder.cpp @@ -53,7 +53,8 @@ ParsedRawSyntaxNode ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) { CharSourceRange range{loc, 0}; OpaqueSyntaxNode n = SPActions->recordMissingToken(tokenKind, loc); - return ParsedRawSyntaxNode{SyntaxKind::Token, tokenKind, range, n}; + return ParsedRawSyntaxNode{SyntaxKind::Token, tokenKind, range, n, + /*isMissing=*/true}; } static ParsedRawSyntaxNode @@ -128,3 +129,21 @@ ParsedRawSyntaxRecorder::lookupNode(size_t lexerOffset, SourceLoc loc, CharSourceRange range{loc, unsigned(length)}; return ParsedRawSyntaxNode{kind, tok::unknown, range, n}; } + +#ifndef NDEBUG +void ParsedRawSyntaxRecorder::verifyElementRanges(ArrayRef elements) { + SourceLoc prevEndLoc; + for (const auto &elem: elements) { + if (elem.isMissing() || elem.isNull()) + continue; + CharSourceRange range = elem.isRecorded() + ? elem.getRecordedRange() + : elem.getDeferredRange(/*includeTrivia=*/true); + if (range.isValid()) { + assert((prevEndLoc.isInvalid() || range.getStart() == prevEndLoc) + && "Non-contiguous child ranges?"); + prevEndLoc = range.getEnd(); + } + } +} +#endif diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 7277a71462b2b..2d574a0598686 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -120,6 +120,10 @@ void Parsed${node.name}Builder::finishLayout(bool deferred) { } % end % end + +#ifndef NDEBUG + ParsedRawSyntaxRecorder::verifyElementRanges(Layout); +#endif % end } diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index 5c5ac75d7a74e..3ffcb36e1bdf9 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -90,23 +90,21 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, % child_params = ', '.join(child_params) % child_move_args = ', '.join(child_move_args) Parsed${node.name} -ParsedSyntaxRecorder::record${node.syntax_kind}(${child_params}, +ParsedSyntaxRecorder::record${node.syntax_kind}(MutableArrayRef layout, ParsedRawSyntaxRecorder &rec) { - ParsedRawSyntaxNode layout[] = { -% for child in node.children: -% if child.is_optional: - ${child.name}.hasValue() ? ${child.name}->takeRaw() : ParsedRawSyntaxNode::null(), -% else: - ${child.name}.takeRaw(), -% end -% end - }; auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); } Parsed${node.name} -ParsedSyntaxRecorder::defer${node.syntax_kind}(${child_params}, SyntaxParsingContext &SPCtx) { +ParsedSyntaxRecorder::defer${node.syntax_kind}(MutableArrayRef layout, SyntaxParsingContext &SPCtx) { + auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); + return Parsed${node.name}(std::move(raw)); +} + +Parsed${node.name} +ParsedSyntaxRecorder::make${node.syntax_kind}(${child_params}, + SyntaxParsingContext &SPCtx) { ParsedRawSyntaxNode layout[] = { % for child in node.children: % if child.is_optional: @@ -116,41 +114,27 @@ ParsedSyntaxRecorder::defer${node.syntax_kind}(${child_params}, SyntaxParsingCon % end % end }; - auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, llvm::makeMutableArrayRef(layout, ${len(node.children)}), SPCtx); - return Parsed${node.name}(std::move(raw)); -} - -Parsed${node.name} -ParsedSyntaxRecorder::make${node.syntax_kind}(${child_params}, - SyntaxParsingContext &SPCtx) { + #ifndef NDEBUG + ParsedRawSyntaxRecorder::verifyElementRanges(layout); + #endif if (SPCtx.shouldDefer()) - return defer${node.syntax_kind}(${child_move_args}, SPCtx); - return record${node.syntax_kind}(${child_move_args}, SPCtx.getRecorder()); + return defer${node.syntax_kind}(layout, SPCtx); + return record${node.syntax_kind}(layout, SPCtx.getRecorder()); } % elif node.is_syntax_collection(): Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}( - MutableArrayRef elements, + MutableArrayRef layout, ParsedRawSyntaxRecorder &rec) { - SmallVector layout; - layout.reserve(elements.size()); - for (auto &element : elements) { - layout.push_back(element.takeRaw()); - } auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); } Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}( - MutableArrayRef elements, + MutableArrayRef layout, SyntaxParsingContext &SPCtx) { - SmallVector layout; - layout.reserve(elements.size()); - for (auto &element : elements) { - layout.push_back(element.takeRaw()); - } auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); return Parsed${node.name}(std::move(raw)); @@ -160,9 +144,17 @@ Parsed${node.name} ParsedSyntaxRecorder::make${node.syntax_kind}( MutableArrayRef elements, SyntaxParsingContext &SPCtx) { + SmallVector layout; + layout.reserve(elements.size()); + for (auto &element : elements) { + layout.push_back(element.takeRaw()); + } + #ifndef NDEBUG + ParsedRawSyntaxRecorder::verifyElementRanges(layout); + #endif if (SPCtx.shouldDefer()) - return defer${node.syntax_kind}(elements, SPCtx); - return record${node.syntax_kind}(elements, SPCtx.getRecorder()); + return defer${node.syntax_kind}(layout, SPCtx); + return record${node.syntax_kind}(layout, SPCtx.getRecorder()); } Parsed${node.name} @@ -180,26 +172,16 @@ ParsedSyntaxRecorder::makeBlank${node.syntax_kind}(SourceLoc loc, % elif node.is_unknown(): Parsed${node.name} ParsedSyntaxRecorder::record${node.syntax_kind}( - MutableArrayRef elements, + MutableArrayRef layout, ParsedRawSyntaxRecorder &rec) { - SmallVector layout; - layout.reserve(elements.size()); - for (auto &element : elements) { - layout.push_back(element.takeRaw()); - } auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout); return Parsed${node.name}(std::move(raw)); } Parsed${node.name} ParsedSyntaxRecorder::defer${node.syntax_kind}( - MutableArrayRef elements, + MutableArrayRef layout, SyntaxParsingContext &SPCtx) { - SmallVector layout; - layout.reserve(elements.size()); - for (auto &element : elements) { - layout.push_back(element.takeRaw()); - } auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx); return Parsed${node.name}(std::move(raw)); } @@ -208,9 +190,17 @@ Parsed${node.name} ParsedSyntaxRecorder::make${node.syntax_kind}( MutableArrayRef elements, SyntaxParsingContext &SPCtx) { + SmallVector layout; + layout.reserve(elements.size()); + for (auto &element : elements) { + layout.push_back(element.takeRaw()); + } + #ifndef NDEBUG + ParsedRawSyntaxRecorder::verifyElementRanges(layout); + #endif if (SPCtx.shouldDefer()) - return defer${node.syntax_kind}(elements, SPCtx); - return record${node.syntax_kind}(elements, SPCtx.getRecorder()); + return defer${node.syntax_kind}(layout, SPCtx); + return record${node.syntax_kind}(layout, SPCtx.getRecorder()); } % end % end diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 8dba5428251ce..3e83587606ec1 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -1626,6 +1626,9 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Result, } else if (!ParseState && Id.str() == "propertyinit") { Kind = SILDeclRef::Kind::StoredPropertyInitializer; ParseState = 1; + } else if (!ParseState && Id.str() == "backinginit") { + Kind = SILDeclRef::Kind::PropertyWrapperBackingInitializer; + ParseState = 1; // SWIFT_ENABLE_TENSORFLOW } else if (ParseState < 3 && Id.str() == "foreign") { IsObjC = true; diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index ef02e490f8b7d..9b264e8665e0c 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -26,8 +26,8 @@ #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/SubstitutionMap.h" -#include "swift/AST/Types.h" #include "swift/AST/TypeRepr.h" +#include "swift/AST/Types.h" #include "swift/Basic/Mangler.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/Demangling/Demangler.h" @@ -491,7 +491,7 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { Result getDynamicTypeAndAddressClassExistential(RemoteAddress object) { - auto pointerval = Reader.readPointerValue(object.getAddressData()); + auto pointerval = Reader.readResolvedPointerValue(object.getAddressData()); if (!pointerval) return getFailure(); auto result = Reader.readMetadataFromInstance(*pointerval); @@ -508,7 +508,7 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { getDynamicTypeAndAddressErrorExistential(RemoteAddress object, bool dereference=true) { if (dereference) { - auto pointerval = Reader.readPointerValue(object.getAddressData()); + auto pointerval = Reader.readResolvedPointerValue(object.getAddressData()); if (!pointerval) return getFailure(); object = RemoteAddress(*pointerval); @@ -531,7 +531,7 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { auto payloadAddress = result->PayloadAddress; if (!result->IsBridgedError && typeResult->getClassOrBoundGenericClass()) { - auto pointerval = Reader.readPointerValue( + auto pointerval = Reader.readResolvedPointerValue( payloadAddress.getAddressData()); if (!pointerval) return getFailure(); @@ -559,7 +559,7 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { // of the reference. auto payloadAddress = result->PayloadAddress; if (typeResult->getClassOrBoundGenericClass()) { - auto pointerval = Reader.readPointerValue( + auto pointerval = Reader.readResolvedPointerValue( payloadAddress.getAddressData()); if (!pointerval) return getFailure(); @@ -578,7 +578,7 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { // 1) Loading a pointer from the input address // 2) Reading it as metadata and resolving the type // 3) Wrapping the resolved type in an existential metatype. - auto pointerval = Reader.readPointerValue(object.getAddressData()); + auto pointerval = Reader.readResolvedPointerValue(object.getAddressData()); if (!pointerval) return getFailure(); auto typeResult = Reader.readTypeFromMetadata(*pointerval); diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index d99561435e2f5..b1e23a36b3f90 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -85,22 +85,22 @@ bool swift::isOwnershipForwardingInst(SILInstruction *i) { // Borrow Introducers //===----------------------------------------------------------------------===// -void BorrowScopeIntroducerKind::print(llvm::raw_ostream &os) const { +void BorrowScopeIntroducingValueKind::print(llvm::raw_ostream &os) const { switch (value) { - case BorrowScopeIntroducerKind::SILFunctionArgument: + case BorrowScopeIntroducingValueKind::SILFunctionArgument: os << "SILFunctionArgument"; return; - case BorrowScopeIntroducerKind::BeginBorrow: + case BorrowScopeIntroducingValueKind::BeginBorrow: os << "BeginBorrowInst"; return; - case BorrowScopeIntroducerKind::LoadBorrow: + case BorrowScopeIntroducingValueKind::LoadBorrow: os << "LoadBorrowInst"; return; } llvm_unreachable("Covered switch isn't covered?!"); } -void BorrowScopeIntroducerKind::dump() const { +void BorrowScopeIntroducingValueKind::dump() const { #ifndef NDEBUG print(llvm::dbgs()); #endif @@ -111,13 +111,13 @@ void BorrowScopeIntroducingValue::getLocalScopeEndingInstructions( assert(isLocalScope() && "Should only call this given a local scope"); switch (kind) { - case BorrowScopeIntroducerKind::SILFunctionArgument: + case BorrowScopeIntroducingValueKind::SILFunctionArgument: llvm_unreachable("Should only call this with a local scope"); - case BorrowScopeIntroducerKind::BeginBorrow: + case BorrowScopeIntroducingValueKind::BeginBorrow: llvm::copy(cast(value)->getEndBorrows(), std::back_inserter(scopeEndingInsts)); return; - case BorrowScopeIntroducerKind::LoadBorrow: + case BorrowScopeIntroducingValueKind::LoadBorrow: llvm::copy(cast(value)->getEndBorrows(), std::back_inserter(scopeEndingInsts)); return; @@ -129,17 +129,17 @@ void BorrowScopeIntroducingValue::visitLocalScopeEndingUses( function_ref visitor) const { assert(isLocalScope() && "Should only call this given a local scope"); switch (kind) { - case BorrowScopeIntroducerKind::SILFunctionArgument: + case BorrowScopeIntroducingValueKind::SILFunctionArgument: llvm_unreachable("Should only call this with a local scope"); - case BorrowScopeIntroducerKind::BeginBorrow: - for (auto *use : cast(value)->getUses()) { + case BorrowScopeIntroducingValueKind::BeginBorrow: + for (auto *use : value->getUses()) { if (isa(use->getUser())) { visitor(use); } } return; - case BorrowScopeIntroducerKind::LoadBorrow: - for (auto *use : cast(value)->getUses()) { + case BorrowScopeIntroducingValueKind::LoadBorrow: + for (auto *use : value->getUses()) { if (isa(use->getUser())) { visitor(use); } @@ -186,7 +186,7 @@ bool swift::getUnderlyingBorrowIntroducingValues( } llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os, - BorrowScopeIntroducerKind kind) { + BorrowScopeIntroducingValueKind kind) { kind.print(os); return os; } diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp index 7e935989476a0..f40d7905fa5b8 100644 --- a/lib/SIL/Projection.cpp +++ b/lib/SIL/Projection.cpp @@ -1514,3 +1514,11 @@ replaceValueUsesWithLeafUses(SILBuilder &Builder, SILLocation Loc, NewNodes.clear(); } } + +void ProjectionTree::getUsers(SmallPtrSetImpl &users) const { + for (auto *node : ProjectionTreeNodes) { + for (auto *op : node->getNonProjUsers()) { + users.insert(op->getUser()); + } + } +} diff --git a/lib/SIL/SILConstants.cpp b/lib/SIL/SILConstants.cpp index 4bd8bcb9b5894..9442912092cb8 100644 --- a/lib/SIL/SILConstants.cpp +++ b/lib/SIL/SILConstants.cpp @@ -101,12 +101,32 @@ void SymbolicValue::print(llvm::raw_ostream &os, unsigned indent) const { case RK_DerivedAddress: { SmallVector accessPath; SymbolicValueMemoryObject *memObject = getAddressValue(accessPath); - os << "Address[" << memObject->getType() << "] "; + os << "address[" << memObject->getType() << "] "; interleave(accessPath.begin(), accessPath.end(), [&](unsigned idx) { os << idx; }, [&]() { os << ", "; }); os << "\n"; break; } + case RK_ArrayStorage: { + CanType elementType; + ArrayRef elements = getStoredElements(elementType); + os << "elements type: " << elementType << " size: " << elements.size(); + switch (elements.size()) { + case 0: + os << " contents []\n"; + return; + default: + os << " contents [\n"; + for (auto elt : elements) + elt.print(os, indent + 2); + os.indent(indent) << "]\n"; + return; + } + } + case RK_Array: { + os << getArrayType() << ": \n"; + getStorageOfArray().print(os, indent); + } } } @@ -138,11 +158,15 @@ SymbolicValue::Kind SymbolicValue::getKind() const { case RK_DirectAddress: case RK_DerivedAddress: return Address; + case RK_ArrayStorage: + return ArrayStorage; + case RK_Array: + return Array; } llvm_unreachable("covered switch"); } -/// Clone this SymbolicValue into the specified ASTContext and return the new +/// Clone this SymbolicValue into the specified allocator and return the new /// version. This only works for valid constants. SymbolicValue SymbolicValue::cloneInto(SymbolicValueAllocator &allocator) const { @@ -169,16 +193,32 @@ SymbolicValue::cloneInto(SymbolicValueAllocator &allocator) const { results.push_back(elt.cloneInto(allocator)); return getAggregate(results, allocator); } - case RK_EnumWithPayload: - return getEnumWithPayload(getEnumValue(), getEnumPayloadValue(), allocator); + case RK_EnumWithPayload: { + return getEnumWithPayload( + getEnumValue(), getEnumPayloadValue().cloneInto(allocator), allocator); + } case RK_DirectAddress: case RK_DerivedAddress: { SmallVector accessPath; auto *memObject = getAddressValue(accessPath); auto *newMemObject = SymbolicValueMemoryObject::create( - memObject->getType(), memObject->getValue(), allocator); + memObject->getType(), memObject->getValue().cloneInto(allocator), + allocator); return getAddress(newMemObject, accessPath, allocator); } + case RK_ArrayStorage: { + CanType elementType; + ArrayRef oldElements = getStoredElements(elementType); + SmallVector clonedElements; + clonedElements.reserve(oldElements.size()); + for (auto elem : oldElements) + clonedElements.push_back(elem.cloneInto(allocator)); + return getSymbolicArrayStorage(clonedElements, elementType, allocator); + } + case RK_Array: { + SymbolicValue clonedStorage = getStorageOfArray().cloneInto(allocator); + return getArray(getArrayType(), clonedStorage, allocator); + } } llvm_unreachable("covered switch"); } @@ -522,6 +562,105 @@ SymbolicValueMemoryObject *SymbolicValue::getAddressValueMemoryObject() const { return value.derivedAddress->memoryObject; } +//===----------------------------------------------------------------------===// +// Arrays +//===----------------------------------------------------------------------===// + +namespace swift { + +/// Representation of the internal storage of an array. This is a container for +/// a sequence of symbolic values corresponding to the elements of an array. +struct SymbolicArrayStorage final + : private llvm::TrailingObjects { + friend class llvm::TrailingObjects; + + const CanType elementType; + + const unsigned numElements; + + static SymbolicArrayStorage *create(ArrayRef elements, + CanType elementType, + SymbolicValueAllocator &allocator) { + auto byteSize = + SymbolicArrayStorage::totalSizeToAlloc(elements.size()); + auto rawMem = allocator.allocate(byteSize, alignof(SymbolicArrayStorage)); + + // Placement initialize the object. + auto *storage = + ::new (rawMem) SymbolicArrayStorage(elementType, elements.size()); + std::uninitialized_copy(elements.begin(), elements.end(), + storage->getTrailingObjects()); + return storage; + } + + /// Return the stored elements. + ArrayRef getElements() const { + return {getTrailingObjects(), numElements}; + } + + // This is used by the llvm::TrailingObjects base class. + size_t numTrailingObjects(OverloadToken) const { + return numElements; + } + +private: + SymbolicArrayStorage() = delete; + SymbolicArrayStorage(const SymbolicArrayStorage &) = delete; + SymbolicArrayStorage(CanType elementType, unsigned numElements) + : elementType(elementType), numElements(numElements) {} +}; +} // namespace swift +// end namespace swift + +SymbolicValue +SymbolicValue::getSymbolicArrayStorage(ArrayRef elements, + CanType elementType, + SymbolicValueAllocator &allocator) { + // TODO: Could compress the empty array representation if there were a reason + // to. + auto *arrayStorage = + SymbolicArrayStorage::create(elements, elementType, allocator); + SymbolicValue result; + result.representationKind = RK_ArrayStorage; + result.value.arrayStorage = arrayStorage; + return result; +} + +ArrayRef +SymbolicValue::getStoredElements(CanType &elementType) const { + assert(getKind() == ArrayStorage); + elementType = value.arrayStorage->elementType; + return value.arrayStorage->getElements(); +} + +SymbolicValue SymbolicValue::getArray(Type arrayType, + SymbolicValue arrayStorage, + SymbolicValueAllocator &allocator) { + assert(arrayStorage.getKind() == ArrayStorage); + SymbolicValue result; + result.representationKind = RK_Array; + result.value.array = + SymbolicValueMemoryObject::create(arrayType, arrayStorage, allocator); + return result; +} + +SymbolicValue +SymbolicValue::getAddressOfArrayElement(SymbolicValueAllocator &allocator, + unsigned index) const { + assert(getKind() == Array); + return SymbolicValue::getAddress(value.array, {index}, allocator); +} + +SymbolicValue SymbolicValue::getStorageOfArray() const { + assert(getKind() == Array); + return value.array->getValue(); +} + +Type SymbolicValue::getArrayType() const { + assert(getKind() == Array); + return value.array->getType(); +} + //===----------------------------------------------------------------------===// // Higher level code //===----------------------------------------------------------------------===// @@ -766,20 +905,29 @@ static SymbolicValue getIndexedElement(SymbolicValue aggregate, if (aggregate.getKind() == SymbolicValue::UninitMemory) return SymbolicValue::getUninitMemory(); - assert(aggregate.getKind() == SymbolicValue::Aggregate && + assert((aggregate.getKind() == SymbolicValue::Aggregate || + aggregate.getKind() == SymbolicValue::ArrayStorage) && "the accessPath is invalid for this type"); unsigned elementNo = accessPath.front(); - SymbolicValue elt = aggregate.getAggregateValue()[elementNo]; + SymbolicValue elt; Type eltType; - if (auto *decl = type->getStructOrBoundGenericStruct()) { - eltType = decl->getStoredProperties()[elementNo]->getType(); - } else if (auto tuple = type->getAs()) { - assert(elementNo < tuple->getNumElements() && "invalid index"); - eltType = tuple->getElement(elementNo).getType(); + + if (aggregate.getKind() == SymbolicValue::ArrayStorage) { + CanType arrayEltTy; + elt = aggregate.getStoredElements(arrayEltTy)[elementNo]; + eltType = arrayEltTy; } else { - llvm_unreachable("the accessPath is invalid for this type"); + elt = aggregate.getAggregateValue()[elementNo]; + if (auto *decl = type->getStructOrBoundGenericStruct()) { + eltType = decl->getStoredProperties()[elementNo]->getType(); + } else if (auto tuple = type->getAs()) { + assert(elementNo < tuple->getNumElements() && "invalid index"); + eltType = tuple->getElement(elementNo).getType(); + } else { + llvm_unreachable("the accessPath is invalid for this type"); + } } return getIndexedElement(elt, accessPath.drop_front(), eltType); @@ -828,20 +976,29 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate, aggregate = SymbolicValue::getAggregate(newElts, allocator); } - assert(aggregate.getKind() == SymbolicValue::Aggregate && + assert((aggregate.getKind() == SymbolicValue::Aggregate || + aggregate.getKind() == SymbolicValue::ArrayStorage) && "the accessPath is invalid for this type"); unsigned elementNo = accessPath.front(); - ArrayRef oldElts = aggregate.getAggregateValue(); + ArrayRef oldElts; Type eltType; - if (auto *decl = type->getStructOrBoundGenericStruct()) { - eltType = decl->getStoredProperties()[elementNo]->getType(); - } else if (auto tuple = type->getAs()) { - assert(elementNo < tuple->getNumElements() && "invalid index"); - eltType = tuple->getElement(elementNo).getType(); + + if (aggregate.getKind() == SymbolicValue::ArrayStorage) { + CanType arrayEltTy; + oldElts = aggregate.getStoredElements(arrayEltTy); + eltType = arrayEltTy; } else { - llvm_unreachable("the accessPath is invalid for this type"); + oldElts = aggregate.getAggregateValue(); + if (auto *decl = type->getStructOrBoundGenericStruct()) { + eltType = decl->getStoredProperties()[elementNo]->getType(); + } else if (auto tuple = type->getAs()) { + assert(elementNo < tuple->getNumElements() && "invalid index"); + eltType = tuple->getElement(elementNo).getType(); + } else { + llvm_unreachable("the accessPath is invalid for this type"); + } } // Update the indexed element of the aggregate. @@ -850,7 +1007,11 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate, setIndexedElement(newElts[elementNo], accessPath.drop_front(), newElement, eltType, allocator); - aggregate = SymbolicValue::getAggregate(newElts, allocator); + if (aggregate.getKind() == SymbolicValue::Aggregate) + return SymbolicValue::getAggregate(newElts, allocator); + + return aggregate = SymbolicValue::getSymbolicArrayStorage( + newElts, eltType->getCanonicalType(), allocator); return aggregate; } diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp index d74dc6062c3e7..c68048314f644 100644 --- a/lib/SIL/SILDeclRef.cpp +++ b/lib/SIL/SILDeclRef.cpp @@ -319,6 +319,13 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { limit = Limit::NeverPublic; } + // The property wrapper backing initializer is never public for resilient + // properties. + if (kind == SILDeclRef::Kind::PropertyWrapperBackingInitializer) { + if (cast(d)->isResilient()) + limit = Limit::NeverPublic; + } + // Stored property initializers get the linkage of their containing type. if (isStoredPropertyInitializer()) { // Three cases: @@ -808,6 +815,11 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const { case SILDeclRef::Kind::StoredPropertyInitializer: assert(!isCurried); return mangler.mangleInitializerEntity(cast(getDecl()), SKind); + + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + assert(!isCurried); + return mangler.mangleBackingInitializerEntity(cast(getDecl()), + SKind); } llvm_unreachable("bad entity kind!"); diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 00ce447a3e1ca..b4eb331229fcc 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -1524,6 +1524,7 @@ static CanSILFunctionType getNativeSILFunctionType( case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: { auto conv = DefaultConventions(NormalParameterConvention::Guaranteed); @@ -2051,6 +2052,7 @@ static ObjCSelectorFamily getObjCSelectorFamily(SILDeclRef c) { case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: llvm_unreachable("Unexpected Kind of foreign SILDeclRef"); } @@ -2281,6 +2283,7 @@ TypeConverter::getDeclRefRepresentation(SILDeclRef c) { case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: return SILFunctionTypeRepresentation::Thin; case SILDeclRef::Kind::Func: @@ -2855,6 +2858,7 @@ static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: return nullptr; diff --git a/lib/SIL/SILLocation.cpp b/lib/SIL/SILLocation.cpp index 015c415583e58..cae0c1acc3626 100644 --- a/lib/SIL/SILLocation.cpp +++ b/lib/SIL/SILLocation.cpp @@ -223,6 +223,11 @@ MandatoryInlinedLocation::getMandatoryInlinedLocation(SILLocation L) { llvm_unreachable("Cannot construct Inlined loc from the given location."); } +MandatoryInlinedLocation MandatoryInlinedLocation::getAutoGeneratedLocation() { + return getMandatoryInlinedLocation( + RegularLocation::getAutoGeneratedLocation()); +} + CleanupLocation CleanupLocation::get(SILLocation L) { if (Expr *E = L.getAsASTNode()) return CleanupLocation(E, L.getSpecialFlags()); diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp index a5105483c7f09..c4b19b0422e64 100644 --- a/lib/SIL/SILOwnershipVerifier.cpp +++ b/lib/SIL/SILOwnershipVerifier.cpp @@ -278,14 +278,10 @@ bool SILValueOwnershipChecker::gatherUsers( // For correctness reasons we use indices to make sure that we can // append to NonLifetimeEndingUsers without needing to deal with // iterator invalidation. - for (unsigned i : indices(nonLifetimeEndingUsers)) { - if (auto *bbi = dyn_cast( - nonLifetimeEndingUsers[i]->getUser())) { - for (auto *use : bbi->getUses()) { - if (isa(use->getUser())) { - implicitRegularUsers.push_back(use); - } - } + for (auto *op : nonLifetimeEndingUsers) { + if (auto scopedOperand = BorrowScopeOperand::get(op)) { + scopedOperand->visitEndScopeInstructions( + [&](Operand *op) { implicitRegularUsers.push_back(op); }); } } } diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 9e3255d3b3bc3..13cf14af620b9 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -333,6 +333,9 @@ void SILDeclRef::print(raw_ostream &OS) const { case SILDeclRef::Kind::StoredPropertyInitializer: OS << "!propertyinit"; break; + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + OS << "!backinginit"; + break; } auto uncurryLevel = getParameterListCount() - 1; diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp index be1cada7c67c8..54fd9401e7d26 100644 --- a/lib/SIL/SILType.cpp +++ b/lib/SIL/SILType.cpp @@ -38,10 +38,6 @@ SILType SILType::getBridgeObjectType(const ASTContext &C) { return SILType(C.TheBridgeObjectType, SILValueCategory::Object); } -SILType SILType::getUnknownObjectType(const ASTContext &C) { - return getPrimitiveObjectType(C.TheUnknownObjectType); -} - SILType SILType::getRawPointerType(const ASTContext &C) { return getPrimitiveObjectType(C.TheRawPointerType); } @@ -216,8 +212,6 @@ bool SILType::isHeapObjectReferenceType() const { return true; if (Ty->isEqual(C.TheBridgeObjectType)) return true; - if (Ty->isEqual(C.TheUnknownObjectType)) - return true; if (is()) return true; return false; diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 2f100b592f80a..b5946c843eb72 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -215,7 +215,6 @@ namespace { IMPL(BuiltinRawPointer, Trivial) IMPL(BuiltinNativeObject, Reference) IMPL(BuiltinBridgeObject, Reference) - IMPL(BuiltinUnknownObject, Reference) IMPL(BuiltinVector, Trivial) IMPL(SILToken, Trivial) IMPL(Class, Reference) @@ -330,7 +329,7 @@ namespace { return getConcreteReferenceStorageReferent(bound->getCanonicalType()); } - return TC.Context.TheUnknownObjectType; + return TC.Context.getAnyObjectType(); } return type; @@ -1912,6 +1911,27 @@ static CanAnyFunctionType getStoredPropertyInitializerInterfaceType( {}, resultTy); } +/// Get the type of a property wrapper backing initializer, +/// (property-type) -> backing-type. +static CanAnyFunctionType getPropertyWrapperBackingInitializerInterfaceType( + TypeConverter &TC, + VarDecl *VD) { + CanType resultType = + VD->getPropertyWrapperBackingPropertyType()->getCanonicalType(); + + auto *DC = VD->getInnermostDeclContext(); + CanType inputType = + VD->getParentPattern()->getType()->mapTypeOutOfContext() + ->getCanonicalType(); + + auto sig = DC->getGenericSignatureOfContext(); + + AnyFunctionType::Param param( + inputType, Identifier(), + ParameterTypeFlags().withValueOwnership(ValueOwnership::Owned)); + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), {param}, + resultType); +} /// Get the type of a destructor function. static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, bool isDeallocating, @@ -2057,6 +2077,9 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { return getDefaultArgGeneratorInterfaceType(c); case SILDeclRef::Kind::StoredPropertyInitializer: return getStoredPropertyInitializerInterfaceType(cast(vd)); + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: + return getPropertyWrapperBackingInitializerInterfaceType(*this, + cast(vd)); case SILDeclRef::Kind::IVarInitializer: return getIVarInitDestroyerInterfaceType(cast(vd), c.isForeign, false); @@ -2095,6 +2118,7 @@ TypeConverter::getConstantGenericSignature(SILDeclRef c) { case SILDeclRef::Kind::EnumElement: case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: return vd->getDeclContext()->getGenericSignatureOfContext(); } diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index bfc831c0376de..23fd18d3379b5 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1226,6 +1226,23 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) { }); } +void SILGenModule:: +emitPropertyWrapperBackingInitializer(VarDecl *var) { + SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperBackingInitializer); + emitOrDelayFunction(*this, constant, [this, constant, var](SILFunction *f) { + preEmitFunction(constant, var, f, var); + PrettyStackTraceSILFunction X( + "silgen emitPropertyWrapperBackingInitializer", f); + f->createProfiler(var, constant, ForDefinition); + auto varDC = var->getInnermostDeclContext(); + auto wrapperInfo = var->getPropertyWrapperBackingPropertyInfo(); + assert(wrapperInfo.initializeFromOriginal); + SILGenFunction SGF(*this, *f, varDC); + SGF.emitGeneratorFunction(constant, wrapperInfo.initializeFromOriginal); + postEmitFunction(constant, f); + }); +} + SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, PatternBindingDecl *binding, unsigned pbdEntry) { @@ -1738,9 +1755,13 @@ void SILGenModule::emitSourceFile(SourceFile *sf) { visit(D); } - for (Decl *D : sf->LocalTypeDecls) { - FrontendStatsTracer StatsTracer(getASTContext().Stats, "SILgen-tydecl", D); - visit(D); + for (TypeDecl *TD : sf->LocalTypeDecls) { + FrontendStatsTracer StatsTracer(getASTContext().Stats, "SILgen-tydecl", TD); + // FIXME: Delayed parsing would prevent these types from being added to the + // module in the first place. + if (TD->getDeclContext()->getInnermostSkippedFunctionContext()) + continue; + visit(TD); } } diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 4ff76c43346c2..2371f6bc97de3 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -264,6 +264,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Emits the stored property initializer for the given pattern. void emitStoredPropertyInitialization(PatternBindingDecl *pd, unsigned i); + /// Emits the backing initializer for a property with an attached wrapper. + void emitPropertyWrapperBackingInitializer(VarDecl *var); + /// Emits default argument generators for the given parameter list. void emitDefaultArgGenerators(SILDeclRef::Loc decl, ParameterList *paramList); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index f959d492c5e01..e52bb71d52532 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -5006,30 +5006,6 @@ RValue SILGenFunction::emitApplyMethod(SILLocation loc, ConcreteDeclRef declRef, return emission.apply(C); } -RValue SILGenFunction::emitApplyPropertyWrapperAllocator(SILLocation loc, - SubstitutionMap subs, - SILDeclRef ctorRef, - Type wrapperTy, - CanAnyFunctionType funcTy) { - Callee callee = Callee::forDirect(*this, ctorRef, subs, loc); - - MetatypeType *MTty = MetatypeType::get(wrapperTy); - auto metatypeVal = B.createMetatype(loc, getLoweredType(MTty)); - ManagedValue mtManagedVal = ManagedValue::forUnmanaged(metatypeVal); - RValue metatypeRVal(*this, loc, MTty->getCanonicalType(), mtManagedVal); - - ArgumentSource ArgSrc(loc, std::move(metatypeRVal)); - FormalEvaluationScope writebacks(*this); - CallEmission emission(*this, std::move(callee), std::move(writebacks)); - - AnyFunctionType::Param selfParam((Type(MTty)), Identifier(), - ParameterTypeFlags()); - emission.addSelfParam(loc, std::move(ArgSrc), selfParam, funcTy.getResult()); - - RValue RV = emission.apply(); - return RV; -} - /// Emit a literal that applies the various initializers. RValue SILGenFunction::emitLiteral(LiteralExpr *literal, SGFContext C) { ConcreteDeclRef builtinInit; diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index a9cbe49fb156f..6c31bc3fe9c07 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -99,33 +99,24 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, } /// If the field has a property wrapper for which we will need to call the -/// wrapper type's init(wrapperValue:), set up that evaluation and call the -/// \c body with the expression to form the property wrapper instance from -/// the initial value type. -/// -/// \returns true if this was such a wrapper, \c false otherwise. -static bool maybeEmitPropertyWrapperInitFromValue( +/// wrapper type's init(wrappedValue:, ...), call the function that performs +/// that initialization and return the result. Otherwise, return \c arg. +static RValue maybeEmitPropertyWrapperInitFromValue( SILGenFunction &SGF, SILLocation loc, VarDecl *field, - RValue &&arg, - llvm::function_ref body) { + RValue &&arg) { auto originalProperty = field->getOriginalWrappedProperty(); if (!originalProperty || !originalProperty->isPropertyMemberwiseInitializedWithWrappedType()) - return false; + return std::move(arg); auto wrapperInfo = originalProperty->getPropertyWrapperBackingPropertyInfo(); if (!wrapperInfo || !wrapperInfo.initializeFromOriginal) - return false; + return std::move(arg); - SILGenFunction::OpaqueValueRAII opaqueValue( - SGF, - wrapperInfo.underlyingValue, - std::move(arg).getAsSingleValue(SGF, loc)); - - body(wrapperInfo.initializeFromOriginal); - return true; + return SGF.emitApplyOfPropertyWrapperBackingInitializer(loc, originalProperty, + std::move(arg)); } static void emitImplicitValueConstructor(SILGenFunction &SGF, @@ -183,13 +174,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, "number of args does not match number of fields"); (void)eltEnd; FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); - if (!maybeEmitPropertyWrapperInitFromValue( - SGF, Loc, field, std::move(*elti), - [&](Expr *expr) { - SGF.emitExprInto(expr, init.get()); - })) { - std::move(*elti).forwardInto(SGF, Loc, init.get()); - } + maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, std::move(*elti)) + .forwardInto(SGF, Loc, init.get()); ++elti; } else { #ifndef NDEBUG @@ -221,14 +207,9 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); assert(elti != eltEnd && "number of args does not match number of fields"); (void)eltEnd; - if (!maybeEmitPropertyWrapperInitFromValue( - SGF, Loc, field, std::move(*elti), - [&](Expr *expr) { - v = SGF.emitRValue(expr) - .forwardAsSingleStorageValue(SGF, fieldTy, Loc); - })) { - v = std::move(*elti).forwardAsSingleStorageValue(SGF, fieldTy, Loc); - } + v = maybeEmitPropertyWrapperInitFromValue( + SGF, Loc, field, std::move(*elti)) + .forwardAsSingleStorageValue(SGF, fieldTy, Loc); ++elti; } else { // Otherwise, use its initializer. @@ -982,11 +963,8 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc, auto originalVar = singleVar->getOriginalWrappedProperty(); if (originalVar && originalVar->isPropertyWrapperInitializedWithInitialValue()) { - (void)maybeEmitPropertyWrapperInitFromValue( - *this, init, singleVar, std::move(result), - [&](Expr *expr) { - result = emitRValue(expr); - }); + result = maybeEmitPropertyWrapperInitFromValue( + *this, init, singleVar, std::move(result)); } } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 1a9c2ed71b91a..8597611e67854 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2244,6 +2244,46 @@ RValue SILGenFunction::emitApplyOfStoredPropertyInitializer( subs, {}, calleeTypeInfo, ApplyOptions::None, C); } +RValue SILGenFunction::emitApplyOfPropertyWrapperBackingInitializer( + SILLocation loc, + VarDecl *var, + RValue &&originalValue, + SGFContext C) { + SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperBackingInitializer); + auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc, constant)); + auto fnType = fnRef.getType().castTo(); + + SubstitutionMap subs; + auto varDC = var->getInnermostDeclContext(); + if (auto genericSig = varDC->getGenericSignatureOfContext()) { + subs = SubstitutionMap::get( + genericSig, + [&](SubstitutableType *type) { + if (auto gp = type->getAs()) { + return F.mapTypeIntoContext(gp); + } + + return Type(type); + }, + LookUpConformanceInModule(varDC->getParentModule())); + } + + auto substFnType = fnType->substGenericArgs(SGM.M, subs); + + CanType resultType = + F.mapTypeIntoContext(var->getPropertyWrapperBackingPropertyType()) + ->getCanonicalType(); + AbstractionPattern origResultType(resultType); + CalleeTypeInfo calleeTypeInfo(substFnType, origResultType, resultType); + ResultPlanPtr resultPlan = + ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, C); + ArgumentScope argScope(*this, loc); + SmallVector args; + std::move(originalValue).getAll(args); + return emitApply(std::move(resultPlan), std::move(argScope), loc, fnRef, subs, + args, calleeTypeInfo, ApplyOptions::None, C); +} + RValue RValueEmitter::visitDestructureTupleExpr(DestructureTupleExpr *E, SGFContext C) { // Emit the sub-expression tuple and destructure it into elements. diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 65bed08759832..00833515db76c 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILProfiler.h" @@ -127,6 +128,7 @@ DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) { case SILDeclRef::Kind::DefaultArgGenerator: return getMagicFunctionName(cast(ref.getDecl())); case SILDeclRef::Kind::StoredPropertyInitializer: + case SILDeclRef::Kind::PropertyWrapperBackingInitializer: return getMagicFunctionName(cast(ref.getDecl())->getDeclContext()); case SILDeclRef::Kind::IVarInitializer: return getMagicFunctionName(cast(ref.getDecl())); @@ -666,6 +668,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value, bool EmitProfilerIncrement) { + auto *dc = function.getDecl()->getInnermostDeclContext(); MagicFunctionName = SILGenModule::getMagicFunctionName(function); RegularLocation Loc(value); @@ -684,18 +687,52 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value, } } + // For a property wrapper backing initializer, form a parameter list + // containing the wrapped value. + ParameterList *params = nullptr; + if (function.kind == SILDeclRef::Kind::PropertyWrapperBackingInitializer) { + auto &ctx = getASTContext(); + auto param = new (ctx) ParamDecl(ParamDecl::Specifier::Owned, + SourceLoc(), SourceLoc(), + ctx.getIdentifier("$input_value"), + SourceLoc(), + ctx.getIdentifier("$input_value"), + dc); + param->setInterfaceType(function.getDecl()->getInterfaceType()); + + params = ParameterList::create(ctx, SourceLoc(), {param}, SourceLoc()); + } + CaptureInfo captureInfo; if (function.getAnyFunctionRef()) captureInfo = SGM.M.Types.getLoweredLocalCaptures(function); - auto *dc = function.getDecl()->getInnermostDeclContext(); auto interfaceType = value->getType()->mapTypeOutOfContext(); - emitProlog(captureInfo, /*paramList=*/nullptr, /*selfParam=*/nullptr, + emitProlog(captureInfo, params, /*selfParam=*/nullptr, dc, interfaceType, /*throws=*/false, SourceLoc()); if (EmitProfilerIncrement) emitProfilerIncrement(value); prepareEpilog(value->getType(), false, CleanupLocation::get(Loc)); - emitReturnExpr(Loc, value); + + { + llvm::Optional opaqueValue; + + // For a property wrapper backing initializer, bind the opaque value used + // in the initializer expression to the given parameter. + if (function.kind == SILDeclRef::Kind::PropertyWrapperBackingInitializer) { + auto var = cast(function.getDecl()); + auto wrappedInfo = var->getPropertyWrapperBackingPropertyInfo(); + auto param = params->get(0); + opaqueValue.emplace(*this, wrappedInfo.underlyingValue, + maybeEmitValueOfLocalVarDecl(param)); + + assert(value == wrappedInfo.initializeFromOriginal); + } + + emitReturnExpr(Loc, value); + } + emitEpilog(Loc); + mergeCleanupBlocks(); } void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) { diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 26e036368f4b3..8d5f04d029532 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -1460,6 +1460,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction AbstractionPattern origResultType, SGFContext C); + RValue emitApplyOfPropertyWrapperBackingInitializer( + SILLocation loc, + VarDecl *var, + RValue &&originalValue, + SGFContext C = SGFContext()); + /// A convenience method for emitApply that just handles monomorphic /// applications. RValue emitMonomorphicApply(SILLocation loc, @@ -1486,12 +1492,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction ArgumentSource &&self, PreparedArguments &&args, SGFContext C); - RValue emitApplyPropertyWrapperAllocator(SILLocation loc, - SubstitutionMap subs, - SILDeclRef ctorRef, - Type wrapperTy, - CanAnyFunctionType funcTy); - CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn, SubstitutionMap subs, ArrayRef args, CanSILFunctionType substFnType, diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 5849093e0314b..5b5d52ab93445 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -1295,29 +1295,26 @@ namespace { bool hasPropertyWrapper() const { if (auto *VD = dyn_cast(Storage)) { - // FIXME: Handle composition of property wrappers. - if (VD->getAttachedPropertyWrappers().size() == 1) { - auto wrapperInfo = VD->getAttachedPropertyWrapperTypeInfo(0); - - // If there is no init(wrapperValue:), we cannot rewrite an - // assignment into an initialization. - if (!wrapperInfo.wrappedValueInit) - return false; - - // If we have a nonmutating setter on a value type, the call - // captures all of 'self' and we cannot rewrite an assignment - // into an initialization. - if (!VD->isSetterMutating() && - VD->getDeclContext()->getSelfNominalTypeDecl() && - VD->isInstanceMember() && - !VD->getDeclContext()->getDeclaredInterfaceType() - ->hasReferenceSemantics()) { - return false; - } - - return true; + // If this is not a wrapper property that can be initialized from + // a value of the wrapped type, we can't perform the initialization. + auto wrapperInfo = VD->getPropertyWrapperBackingPropertyInfo(); + if (!wrapperInfo.initializeFromOriginal) + return false; + + // If we have a nonmutating setter on a value type, the call + // captures all of 'self' and we cannot rewrite an assignment + // into an initialization. + if (!VD->isSetterMutating() && + VD->getDeclContext()->getSelfNominalTypeDecl() && + VD->isInstanceMember() && + !VD->getDeclContext()->getDeclaredInterfaceType() + ->hasReferenceSemantics()) { + return false; } + + return true; } + return false; } @@ -1404,31 +1401,36 @@ namespace { proj = std::move(SEC).project(SGF, loc, base); } - // Create the allocating initializer function. It captures the metadata. - // FIXME: Composition. - assert(field->getAttachedPropertyWrappers().size() == 1); - auto wrapperInfo = field->getAttachedPropertyWrapperTypeInfo(0); - auto ctor = wrapperInfo.wrappedValueInit; - SubstitutionMap subs = ValType->getMemberSubstitutionMap( - SGF.getModule().getSwiftModule(), ctor); - - Type ity = ctor->getInterfaceType(); - AnyFunctionType *substIty = - ity.subst(subs)->getCanonicalType()->castTo(); - - auto initRef = SILDeclRef(ctor, SILDeclRef::Kind::Allocator) - .asForeign(requiresForeignEntryPoint(ctor)); - RValue initFuncRV = - SGF.emitApplyPropertyWrapperAllocator(loc, subs,initRef, - ValType, - CanAnyFunctionType(substIty)); - ManagedValue initFn = std::move(initFuncRV).getAsSingleValue(SGF, loc); + // The property wrapper backing initializer forms an instance of + // the backing storage type from a wrapped value. + SILDeclRef initConstant( + field, SILDeclRef::Kind::PropertyWrapperBackingInitializer); + SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant); + + SubstitutionMap initSubs; + if (auto genericSig = field->getInnermostDeclContext() + ->getGenericSignatureOfContext()) { + initSubs = SubstitutionMap::get( + genericSig, + [&](SubstitutableType *type) { + if (auto gp = type->getAs()) { + return SGF.F.mapTypeIntoContext(gp); + } + + return Type(type); + }, + LookUpConformanceInModule(SGF.SGM.M.getSwiftModule())); + } + + PartialApplyInst *initPAI = + SGF.B.createPartialApply(loc, initFRef, + initSubs, ArrayRef(), + ParameterConvention::Direct_Guaranteed); + ManagedValue initFn = SGF.emitManagedRValueWithCleanup(initPAI); // Create the allocating setter function. It captures the base address. auto setterInfo = SGF.getConstantInfo(setter); SILValue setterFRef = SGF.emitGlobalFunctionRef(loc, setter, setterInfo); - auto setterSubs = SGF.getFunction().getForwardingSubstitutionMap(); - CanSILFunctionType setterTy = setterFRef->getType().castTo(); SILFunctionConventions setterConv(setterTy, SGF.SGM.M); @@ -1442,7 +1444,7 @@ namespace { PartialApplyInst *setterPAI = SGF.B.createPartialApply(loc, setterFRef, - setterSubs, { capturedBase }, + Substitutions, { capturedBase }, ParameterConvention::Direct_Guaranteed); ManagedValue setterFn = SGF.emitManagedRValueWithCleanup(setterPAI); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 656ad9cdbf33c..3f0d8903b78c2 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -547,4 +547,3 @@ uint16_t SILGenFunction::emitProlog(ParameterList *paramList, return ArgNo; } - diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 7c8055dce9beb..65d32bbb75cfa 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -25,6 +25,7 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/PropertyWrappers.h" #include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeMemberVisitor.h" @@ -1074,6 +1075,14 @@ class SILGenType : public TypeMemberVisitor { return; } + // If this variable has an attached property wrapper with an initialization + // function, emit the backing initializer function. + if (auto wrapperInfo = vd->getPropertyWrapperBackingPropertyInfo()) { + if (wrapperInfo.initializeFromOriginal && !vd->isStatic()) { + SGM.emitPropertyWrapperBackingInitializer(vd); + } + } + visitAbstractStorageDecl(vd); } diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index 832fd5d38545d..acbd467d37419 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -463,8 +463,7 @@ static bool typedAccessTBAAMayAlias(SILType LTy, SILType RTy, // The Builtin reference types can alias any class instance. if (LTyClass) { - if (RTy.is() || - RTy.is() || + if (RTy.is() || RTy.is()) { return true; } diff --git a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp index ce0c4c70dee23..c2894f1072532 100644 --- a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp @@ -33,7 +33,9 @@ CallerAnalysis::FunctionInfo::FunctionInfo(SILFunction *f) // TODO: Make this more aggressive by considering // final/visibility/etc. mayHaveIndirectCallers(f->getDynamicallyReplacedFunction() || - canBeCalledIndirectly(f->getRepresentation())) {} + canBeCalledIndirectly(f->getRepresentation())), + mayHaveExternalCallers(f->isPossiblyUsedExternally() || + f->isAvailableExternally()) {} //===----------------------------------------------------------------------===// // CallerAnalysis::ApplySiteFinderVisitor diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ArgumentExplosionTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ArgumentExplosionTransform.cpp index 21a3ca467e497..37038e08da81e 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ArgumentExplosionTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ArgumentExplosionTransform.cpp @@ -9,6 +9,15 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file contains an implementation of the partial dead argument +/// elimination optimization. We do this to attempt to remove non-trivial +/// arguments of callees to eliminate lifetime constraints of a large argument +/// on values in the caller. +/// +//===----------------------------------------------------------------------===// #define DEBUG_TYPE "fso-argument-explosion-transform" #include "FunctionSignatureOpts.h" @@ -25,43 +34,282 @@ static llvm::cl::opt FSODisableArgExplosion( // Utility //===----------------------------------------------------------------------===// +/// Whether the known-to-date upper bound on the live leaf count is high enough +/// so that argument explosion is possible. +static bool +mayExplodeGivenLiveLeafCountUpperBound(unsigned knownLiveLeafCountUpperBound) { + return knownLiveLeafCountUpperBound > 0; +} + +static unsigned maxExplosionSizeWhenSpecializationWillIntroduceThunk( + bool willSpecializationIntroduceThunk) { + // 3 is the heuristic max explosion size for a single argument when the + // specializing the function will introduce a thunk. If specializing the + // function may not introduce a thunk, then we rely on the maximum size + // imposed by shouldExpand. + return willSpecializationIntroduceThunk ? 3 : UINT_MAX; +} + +static bool shouldExplode(unsigned knownLiveLeafCountUpperBound, + bool hasKnownDeadLeaves, + bool hasKnownDeadNontrivialLeaves, + bool willSpecializationIntroduceThunk) { + unsigned maxExplosionSize = + maxExplosionSizeWhenSpecializationWillIntroduceThunk( + /*willSpecializationIntroduceThunk=*/ + willSpecializationIntroduceThunk); + bool isLiveLeafCountInExplodableRange = + mayExplodeGivenLiveLeafCountUpperBound(knownLiveLeafCountUpperBound) && + (knownLiveLeafCountUpperBound <= maxExplosionSize); + bool hasKnownDeadRelevantLeaves = willSpecializationIntroduceThunk + ? hasKnownDeadNontrivialLeaves + : hasKnownDeadLeaves; + return isLiveLeafCountInExplodableRange && hasKnownDeadRelevantLeaves; +} + /// Return true if it's both legal and a good idea to explode this argument. -static bool shouldExplode(ArgumentDescriptor &argDesc, - ConsumedArgToEpilogueReleaseMatcher &ERM) { - // We cannot optimize the argument. - if (!argDesc.canOptimizeLiveArg()) +/// +/// Our main interest here is to expose more opportunities for ARC. This means +/// that we are not interested in exploding (and partially DCEing) structs in +/// the following cases: +/// +/// 1. Completely dead arguments. This is handled by dead argument elimination. +/// +/// 2. Structs with many live leaf nodes. Our heuristic is to explode if there +/// are only 1-3 live leaf nodes for specializations and 1-6 live leaf nodes +/// (in fact, the number specified in shouldExpand). Otherwise again we run +/// into register pressure/spilling issues. +/// TODO: Improve the 1-3 heuristic by having FSO consider the total +/// resultant argument count. Currently, there is no consideration of +/// that, meaning we could end up with argument exploding even in the +/// case of long argument lists where it isn't beneficial. +/// +/// Perform argument exploding if one of the following sets of conditions hold: +/// +/// 1. a. The live leaf count is less than or equal to 3. +/// b. There is a dead non-trivial leaf. +/// 2. a. The live leaf count is less than or equal to 6. +/// b. There is a dead trivial leaf. +/// c. Specializing the function will not result in a thunk. +static bool +shouldExplode(FunctionSignatureTransformDescriptor &transformDesc, + ArgumentDescriptor &argDesc, + ConsumedArgToEpilogueReleaseMatcher &epilogueReleaseMatcher) { + // The method is structured as follows: + // + // First, do some basic checks and exit early. + // Then in three steps of increasing complexity, calculate data which could + // permit the heuristic to decide to explode the argument. These steps + // provide information of increasing expense and fidelity. Checking whether + // the heuristic allows explosion after each step unnecessary work to be + // avoided. + // + // In a bit more detail: + // + // 1) Do some basic checks and exit early, returning false. + // - that we can optimize the argument at all + // - that the argument has more than a single leaf node + // - that the module permits the type to be expanded + // 2) Gather some basic leaf counts. + // - calculate the unmodified (unmodified that is by the results of the + // owned-to-guaranteed transformation) live leaf count + // - calculate the total list of leaf types to obtain the total leaf count + // 3) Check whether the heuristic allows the argument to be exploded using + // only potentially-trivial leaf counts. At this point it is certainly not + // known that there are dead non-trivial leaves, so exiting early here + // is only possible if specializing the function will not result in a + // thunk. + // 4) Gather the counts of non-trivial leaves. + // - calculate the count of total non-trivial leaves by filtering the total + // list of leaf types from step 2) according to whether leaf is trivial + // - calculate an upper bound (upper bound because it doesn't consider the + // results of the owned-to-guaranteed transformation) on the count of + // live non-trivial leaves + // 5) Check whether the heuristic allows the argument to be exploded using the + // upper bound on live non-trivial leaves. + // 6) Dial in the upper bounds calculated in steps 2) and 4) by compensating + // for the effects of the owned-to-guaranteed transformation. + // 7) Check whether the heuristic allows the argument to be exploded using the + // actual count of live leaves, both trivial and non-trivial. + + // No passes can optimize this argument, so just bail. + if (!argDesc.canOptimizeLiveArg()) { + LLVM_DEBUG(llvm::dbgs() + << "The argument is of a type that cannot be exploded."); return false; + } - // See if the projection tree consists of potentially multiple levels of - // structs containing one field. In such a case, there is no point in - // exploding the argument. + // If the argument is a singleton, it will not be exploded. // - // Also, in case of a type can not be exploded, e.g an enum, we treat it - // as a singleton. - if (argDesc.ProjTree.isSingleton()) + // Explosion makes sense only if some but not all of the leaves are live. + // + // Note that ProjectionTree::isSingleton returns true for enums since they are + // sums and not products and so only have a single top-level node. + if (argDesc.ProjTree.isSingleton()) { + LLVM_DEBUG(llvm::dbgs() << "The argument's type is a singleton."); return false; + } - auto *arg = argDesc.Arg; - if (!shouldExpand(arg->getModule(), arg->getType().getObjectType())) { + auto *argument = argDesc.Arg; + auto &module = argument->getModule(); + auto type = argument->getType().getObjectType(); + + // If the global type expansion heuristic does not allow the type to be + // expanded, it will not be exploded. + if (!shouldExpand(module, type)) { + LLVM_DEBUG(llvm::dbgs() + << "The argument is of a type which should not be expanded."); return false; } - // If this argument is @owned and we can not find all the releases for it - // try to explode it, maybe we can find some of the releases and O2G some - // of its components. + bool willSpecializationIntroduceThunk = + transformDesc.willSpecializationIntroduceThunk(); + + unsigned const liveLeafCountUpperBound = argDesc.ProjTree.getLiveLeafCount(); + + // If we know already that we may not explode given the upper bound we have + // established on the live leaf count, exit early. + // + // If the argument is completely dead, it will not be exploded. // - // This is a potentially a very profitable optimization. Ignore other - // heuristics. - if (arg->hasConvention(SILArgumentConvention::Direct_Owned) && - ERM.hasSomeReleasesForArgument(arg)) + // Explosion makes sense only if some but not all of the leaves are live. The + // dead argument transformation will try to eliminate the argument. + if (!mayExplodeGivenLiveLeafCountUpperBound(liveLeafCountUpperBound)) { + LLVM_DEBUG(llvm::dbgs() << "The argument has no live leaves."); + return false; + } + + // To determine whether some but not all of the leaves are used, the total + // leaf count must be retrieved. + llvm::SmallVector allLeaves; + argDesc.ProjTree.getAllLeafTypes(allLeaves); + unsigned const leafCount = allLeaves.size(); + + assert( + liveLeafCountUpperBound <= leafCount && + "There should be no more *live* leaves than there are *total* leaves."); + + if (shouldExplode( + /*knownLifeLeafCount=*/liveLeafCountUpperBound, + /*hasKnownDeadLeaves=*/liveLeafCountUpperBound < leafCount, + /*hasKnownDeadNontrivialLeaves=*/false, + /*willSpecializationIntroduceThunk=*/ + willSpecializationIntroduceThunk)) { + LLVM_DEBUG( + llvm::dbgs() + << "Without considering the liveness of non-trivial leaves, it has " + "already been determined that there are already fewer (" + << liveLeafCountUpperBound + << ") live leaves of the relevant sort (trivial) than total leaves (" + << leafCount << ") and no more total live leaves (" + << liveLeafCountUpperBound << ") than the heuristic permits (" + << maxExplosionSizeWhenSpecializationWillIntroduceThunk( + /*willSpecializationIntroduceThunk=*/ + willSpecializationIntroduceThunk) + << "). Exploding."); + return true; + } + + auto *function = argument->getFunction(); + unsigned const nontrivialLeafCount = llvm::count_if( + allLeaves, [&](SILType type) { return !type.isTrivial(*function); }); + + llvm::SmallVector liveLeaves; + argDesc.ProjTree.getLiveLeafNodes(liveLeaves); + // NOTE: The value obtained here is an upper bound because the + // owned-to-guaranteed transformation may eliminate some live + // non-trivial leaves, leaving the count lower. + unsigned const liveNontrivialLeafCountUpperBound = + llvm::count_if(liveLeaves, [&](const ProjectionTreeNode *leaf) { + return !leaf->getType().isTrivial(*function); + }); + + assert(liveNontrivialLeafCountUpperBound <= nontrivialLeafCount && + "There should be no more *live* non-trivial leaves than there are " + "*total* non-trivial leaves."); + assert(nontrivialLeafCount <= leafCount && + "There should be no more *non-trivial* leaves than there are *total* " + "leaves."); + + // If it is known without taking the owned-to-guaranteed transformation into + // account both that exploding will reduce ARC traffic (because an upper bound + // for the number of live non-trivial leaves is less than the non-trivial + // leaf count) and also that the explosion will fit within the heuristic upper + // bound (because an upper bound for the total live leaf count falls within + // the limit imposed by the heuristic), then explode now. + bool shouldExplodeGivenUpperBounds = shouldExplode( + /*knownLiveLeafCount=*/liveLeafCountUpperBound, + /*hasKnownDeadLeaves=*/liveLeafCountUpperBound < leafCount, + /*hasKnownDeadNontrivialLeaves=*/liveNontrivialLeafCountUpperBound < + nontrivialLeafCount, + /*willSpecializationIntroduceThunk=*/willSpecializationIntroduceThunk); + if (shouldExplodeGivenUpperBounds) { + LLVM_DEBUG( + llvm::dbgs() + << "Without considering the expected results of the " + "owned-to-guaranteed transformation, there are already fewer (" + << liveNontrivialLeafCountUpperBound + << ") live non-trivial leaves than total leaves (" + << nontrivialLeafCount << ") and no more total live leaves (" + << liveLeafCountUpperBound << ") than the heuristic permits (" + << maxExplosionSizeWhenSpecializationWillIntroduceThunk( + /*willSpecializationIntroduceThunk=*/ + willSpecializationIntroduceThunk) + << "). Exploding."); return true; + } + + unsigned liveLeafCount = liveLeafCountUpperBound; + unsigned liveNontrivialLeafCount = liveNontrivialLeafCountUpperBound; + + // The upper bounds that have been established for the live leaf counts are + // too high to permit us to explode. That could be because it hasn't been + // established that any leaves are dead or alternatively that it hasn't been + // established that there are fewer total live leaves than the limit imposed + // by the heuristic. In either case, if some live leaves are eliminated, the + // number of live leaves may decrease such that exploding will be possible. + // The results of the owned-to-guaranteed transformation are predicated. If + // it is predicted that a leaf will be dead after the owned-to-guaranteed + // transformation, then the leaf count is decreased. + // + // The owned-to-guaranteed will only be applied to the argumehnt if its + // convention is Direct_Owned. Additionally, it only applies to non-trivial + // leaves, which it may kill, so if it is already known that there are no live + // non-trivial leaves, owned-to-guaranteed will not eliminate anything. + if (argDesc.hasConvention(SILArgumentConvention::Direct_Owned) && + liveNontrivialLeafCountUpperBound > 0) { + if (auto maybeReleases = + epilogueReleaseMatcher.getPartiallyPostDomReleaseSet(argument)) { + auto releases = maybeReleases.getValue(); + llvm::SmallPtrSet users; + users.insert(std::begin(releases), std::end(releases)); + + for (auto *leaf : liveLeaves) { + if (llvm::all_of(leaf->getNonProjUsers(), [&](Operand *operand) { + return users.count(operand->getUser()); + })) { + // Every non-projection user of the leaf is an epilogue release. The + // owned-to-guaranteed transformation will eliminate this usage. With + // the expectation of that usage being eliminated, stop considering + // this leaf to be live for the purposes of deciding whether the + // argument should be exploded. + --liveLeafCount; + --liveNontrivialLeafCount; + } + } + } + } - unsigned explosionSize = argDesc.ProjTree.getLiveLeafCount(); - return explosionSize >= 1 && explosionSize <= 3; + return shouldExplode( + /*knownLifeLeafCount=*/liveLeafCount, + /*hasKnownDeadLeaves=*/liveLeafCount < leafCount, + /*hasKnownDeadNontrivialLeaves=*/liveNontrivialLeafCount < + nontrivialLeafCount, + /*willSpecializationIntroduceThunk=*/willSpecializationIntroduceThunk); } //===----------------------------------------------------------------------===// -// Implementation +// Top Level Implementation //===----------------------------------------------------------------------===// bool FunctionSignatureTransform::ArgumentExplosionAnalyzeParameters() { @@ -95,7 +343,7 @@ bool FunctionSignatureTransform::ArgumentExplosionAnalyzeParameters() { continue; A.ProjTree.computeUsesAndLiveness(A.Arg); - A.Explode = shouldExplode(A, ArgToReturnReleaseMap); + A.Explode = shouldExplode(TransformDescriptor, A, ArgToReturnReleaseMap); // Modified self argument. if (A.Explode && Args[i]->isSelf()) { diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 1c64e1854a329..c42be855bda52 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -134,7 +134,7 @@ void ExistentialSpecializerCloner::cloneArguments( // SILBuilderContext. SILBuilder NewFBuilder(ClonedEntryBB, DebugScope, getBuilder().getBuilderContext()); - auto InsertLoc = OrigF->begin()->begin()->getLoc(); + auto InsertLoc = RegularLocation::getAutoGeneratedLocation(); auto NewFTy = NewF.getLoweredFunctionType(); SmallVector params; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 1fd6a2630522b..6cfef091876fc 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -65,11 +65,17 @@ using ArgumentIndexMap = llvm::SmallDenseMap; //===----------------------------------------------------------------------===// /// Set to true to enable the support for partial specialization. -llvm::cl::opt +static llvm::cl::opt FSOEnableGenerics("sil-fso-enable-generics", llvm::cl::init(true), llvm::cl::desc("Support function signature optimization " "of generic functions")); +static llvm::cl::opt + FSOOptimizeIfNotCalled("sil-fso-optimize-if-not-called", + llvm::cl::init(false), + llvm::cl::desc("Optimize even if a function isn't " + "called. For testing only!")); + static bool isSpecializableRepresentation(SILFunctionTypeRepresentation Rep, bool OptForPartialApply) { switch (Rep) { @@ -89,7 +95,7 @@ static bool isSpecializableRepresentation(SILFunctionTypeRepresentation Rep, llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch."); } -/// Returns true if F is a function which the pass know show to specialize +/// Returns true if F is a function which the pass knows how to specialize /// function signatures for. static bool canSpecializeFunction(SILFunction *F, const CallerAnalysis::FunctionInfo *FuncInfo, @@ -616,7 +622,11 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() { // Run the optimization. bool FunctionSignatureTransform::run(bool hasCaller) { - bool Changed = false; + // We use a reference here on purpose so our transformations can know if we + // are going to make a thunk and thus should just optimize. + bool &Changed = TransformDescriptor.Changed; + bool hasOnlyDirectInModuleCallers = + TransformDescriptor.hasOnlyDirectInModuleCallers; SILFunction *F = TransformDescriptor.OriginalFunction; // Never repeat the same function signature optimization on the same function. @@ -632,6 +642,9 @@ bool FunctionSignatureTransform::run(bool hasCaller) { return false; } + // If we are asked to assume a caller for testing purposes, set the flag. + hasCaller |= FSOOptimizeIfNotCalled; + if (!hasCaller && (F->getDynamicallyReplacedFunction() || canBeCalledIndirectly(F->getRepresentation()))) { LLVM_DEBUG(llvm::dbgs() << " function has no caller -> abort\n"); @@ -648,7 +661,8 @@ bool FunctionSignatureTransform::run(bool hasCaller) { // Run DeadArgument elimination transformation. We only specialize // if this function has a caller inside the current module or we have // already created a thunk. - if ((hasCaller || Changed) && DeadArgumentAnalyzeParameters()) { + if ((hasCaller || Changed || hasOnlyDirectInModuleCallers) && + DeadArgumentAnalyzeParameters()) { Changed = true; LLVM_DEBUG(llvm::dbgs() << " remove dead arguments\n"); DeadArgumentTransformFunction(); @@ -666,7 +680,8 @@ bool FunctionSignatureTransform::run(bool hasCaller) { // In order to not miss any opportunity, we send the optimized function // to the passmanager to optimize any opportunities exposed by argument // explosion. - if ((hasCaller || Changed) && ArgumentExplosionAnalyzeParameters()) { + if ((hasCaller || Changed || hasOnlyDirectInModuleCallers) && + ArgumentExplosionAnalyzeParameters()) { Changed = true; } @@ -821,7 +836,8 @@ class FunctionSignatureOpts : public SILFunctionTransform { SILOptFunctionBuilder FuncBuilder(*this); // Owned to guaranteed optimization. FunctionSignatureTransform FST(FuncBuilder, F, RCIA, EA, Mangler, AIM, - ArgumentDescList, ResultDescList); + ArgumentDescList, ResultDescList, + FuncInfo.foundAllCallers()); bool Changed = false; if (OptForPartialApply) { diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h index cf0404392ad0b..84c1f62847afb 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h @@ -111,9 +111,13 @@ struct ArgumentDescriptor { return Arg->hasConvention(P); } + /// Returns true if all function signature opt passes are able to process + /// this. bool canOptimizeLiveArg() const { - if (Arg->getType().isObject()) + if (Arg->getType().isObject()) { return true; + } + // @in arguments of generic types can be processed. if (Arg->getType().hasArchetype() && Arg->getType().isAddress() && @@ -194,6 +198,13 @@ struct FunctionSignatureTransformDescriptor { /// will use during our optimization. MutableArrayRef ResultDescList; + /// Are we going to make a change to this function? + bool Changed; + + /// Does this function only have direct callers. In such a case we know that + /// all thunks we create will be eliminated so we can be more aggressive. + bool hasOnlyDirectInModuleCallers; + /// Return a function name based on the current state of ArgumentDescList and /// ResultDescList. /// @@ -214,6 +225,19 @@ struct FunctionSignatureTransformDescriptor { /// simply passes it through. void addThunkArgument(ArgumentDescriptor &AD, SILBuilder &Builder, SILBasicBlock *BB, SmallVectorImpl &NewArgs); + + /// Whether specializing the function will result in a thunk with the same + /// signature as the original function that calls through to the specialized + /// function. + /// + /// Such a thunk is necessary if there is (or could be) code that calls the + /// function which we are unable to specialize to match the function's + /// specialization. + bool willSpecializationIntroduceThunk() { + return !hasOnlyDirectInModuleCallers || + OriginalFunction->isPossiblyUsedExternally() || + OriginalFunction->isAvailableExternally(); + } }; class FunctionSignatureTransform { @@ -287,15 +311,17 @@ class FunctionSignatureTransform { public: /// Constructor. FunctionSignatureTransform( - SILOptFunctionBuilder &FunctionBuilder, - SILFunction *F, RCIdentityAnalysis *RCIA, EpilogueARCAnalysis *EA, + SILOptFunctionBuilder &FunctionBuilder, SILFunction *F, + RCIdentityAnalysis *RCIA, EpilogueARCAnalysis *EA, Mangle::FunctionSignatureSpecializationMangler &Mangler, llvm::SmallDenseMap &AIM, llvm::SmallVector &ADL, - llvm::SmallVector &RDL) + llvm::SmallVector &RDL, + bool hasOnlyDirectInModuleCallers) : FunctionBuilder(FunctionBuilder), - TransformDescriptor{F, nullptr, AIM, false, ADL, RDL}, RCIA(RCIA), - EA(EA) {} + TransformDescriptor{F, nullptr, AIM, false, + ADL, RDL, false, hasOnlyDirectInModuleCallers}, + RCIA(RCIA), EA(EA) {} /// Return the optimized function. SILFunction *getOptimizedFunction() { diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index d039f10b382c8..babb3e0aac2a9 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -4691,7 +4691,8 @@ class JVPEmitter final CLONE_AND_EMIT_TANGENT(AllocStack, asi) { auto &diffBuilder = getDifferentialBuilder(); auto *mappedAllocStackInst = diffBuilder.createAllocStack( - asi->getLoc(), getRemappedTangentType(asi->getElementType())); + asi->getLoc(), getRemappedTangentType(asi->getElementType()), + asi->getVarInfo()); bufferMap.try_emplace({asi->getParent(), asi}, mappedAllocStackInst); } @@ -6112,7 +6113,7 @@ class PullbackEmitter final : public SILInstructionVisitor { // Allocate local buffer and initialize to zero. auto bufObjectType = getRemappedTangentType(originalBuffer->getType()); auto *newBuf = localAllocBuilder.createAllocStack( - originalBuffer.getLoc(), bufObjectType); + RegularLocation::getAutoGeneratedLocation(), bufObjectType); // Temporarily change global builder insertion point and emit zero into the // local buffer. auto insertionPoint = builder.getInsertionBB(); diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index d22c2c4caca0b..76341b3f62278 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -53,21 +53,6 @@ static SILValue stripCopiesAndBorrows(SILValue v) { return v; } -/// If \p applySite is a terminator then pass the first instruction of each -/// successor to fun. Otherwise, pass std::next(applySite). -static void -insertAfterApply(SILInstruction *applySite, - llvm::function_ref &&fun) { - auto *ti = dyn_cast(applySite); - if (!ti) { - return fun(std::next(applySite->getIterator())); - } - - for (auto *succBlocks : ti->getSuccessorBlocks()) { - fun(succBlocks->begin()); - } -} - /// Fixup reference counts after inlining a function call (which is a no-op /// unless the function is a thick function). /// @@ -174,13 +159,12 @@ static void fixupReferenceCounts( // insert a destroy after the apply since the leak will just cover the // other path. if (!error.getFoundOverConsume()) { - insertAfterApply( - applySite.getInstruction(), [&](SILBasicBlock::iterator iter) { - if (hasOwnership) { - SILBuilderWithScope(iter).createEndBorrow(loc, argument); - } - SILBuilderWithScope(iter).emitDestroyValueOperation(loc, copy); - }); + applySite.insertAfter([&](SILBasicBlock::iterator iter) { + if (hasOwnership) { + SILBuilderWithScope(iter).createEndBorrow(loc, argument); + } + SILBuilderWithScope(iter).emitDestroyValueOperation(loc, copy); + }); } v = argument; break; @@ -215,10 +199,9 @@ static void fixupReferenceCounts( } } - insertAfterApply( - applySite.getInstruction(), [&](SILBasicBlock::iterator iter) { - SILBuilderWithScope(iter).emitDestroyValueOperation(loc, v); - }); + applySite.insertAfter([&](SILBasicBlock::iterator iter) { + SILBuilderWithScope(iter).emitDestroyValueOperation(loc, v); + }); break; } @@ -263,10 +246,9 @@ static void fixupReferenceCounts( // Destroy the callee as the apply would have done if our function is not // callee guaranteed. if (!isCalleeGuaranteed) { - insertAfterApply( - applySite.getInstruction(), [&](SILBasicBlock::iterator iter) { - SILBuilderWithScope(iter).emitDestroyValueOperation(loc, calleeValue); - }); + applySite.insertAfter([&](SILBasicBlock::iterator iter) { + SILBuilderWithScope(iter).emitDestroyValueOperation(loc, calleeValue); + }); } } diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index b2aa97eebdb55..9568cd176d8c0 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -105,6 +105,14 @@ static void addMandatoryOptPipeline(SILPassPipelinePlan &P) { // there. const auto &Options = P.getOptions(); P.addClosureLifetimeFixup(); + +#ifndef NDEBUG + // Add a verification pass to check our work when skipping non-inlinable + // function bodies. + if (Options.SkipNonInlinableFunctionBodies) + P.addNonInlinableFunctionSkippingChecker(); +#endif + if (Options.shouldOptimize()) { P.addSemanticARCOpts(); P.addDestroyHoisting(); diff --git a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp index 149406fc6f4b9..e9c51b114e7f5 100644 --- a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp +++ b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp @@ -303,9 +303,15 @@ promoteDebugValueAddr(DebugValueAddrInst *DVAI, SILValue Value, SILBuilder &B) { assert(DVAI->getOperand()->getType().isLoadable(*DVAI->getFunction()) && "Unexpected promotion of address-only type!"); assert(Value && "Expected valid value"); + // Avoid inserting the same debug_value twice. + for (Operand *Use : Value->getUses()) + if (auto *DVI = dyn_cast(Use->getUser())) + if (*DVI->getVarInfo() == *DVAI->getVarInfo()) + return; B.setInsertionPoint(DVAI); B.setCurrentDebugScope(DVAI->getDebugScope()); B.createDebugValue(DVAI->getLoc(), Value, *DVAI->getVarInfo()); + DVAI->eraseFromParent(); } diff --git a/lib/SILOptimizer/Transforms/SILSROA.cpp b/lib/SILOptimizer/Transforms/SILSROA.cpp index 46042d8331f65..50fa0d4f5a7a2 100644 --- a/lib/SILOptimizer/Transforms/SILSROA.cpp +++ b/lib/SILOptimizer/Transforms/SILSROA.cpp @@ -215,19 +215,21 @@ SROAMemoryUseAnalyzer:: createAllocas(llvm::SmallVector &NewAllocations) { SILBuilderWithScope B(AI); SILType Type = AI->getType().getObjectType(); - + // Intentionally dropping the debug info. + // FIXME: VarInfo needs to be extended with fragment info to support this. + SILLocation Loc = RegularLocation::getAutoGeneratedLocation(); if (TT) { for (unsigned EltNo : indices(TT->getElementTypes())) { SILType EltTy = Type.getTupleElementType(EltNo); - NewAllocations.push_back(B.createAllocStack(AI->getLoc(), EltTy)); + NewAllocations.push_back(B.createAllocStack(Loc, EltTy, {})); } } else { assert(SD && "SD should not be null since either it or TT must be set at " "this point."); SILModule &M = AI->getModule(); for (auto *D : SD->getStoredProperties()) - NewAllocations.push_back(B.createAllocStack(AI->getLoc(), - Type.getFieldType(D, M))); + NewAllocations.push_back( + B.createAllocStack(Loc, Type.getFieldType(D, M), {})); } } diff --git a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt index c33fb8245cb25..b7472977050d7 100644 --- a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt +++ b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt @@ -7,6 +7,7 @@ silopt_register_sources( BugReducerTester.cpp CFGPrinter.cpp CallerAnalysisPrinter.cpp + NonInlinableFunctionSkippingChecker.cpp ComputeDominanceInfo.cpp ComputeLoopInfo.cpp ConstantEvaluatorTester.cpp diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp index 54ba6d88c4057..d12e9b016a2e8 100644 --- a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp @@ -74,10 +74,6 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { if (isa(inst)) break; - assert(!previousEvaluationHadFatalError && - "cannot continue evaluation of test driver as previous call " - "resulted in non-skippable evaluation error."); - auto *applyInst = dyn_cast(inst); SILFunction *callee = nullptr; if (applyInst) { @@ -89,6 +85,16 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { if (!applyInst || !callee || !callee->hasSemanticsAttr(constantEvaluableSemanticsAttr)) { + + // Ignore these instructions if we had a fatal error already. + if (previousEvaluationHadFatalError) { + if (isa(inst)) { + assert(false && "non-constant control flow in the test driver"); + } + ++currI; + continue; + } + std::tie(nextInstOpt, errorVal) = stepEvaluator.tryEvaluateOrElseMakeEffectsNonConstant(currI); if (!nextInstOpt) { @@ -100,6 +106,10 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform { continue; } + assert(!previousEvaluationHadFatalError && + "cannot continue evaluation of test driver as previous call " + "resulted in non-skippable evaluation error."); + // Here, a function annotated as "constant_evaluable" is called. llvm::errs() << "@" << demangleSymbolName(callee->getName()) << "\n"; std::tie(nextInstOpt, errorVal) = diff --git a/lib/SILOptimizer/UtilityPasses/NonInlinableFunctionSkippingChecker.cpp b/lib/SILOptimizer/UtilityPasses/NonInlinableFunctionSkippingChecker.cpp new file mode 100644 index 0000000000000..402e275f39591 --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/NonInlinableFunctionSkippingChecker.cpp @@ -0,0 +1,107 @@ +//===------------- NonInlinableFunctionSkippingChecker.cpp ----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 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 "swift/Basic/LLVM.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILModule.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace swift; + +/// Determines whether we should have skipped SILGenning a function that +/// appears in a SILModule. This only applies when +/// \c -experimental-skip-non-inlinable-function-bodies is enabled. +static bool shouldHaveSkippedFunction(const SILFunction &F) { + assert(F.getModule().getOptions().SkipNonInlinableFunctionBodies && + "this check only makes sense if we're skipping function bodies"); + + // First, we only care about functions that haven't been marked serialized. + // If they've been marked serialized, they will end up in the final module + // and we needed to SILGen them. + if (F.isSerialized()) + return false; + + // Next, we're looking for functions that shouldn't have a body, but do. If + // the function doesn't have a body (i.e. it's an external declaration), we + // skipped it successfully. + if (F.isExternalDeclaration()) + return false; + + // Thunks and specializations are automatically synthesized, so it's fine that + // they end up in the module. + if (F.isThunk() || F.isSpecialization()) + return false; + + // FIXME: We can probably skip property initializers, too. + auto func = F.getLocation().getAsASTNode(); + if (!func) + return false; + + // If a body is synthesized/implicit, it shouldn't be skipped. + if (func->isImplicit()) + return false; + + // Local function bodies in inlinable code are okay to show up in the module. + if (func->getDeclContext()->isLocalContext()) + return false; + + // FIXME: Identify __ivar_destroyer, __allocating_init, and + // __deallocating_deinit, which have no special marking, are always + // emitted, and do have a source location with the original decl + // attached. + if (isa(func) || isa(func)) + return false; + + // If none of those conditions trip, then this is something that _should_ + // be serialized in the module even when we're skipping non-inlinable + // function bodies. + return true; +} + +namespace { + +/// This is a verification utility pass that's meant to be used with +/// \c -experimental-skip-non-inlinable-function-bodies. It checks all the +/// functions in a module and ensures that, if the function was written in +/// source and not serialized, then it wasn't even SILGen'd. +class NonInlinableFunctionSkippingChecker : public SILModuleTransform { + void run() override { + // Skip this if we're not skipping function bodies + if (!getModule()->getOptions().SkipNonInlinableFunctionBodies) + return; + + // Skip this verification for SwiftOnoneSupport + if (getModule()->isOptimizedOnoneSupportModule()) + return; + + for (auto &F : *getModule()) { + if (!shouldHaveSkippedFunction(F)) + continue; + + llvm::dbgs() << "Function serialized that should have been skipped!\n"; + F.getLocation().dump(F.getModule().getSourceManager()); + llvm::dbgs() << "\n"; + F.dump(); + abort(); + } + } + +}; + +} // end anonymous namespace + +SILTransform *swift::createNonInlinableFunctionSkippingChecker() { + return new NonInlinableFunctionSkippingChecker(); +} diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index dd5d784e04818..649b3dd3e0549 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -38,6 +38,12 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, // general framework. enum class WellKnownFunction { + // Array.init() + ArrayInitEmpty, + // Array._allocateUninitializedArray + AllocateUninitializedArray, + // Array.append(_:) + ArrayAppendElement, // String.init() StringInitEmpty, // String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:) @@ -53,6 +59,12 @@ enum class WellKnownFunction { }; static llvm::Optional classifyFunction(SILFunction *fn) { + if (fn->hasSemanticsAttr("array.init.empty")) + return WellKnownFunction::ArrayInitEmpty; + if (fn->hasSemanticsAttr("array.uninitialized_intrinsic")) + return WellKnownFunction::AllocateUninitializedArray; + if (fn->hasSemanticsAttr("array.append_element")) + return WellKnownFunction::ArrayAppendElement; if (fn->hasSemanticsAttr("string.init_empty")) return WellKnownFunction::StringInitEmpty; // There are two string initializers in the standard library with the @@ -430,6 +442,29 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { if (isa(value) || isa(value)) return getConstantValue(cast(value)->getOperand(0)); + // Builtin.RawPointer and addresses have the same representation. + if (auto *p2ai = dyn_cast(value)) + return getConstantValue(p2ai->getOperand()); + + // Indexing a pointer moves the deepest index of the access path it represents + // within a memory object. For example, if a pointer p represents the access + // path [1, 2] within a memory object, p + 1 represents [1, 3] + if (auto *ia = dyn_cast(value)) { + auto index = getConstantValue(ia->getOperand(1)); + if (!index.isConstant()) + return index; + auto basePtr = getConstantValue(ia->getOperand(0)); + if (basePtr.getKind() != SymbolicValue::Address) + return basePtr; + + SmallVector accessPath; + auto *memObject = basePtr.getAddressValue(accessPath); + assert(!accessPath.empty() && "Can't index a non-indexed address"); + accessPath.back() += index.getIntegerValue().getLimitedValue(); + return SymbolicValue::getAddress(memObject, accessPath, + evaluator.getAllocator()); + } + LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unknown simple: " << *value << "\n"); // Otherwise, we don't know how to handle this. @@ -732,6 +767,15 @@ extractStaticStringValue(SymbolicValue staticString) { return staticStringProps[0].getStringValue(); } +/// If the specified type is a Swift.Array of some element type, then return the +/// element type. Otherwise, return a null Type. +static Type getArrayElementType(Type ty) { + if (auto bgst = ty->getAs()) + if (bgst->getDecl() == bgst->getASTContext().getArrayDecl()) + return bgst->getGenericArgs()[0]; + return Type(); +} + /// Given a call to a well known function, collect its arguments as constants, /// fold it, and return None. If any of the arguments are not constants, marks /// the call's results as Unknown, and return an Unknown with information about @@ -769,6 +813,134 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, (SILInstruction *)apply, UnknownReason::createTrap(message, evaluator.getAllocator())); } + case WellKnownFunction::ArrayInitEmpty: { // Array.init() + assert(conventions.getNumDirectSILResults() == 1 && + conventions.getNumIndirectSILResults() == 0 && + "unexpected Array.init() signature"); + + auto typeValue = getConstantValue(apply->getOperand(1)); + if (typeValue.getKind() != SymbolicValue::Metatype) { + return typeValue.isConstant() + ? getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue) + : typeValue; + } + Type arrayType = typeValue.getMetatypeValue(); + + // Create an empty SymbolicArrayStorage and then create a SymbolicArray + // using it. + SymbolicValue arrayStorage = SymbolicValue::getSymbolicArrayStorage( + {}, getArrayElementType(arrayType)->getCanonicalType(), + evaluator.getAllocator()); + auto arrayVal = SymbolicValue::getArray(arrayType, arrayStorage, + evaluator.getAllocator()); + setValue(apply, arrayVal); + return None; + } + case WellKnownFunction::AllocateUninitializedArray: { + // This function has this signature: + // func _allocateUninitializedArray(_ builtinCount: Builtin.Word) + // -> (Array, Builtin.RawPointer) + assert(conventions.getNumParameters() == 1 && + conventions.getNumDirectSILResults() == 2 && + conventions.getNumIndirectSILResults() == 0 && + "unexpected _allocateUninitializedArray signature"); + + // Figure out the allocation size. + auto numElementsSV = getConstantValue(apply->getOperand(1)); + if (!numElementsSV.isConstant()) + return numElementsSV; + + unsigned numElements = numElementsSV.getIntegerValue().getLimitedValue(); + + // Allocating uninitialized arrays is supported only in flow-sensitive mode. + // TODO: the top-level mode in the interpreter should be phased out. + if (!fn) + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::Default); + + SmallVector elementConstants; + // Set array elements to uninitialized state. Subsequent stores through + // their addresses will initialize the elements. + elementConstants.assign(numElements, SymbolicValue::getUninitMemory()); + + Type arrayType = apply->getType().castTo()->getElementType(0); + Type arrayEltType = getArrayElementType(arrayType); + assert(arrayEltType && "Couldn't understand Swift.Array type?"); + + // Create a SymbolicArrayStorage with \c elements and then create a + // SymbolicArray using it. + SymbolicValueAllocator &allocator = evaluator.getAllocator(); + SymbolicValue arrayStorage = SymbolicValue::getSymbolicArrayStorage( + elementConstants, arrayEltType->getCanonicalType(), allocator); + SymbolicValue array = + SymbolicValue::getArray(arrayType, arrayStorage, allocator); + + // Construct return value for this call, which is a pair consisting of the + // address of the first element of the array and the array. + SymbolicValue storageAddress = array.getAddressOfArrayElement(allocator, 0); + setValue(apply, + SymbolicValue::getAggregate({array, storageAddress}, allocator)); + return None; + } + case WellKnownFunction::ArrayAppendElement: { + // This function has the following signature in SIL: + // (@in Element, @inout Array) -> () + assert(conventions.getNumParameters() == 2 && + conventions.getNumDirectSILResults() == 0 && + conventions.getNumIndirectSILResults() == 0 && + "unexpected Array.append(_:) signature"); + // Get the element to be appended which is passed indirectly (@in). + SymbolicValue elementAddress = getConstantValue(apply->getOperand(1)); + if (!elementAddress.isConstant()) + return elementAddress; + + auto invalidOperand = [&]() { + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); + }; + if (elementAddress.getKind() != SymbolicValue::Address) { + // TODO: store the operand number in the error message here. + return invalidOperand(); + } + + SmallVector elementAP; + SymbolicValue element = + elementAddress.getAddressValue(elementAP)->getValue(); + + // Get the array value. The array is passed @inout. + SymbolicValue arrayAddress = getConstantValue(apply->getOperand(2)); + if (!arrayAddress.isConstant()) + return arrayAddress; + if (arrayAddress.getKind() != SymbolicValue::Address) + return invalidOperand(); + + SmallVector arrayAP; + SymbolicValueMemoryObject *arrayMemoryObject = + arrayAddress.getAddressValue(arrayAP); + SymbolicValue arrayValue = arrayMemoryObject->getValue(); + if (arrayValue.getKind() != SymbolicValue::Array) { + return invalidOperand(); + } + + // Create a new array storage by appending the \c element to the existing + // storage, and create a new array using the new storage. + SymbolicValue arrayStorage = arrayValue.getStorageOfArray(); + CanType elementType; + ArrayRef oldElements = + arrayStorage.getStoredElements(elementType); + SmallVector newElements(oldElements.begin(), + oldElements.end()); + newElements.push_back(element); + + SymbolicValueAllocator &allocator = evaluator.getAllocator(); + SymbolicValue newStorage = SymbolicValue::getSymbolicArrayStorage( + newElements, elementType, allocator); + SymbolicValue newArray = SymbolicValue::getArray(arrayValue.getArrayType(), + newStorage, allocator); + arrayMemoryObject->setIndexedElement(arrayAP, newArray, allocator); + return None; + } case WellKnownFunction::StringInitEmpty: { // String.init() assert(conventions.getNumDirectSILResults() == 1 && conventions.getNumIndirectSILResults() == 0 && diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp index 4c079c63713b0..ccee64e964731 100644 --- a/lib/SILOptimizer/Utils/GenericCloner.cpp +++ b/lib/SILOptimizer/Utils/GenericCloner.cpp @@ -81,7 +81,8 @@ void GenericCloner::populateCloned() { // We need an alloc_stack as a replacement for the indirect parameter. assert(mappedType.isAddress()); mappedType = mappedType.getObjectType(); - ASI = getBuilder().createAllocStack(Loc, mappedType); + auto AllocStackLoc = RegularLocation::getAutoGeneratedLocation(); + ASI = getBuilder().createAllocStack(AllocStackLoc, mappedType); AllocStacks.push_back(ASI); }; auto handleConversion = [&]() { diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index f5a75cbe6dca5..6e98c9ca25143 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2513,28 +2513,37 @@ namespace { baseTyUnwrapped, memberName, defaultMemberLookupOptions); - - // Lookup didn't find anything, so return + + // Filter out any functions, instance members, enum cases with + // associated values or variables whose type does not match the + // contextual type. + results.filter([&](const LookupResultEntry entry, bool isOuter) { + if (auto member = entry.getValueDecl()) { + if (isa(member)) + return false; + if (member->isInstanceMember()) + return false; + if (auto EED = dyn_cast(member)) { + return !EED->hasAssociatedValues(); + } + if (auto VD = dyn_cast(member)) { + auto baseType = DSCE->getType()->lookThroughAllOptionalTypes(); + return VD->getInterfaceType()->isEqual(baseType); + } + } + + // Filter out anything that's not one of the above. We don't care + // if we have a typealias named 'none' or a struct/class named + // 'none'. + return false; + }); + if (results.empty()) { return; } if (auto member = results.front().getValueDecl()) { - // Lookup returned a member that is an instance member, - // so return - if (member->isInstanceMember()) { - return; - } - - // Return if the member is an enum case w/ assoc values, as we only - // care (for now) about cases with no assoc values (like none) - if (auto EED = dyn_cast(member)) { - if (EED->hasAssociatedValues()) { - return; - } - } - - // Emit a diagnostic with some fixits + // Emit a diagnostic with some fix-its auto baseTyName = baseTy->getCanonicalType().getString(); auto baseTyUnwrappedName = baseTyUnwrapped->getString(); auto loc = DSCE->getLoc(); @@ -7462,7 +7471,7 @@ bool swift::exprNeedsParensInsideFollowingOperator( TypeChecker &TC, DeclContext *DC, Expr *expr, PrecedenceGroupDecl *followingPG) { if (expr->isInfixOperator()) { - auto exprPG = TC.lookupPrecedenceGroupForInfixOperator(DC, expr); + auto exprPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC, expr); if (!exprPG) return true; return TC.Context.associateInfixOperators(exprPG, followingPG) @@ -7496,7 +7505,8 @@ bool swift::exprNeedsParensOutsideFollowingOperator( return false; if (parent->isInfixOperator()) { - auto parentPG = TC.lookupPrecedenceGroupForInfixOperator(DC, parent); + auto parentPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC, + parent); if (!parentPG) return true; // If the index is 0, this is on the LHS of the parent. @@ -7515,10 +7525,10 @@ bool swift::exprNeedsParensOutsideFollowingOperator( bool swift::exprNeedsParensBeforeAddingNilCoalescing(TypeChecker &TC, DeclContext *DC, Expr *expr) { - auto asPG = - TC.lookupPrecedenceGroup(DC, DC->getASTContext().Id_NilCoalescingPrecedence, - SourceLoc()); - if (!asPG) return true; + auto asPG = TypeChecker::lookupPrecedenceGroup( + DC, DC->getASTContext().Id_NilCoalescingPrecedence, SourceLoc()); + if (!asPG) + return true; return exprNeedsParensInsideFollowingOperator(TC, DC, expr, asPG); } @@ -7526,9 +7536,8 @@ bool swift::exprNeedsParensAfterAddingNilCoalescing(TypeChecker &TC, DeclContext *DC, Expr *expr, Expr *rootExpr) { - auto asPG = - TC.lookupPrecedenceGroup(DC, DC->getASTContext().Id_NilCoalescingPrecedence, - SourceLoc()); + auto asPG = TypeChecker::lookupPrecedenceGroup( + DC, DC->getASTContext().Id_NilCoalescingPrecedence, SourceLoc()); if (!asPG) return true; return exprNeedsParensOutsideFollowingOperator(TC, DC, expr, rootExpr, asPG); } diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 6e417ceec39cd..4b20e00a4a124 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -2150,7 +2150,6 @@ bool FailureDiagnosis::diagnoseImplicitSelfErrors( class ArgumentMatcher : public MatchCallArgumentListener { TypeChecker &TC; - Expr *FnExpr; Expr *ArgExpr; ArrayRef &Parameters; const ParameterListInfo &ParamInfo; @@ -2167,12 +2166,12 @@ class ArgumentMatcher : public MatchCallArgumentListener { SmallVector Bindings; public: - ArgumentMatcher(Expr *fnExpr, Expr *argExpr, + ArgumentMatcher(Expr *argExpr, ArrayRef ¶ms, const ParameterListInfo ¶mInfo, SmallVectorImpl &args, CalleeCandidateInfo &CCI, bool isSubscript) - : TC(CCI.CS.TC), FnExpr(fnExpr), ArgExpr(argExpr), Parameters(params), + : TC(CCI.CS.TC), ArgExpr(argExpr), Parameters(params), ParamInfo(paramInfo), Arguments(args), CandidateInfo(CCI), IsSubscript(isSubscript) {} @@ -2214,159 +2213,6 @@ class ArgumentMatcher : public MatchCallArgumentListener { Diagnosed = true; } - void missingArgument(unsigned missingParamIdx) override { - auto ¶m = Parameters[missingParamIdx]; - Identifier name = param.getLabel(); - - // Search insertion index. - unsigned argIdx = 0; - for (int Idx = missingParamIdx - 1; Idx >= 0; --Idx) { - if (Bindings[Idx].empty()) - continue; - argIdx = Bindings[Idx].back() + 1; - break; - } - - unsigned insertableEndIdx = Arguments.size(); - if (CandidateInfo.hasTrailingClosure) - insertableEndIdx -= 1; - - // Build argument string for fix-it. - SmallString<32> insertBuf; - llvm::raw_svector_ostream insertText(insertBuf); - - if (argIdx != 0) - insertText << ", "; - if (!name.empty()) - insertText << name.str() << ": "; - Type Ty = param.getOldType(); - // Explode inout type. - if (param.isInOut()) { - insertText << "&"; - Ty = param.getPlainType(); - } - // @autoclosure; the type should be the result type. - if (param.isAutoClosure()) - Ty = param.getPlainType()->castTo()->getResult(); - insertText << "<#" << Ty << "#>"; - if (argIdx == 0 && insertableEndIdx != 0) - insertText << ", "; - - SourceLoc insertLoc; - if (argIdx > insertableEndIdx) { - // Unreachable for now. - // FIXME: matchCallArguments() doesn't detect "missing argument after - // trailing closure". E.g. - // func fn(x: Int, y: () -> Int, z: Int) { ... } - // fn(x: 1) { return 1 } - // is diagnosed as "missing argument for 'y'" (missingParamIdx 1). - // It should be "missing argument for 'z'" (missingParamIdx 2). - } else if (auto *TE = dyn_cast(ArgExpr)) { - // fn(): - // fn([argMissing]) - // fn(argX, argY): - // fn([argMissing, ]argX, argY) - // fn(argX[, argMissing], argY) - // fn(argX, argY[, argMissing]) - // fn(argX) { closure }: - // fn([argMissing, ]argX) { closure } - // fn(argX[, argMissing]) { closure } - // fn(argX[, closureLabel: ]{closure}[, argMissing)] // Not impl. - if (insertableEndIdx == 0) - insertLoc = TE->getRParenLoc(); - else if (argIdx != 0) - insertLoc = Lexer::getLocForEndOfToken( - TC.Context.SourceMgr, TE->getElement(argIdx - 1)->getEndLoc()); - else { - insertLoc = TE->getElementNameLoc(0); - if (insertLoc.isInvalid()) - insertLoc = TE->getElement(0)->getStartLoc(); - } - } else if (auto *PE = dyn_cast(ArgExpr)) { - assert(argIdx <= 1); - if (PE->getRParenLoc().isValid()) { - // fn(argX): - // fn([argMissing, ]argX) - // fn(argX[, argMissing]) - // fn() { closure }: - // fn([argMissing]) {closure} - // fn([closureLabel: ]{closure}[, argMissing]) // Not impl. - if (insertableEndIdx == 0) - insertLoc = PE->getRParenLoc(); - else if (argIdx == 0) - insertLoc = PE->getSubExpr()->getStartLoc(); - else - insertLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, - PE->getSubExpr()->getEndLoc()); - } else { - // fn { closure }: - // fn[(argMissing)] { closure } - // fn[(closureLabel:] { closure }[, missingArg)] // Not impl. - assert(!IsSubscript && "bracket less subscript"); - assert(PE->hasTrailingClosure() && - "paren less ParenExpr without trailing closure"); - insertBuf.insert(insertBuf.begin(), '('); - insertBuf.insert(insertBuf.end(), ')'); - insertLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, - FnExpr->getEndLoc()); - } - } else { - auto &CS = CandidateInfo.CS; - (void)CS; - // FIXME: Due to a quirk of CSApply, we can end up without a - // ParenExpr if the argument has an '@lvalue TupleType'. - assert((isa(CS.getType(ArgExpr).getPointer()) || - CS.getType(ArgExpr)->hasParenSugar()) && - "unexpected argument expression type"); - insertLoc = ArgExpr->getLoc(); - } - - assert(insertLoc.isValid() && "missing argument after trailing closure?"); - - if (name.empty()) { - TC.diagnose(insertLoc, diag::missing_argument_positional, - missingParamIdx + 1) - .fixItInsert(insertLoc, insertText.str()); - } else { - if (isPropertyWrapperImplicitInit()) { - auto TE = cast(FnExpr); - TC.diagnose(TE->getLoc(), diag::property_wrapper_missing_arg_init, name, - TE->getInstanceType()->getString()); - } else { - TC.diagnose(insertLoc, diag::missing_argument_named, name) - .fixItInsert(insertLoc, insertText.str()); - } - } - - auto candidate = CandidateInfo[0]; - if (candidate.getDecl()) - TC.diagnose(candidate.getDecl(), diag::decl_declared_here, - candidate.getDecl()->getFullName()); - - Diagnosed = true; - } - - bool isPropertyWrapperImplicitInit() { - auto TE = dyn_cast(FnExpr); - if (!TE) - return false; - - auto instanceTy = TE->getInstanceType(); - if (!instanceTy) - return false; - - auto nominalDecl = instanceTy->getAnyNominal(); - if (!(nominalDecl && - nominalDecl->getAttrs().hasAttribute())) - return false; - - if (auto *parentExpr = CandidateInfo.CS.getParentExpr(FnExpr)) { - return parentExpr->isImplicit() && isa(parentExpr); - } - - return false; - } - bool missingLabel(unsigned paramIdx) override { return false; } @@ -2502,7 +2348,7 @@ diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr, // If we have a single candidate that failed to match the argument list, // attempt to use matchCallArguments to diagnose the problem. - return ArgumentMatcher(fnExpr, argExpr, params, paramInfo, args, CCI, + return ArgumentMatcher(argExpr, params, paramInfo, args, CCI, isa(fnExpr)) .diagnose(); } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ae75692c66324..f0c58f8d335d0 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3567,13 +3567,19 @@ bool ImplicitInitOnNonConstMetatypeFailure::diagnoseAsError() { } bool MissingArgumentsFailure::diagnoseAsError() { + auto &cs = getConstraintSystem(); auto *locator = getLocator(); auto path = locator->getPath(); - // TODO: Currently this is only intended to diagnose contextual failures. if (path.empty() || !(path.back().getKind() == ConstraintLocator::ApplyArgToParam || - path.back().getKind() == ConstraintLocator::ContextualType)) + path.back().getKind() == ConstraintLocator::ContextualType || + path.back().getKind() == ConstraintLocator::ApplyArgument)) + return false; + + // If this is a misplaced `missng argument` situation, it would be + // diagnosed by invalid conversion fix. + if (isMisplacedMissingArgument(cs, locator)) return false; auto *anchor = getAnchor(); @@ -3583,7 +3589,223 @@ bool MissingArgumentsFailure::diagnoseAsError() { if (auto *closure = dyn_cast(anchor)) return diagnoseClosure(closure); - return false; + // This is a situation where function type is passed as an argument + // to a function type parameter and their argument arity is different. + // + // ``` + // func foo(_: (Int) -> Void) {} + // func bar() {} + // + // foo(bar) // `() -> Void` vs. `(Int) -> Void` + // ``` + if (locator->isLastElement(ConstraintLocator::ApplyArgToParam)) { + auto info = *getFunctionArgApplyInfo(locator); + + auto *argExpr = info.getArgExpr(); + emitDiagnostic(argExpr->getLoc(), diag::cannot_convert_argument_value, + info.getArgType(), info.getParamType()); + // TODO: It would be great so somehow point out which arguments are missing. + return true; + } + + // Function type has fewer arguments than expected by context: + // + // ``` + // func foo() {} + // let _: (Int) -> Void = foo + // ``` + if (locator->isLastElement(ConstraintLocator::ContextualType)) { + auto &cs = getConstraintSystem(); + emitDiagnostic(anchor->getLoc(), diag::cannot_convert_initializer_value, + getType(anchor), resolveType(cs.getContextualType())); + // TODO: It would be great so somehow point out which arguments are missing. + return true; + } + + if (diagnoseInvalidTupleDestructuring()) + return true; + + if (SynthesizedArgs.size() == 1) + return diagnoseSingleMissingArgument(); + + // At this point we know that this is a situation when + // there are multiple arguments missing, so let's produce + // a diagnostic which lists all of them and a fix-it + // to add arguments at appropriate positions. + + SmallString<32> diagnostic; + llvm::raw_svector_ostream arguments(diagnostic); + + interleave( + SynthesizedArgs, + [&](const AnyFunctionType::Param &arg) { + if (arg.hasLabel()) { + arguments << "'" << arg.getLabel().str() << "'"; + } else { + auto *typeVar = arg.getPlainType()->castTo(); + auto *locator = typeVar->getImpl().getLocator(); + auto paramIdx = locator->findLast() + ->getParamIdx(); + + arguments << "#" << (paramIdx + 1); + } + }, + [&] { arguments << ", "; }); + + auto diag = emitDiagnostic(anchor->getLoc(), diag::missing_arguments_in_call, + arguments.str()); + + Expr *fnExpr = nullptr; + Expr *argExpr = nullptr; + unsigned numArguments = 0; + bool hasTrailingClosure = false; + + std::tie(fnExpr, argExpr, numArguments, hasTrailingClosure) = + getCallInfo(getRawAnchor()); + + // TODO(diagnostics): We should be able to suggest this fix-it + // unconditionally. + if (argExpr && numArguments == 0) { + SmallString<32> scratch; + llvm::raw_svector_ostream fixIt(scratch); + interleave( + SynthesizedArgs, + [&](const AnyFunctionType::Param &arg) { forFixIt(fixIt, arg); }, + [&] { fixIt << ", "; }); + + auto *tuple = cast(argExpr); + diag.fixItInsertAfter(tuple->getLParenLoc(), fixIt.str()); + } + + diag.flush(); + + if (auto selectedOverload = getChoiceFor(locator)) { + if (auto *decl = selectedOverload->choice.getDeclOrNull()) { + emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + } + } + + return true; +} + +bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { + auto &ctx = getASTContext(); + + auto *anchor = getRawAnchor(); + if (!(isa(anchor) || isa(anchor) || + isa(anchor))) + return false; + + if (SynthesizedArgs.size() != 1) + return false; + + const auto &argument = SynthesizedArgs.front(); + auto *argType = argument.getPlainType()->castTo(); + auto *argLocator = argType->getImpl().getLocator(); + auto position = + argLocator->findLast()->getParamIdx(); + auto label = argument.getLabel(); + + SmallString<32> insertBuf; + llvm::raw_svector_ostream insertText(insertBuf); + + if (position != 0) + insertText << ", "; + + forFixIt(insertText, argument); + + Expr *fnExpr = nullptr; + Expr *argExpr = nullptr; + unsigned insertableEndIdx = 0; + bool hasTrailingClosure = false; + + std::tie(fnExpr, argExpr, insertableEndIdx, hasTrailingClosure) = + getCallInfo(anchor); + + if (!argExpr) + return false; + + if (hasTrailingClosure) + insertableEndIdx -= 1; + + if (position == 0 && insertableEndIdx != 0) + insertText << ", "; + + SourceLoc insertLoc; + if (auto *TE = dyn_cast(argExpr)) { + // fn(): + // fn([argMissing]) + // fn(argX, argY): + // fn([argMissing, ]argX, argY) + // fn(argX[, argMissing], argY) + // fn(argX, argY[, argMissing]) + // fn(argX) { closure }: + // fn([argMissing, ]argX) { closure } + // fn(argX[, argMissing]) { closure } + // fn(argX[, closureLabel: ]{closure}[, argMissing)] // Not impl. + if (insertableEndIdx == 0) + insertLoc = TE->getRParenLoc(); + else if (position != 0) { + auto argPos = std::min(TE->getNumElements(), position) - 1; + insertLoc = Lexer::getLocForEndOfToken( + ctx.SourceMgr, TE->getElement(argPos)->getEndLoc()); + } else { + insertLoc = TE->getElementNameLoc(0); + if (insertLoc.isInvalid()) + insertLoc = TE->getElement(0)->getStartLoc(); + } + } else { + auto *PE = cast(argExpr); + if (PE->getRParenLoc().isValid()) { + // fn(argX): + // fn([argMissing, ]argX) + // fn(argX[, argMissing]) + // fn() { closure }: + // fn([argMissing]) {closure} + // fn([closureLabel: ]{closure}[, argMissing]) // Not impl. + if (insertableEndIdx == 0) + insertLoc = PE->getRParenLoc(); + else if (position == 0) + insertLoc = PE->getSubExpr()->getStartLoc(); + else + insertLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, + PE->getSubExpr()->getEndLoc()); + } else { + // fn { closure }: + // fn[(argMissing)] { closure } + // fn[(closureLabel:] { closure }[, missingArg)] // Not impl. + assert(!isa(anchor) && "bracket less subscript"); + assert(PE->hasTrailingClosure() && + "paren less ParenExpr without trailing closure"); + insertBuf.insert(insertBuf.begin(), '('); + insertBuf.insert(insertBuf.end(), ')'); + insertLoc = + Lexer::getLocForEndOfToken(ctx.SourceMgr, fnExpr->getEndLoc()); + } + } + + if (insertLoc.isInvalid()) + return false; + + if (label.empty()) { + emitDiagnostic(insertLoc, diag::missing_argument_positional, position + 1) + .fixItInsert(insertLoc, insertText.str()); + } else if (isPropertyWrapperInitialization()) { + auto *TE = cast(fnExpr); + emitDiagnostic(TE->getLoc(), diag::property_wrapper_missing_arg_init, label, + resolveType(TE->getInstanceType())->getString()); + } else { + emitDiagnostic(insertLoc, diag::missing_argument_named, label) + .fixItInsert(insertLoc, insertText.str()); + } + + if (auto selectedOverload = getChoiceFor(getLocator())) { + if (auto *decl = selectedOverload->choice.getDeclOrNull()) { + emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + } + } + + return true; } bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { @@ -3600,14 +3822,15 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { if (!funcType) return false; - auto diff = funcType->getNumParams() - NumSynthesized; + unsigned numSynthesized = SynthesizedArgs.size(); + auto diff = funcType->getNumParams() - numSynthesized; // If the closure didn't specify any arguments and it is in a context that // needs some, produce a fixit to turn "{...}" into "{ _,_ in ...}". if (diff == 0) { auto diag = emitDiagnostic(closure->getStartLoc(), - diag::closure_argument_list_missing, NumSynthesized); + diag::closure_argument_list_missing, numSynthesized); std::string fixText; // Let's provide fixits for up to 10 args. if (funcType->getNumParams() <= 10) { @@ -3651,9 +3874,9 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { llvm::raw_svector_ostream OS(fixIt); OS << ","; - for (unsigned i = 0; i != NumSynthesized; ++i) { + for (unsigned i = 0; i != numSynthesized; ++i) { OS << ((onlyAnonymousParams) ? "_" : "<#arg#>"); - OS << ((i == NumSynthesized - 1) ? " " : ","); + OS << ((i == numSynthesized - 1) ? " " : ","); } diag.fixItInsertAfter(params->getEndLoc(), OS.str()); @@ -3662,6 +3885,168 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { return true; } +bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const { + auto *locator = getLocator(); + if (!locator->isLastElement(ConstraintLocator::ApplyArgument)) + return false; + + if (SynthesizedArgs.size() < 2) + return false; + + auto *anchor = getAnchor(); + + Expr *argExpr = nullptr; + // Something like `foo(x: (1, 2))` + if (auto *TE = dyn_cast(anchor)) { + if (TE->getNumElements() == 1) + argExpr = TE->getElement(0); + } else { // or `foo((1, 2))` + argExpr = cast(anchor)->getSubExpr(); + } + + if (!(argExpr && getType(argExpr)->getRValueType()->is())) + return false; + + auto selectedOverload = getChoiceFor(locator); + if (!selectedOverload) + return false; + + auto *decl = selectedOverload->choice.getDeclOrNull(); + if (!decl) + return false; + + auto name = decl->getBaseName(); + auto diagnostic = + emitDiagnostic(anchor->getLoc(), + diag::cannot_convert_single_tuple_into_multiple_arguments, + decl->getDescriptiveKind(), name, name.isSpecial(), + SynthesizedArgs.size(), isa(argExpr)); + + // If argument is a literal tuple, let's suggest removal of parentheses. + if (auto *TE = dyn_cast(argExpr)) { + diagnostic.fixItRemove(TE->getLParenLoc()).fixItRemove(TE->getRParenLoc()); + } + + diagnostic.flush(); + + // Add a note which points to the overload choice location. + emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName()); + return true; +} + +bool MissingArgumentsFailure::isPropertyWrapperInitialization() const { + auto *call = dyn_cast(getRawAnchor()); + if (!(call && call->isImplicit())) + return false; + + auto TE = dyn_cast(call->getFn()); + if (!TE) + return false; + + auto instanceTy = TE->getInstanceType(); + if (!instanceTy) + return false; + + auto *NTD = resolveType(instanceTy)->getAnyNominal(); + return NTD && NTD->getAttrs().hasAttribute(); +} + +bool MissingArgumentsFailure::isMisplacedMissingArgument( + ConstraintSystem &cs, ConstraintLocator *locator) { + auto *calleeLocator = cs.getCalleeLocator(locator); + auto overloadChoice = cs.findSelectedOverloadFor(calleeLocator); + if (!overloadChoice) + return false; + + auto *fnType = + cs.simplifyType(overloadChoice->ImpliedType)->getAs(); + if (!(fnType && fnType->getNumParams() == 2)) + return false; + + auto *anchor = locator->getAnchor(); + + auto hasFixFor = [&](FixKind kind, ConstraintLocator *locator) -> bool { + auto fix = llvm::find_if(cs.getFixes(), [&](const ConstraintFix *fix) { + return fix->getLocator() == locator; + }); + + if (fix == cs.getFixes().end()) + return false; + + return (*fix)->getKind() == kind; + }; + + auto *callLocator = + cs.getConstraintLocator(anchor, ConstraintLocator::ApplyArgument); + + auto argFlags = fnType->getParams()[0].getParameterFlags(); + auto *argLoc = cs.getConstraintLocator( + callLocator, LocatorPathElt::ApplyArgToParam(0, 0, argFlags)); + + if (!(hasFixFor(FixKind::AllowArgumentTypeMismatch, argLoc) && + hasFixFor(FixKind::AddMissingArguments, callLocator))) + return false; + + Expr *argExpr = nullptr; + if (auto *call = dyn_cast(anchor)) { + argExpr = call->getArg(); + } else if (auto *subscript = dyn_cast(anchor)) { + argExpr = subscript->getIndex(); + } else { + return false; + } + + Expr *argument = nullptr; + if (auto *PE = dyn_cast(argExpr)) { + argument = PE->getSubExpr(); + } else { + auto *tuple = cast(argExpr); + if (tuple->getNumElements() != 1) + return false; + argument = tuple->getElement(0); + } + + auto argType = cs.simplifyType(cs.getType(argument)); + auto paramType = fnType->getParams()[1].getPlainType(); + + auto &TC = cs.getTypeChecker(); + return TC.isConvertibleTo(argType, paramType, cs.DC); +} + +std::tuple +MissingArgumentsFailure::getCallInfo(Expr *anchor) const { + if (auto *call = dyn_cast(anchor)) { + return std::make_tuple(call->getFn(), call->getArg(), + call->getNumArguments(), call->hasTrailingClosure()); + } else if (auto *UME = dyn_cast(anchor)) { + return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(), + UME->hasTrailingClosure()); + } else if (auto *SE = dyn_cast(anchor)) { + return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), + SE->hasTrailingClosure()); + } + + return std::make_tuple(nullptr, nullptr, 0, false); +} + +void MissingArgumentsFailure::forFixIt( + llvm::raw_svector_ostream &out, + const AnyFunctionType::Param &argument) const { + if (argument.hasLabel()) + out << argument.getLabel().str() << ": "; + + // Explode inout type. + if (argument.isInOut()) + out << "&"; + + auto resolvedType = resolveType(argument.getPlainType()); + // @autoclosure; the type should be the result type. + if (argument.isAutoClosure()) + resolvedType = resolvedType->castTo()->getResult(); + + out << "<#" << resolvedType << "#>"; +} + bool ClosureParamDestructuringFailure::diagnoseAsError() { auto *closure = cast(getAnchor()); auto params = closure->getParameters(); @@ -4606,6 +4991,9 @@ void InOutConversionFailure::fixItChangeArgumentType() const { } bool ArgumentMismatchFailure::diagnoseAsError() { + if (diagnoseMisplacedMissingArgument()) + return true; + if (diagnoseConversionToBool()) return true; @@ -4835,6 +5223,33 @@ bool ArgumentMismatchFailure::diagnoseArchetypeMismatch() const { return true; } +bool ArgumentMismatchFailure::diagnoseMisplacedMissingArgument() const { + auto &cs = getConstraintSystem(); + auto *locator = getLocator(); + + if (!MissingArgumentsFailure::isMisplacedMissingArgument(cs, locator)) + return false; + + auto info = *getFunctionArgApplyInfo(locator); + + auto *argType = cs.createTypeVariable( + cs.getConstraintLocator(locator, LocatorPathElt::SynthesizedArgument(1)), + /*flags=*/0); + + // Assign new type variable to a type of a parameter. + auto *fnType = info.getFnType(); + const auto ¶m = fnType->getParams()[0]; + cs.assignFixedType(argType, param.getOldType()); + + auto *anchor = getRawAnchor(); + + MissingArgumentsFailure failure( + getParentExpr(), cs, {param.withType(argType)}, + cs.getConstraintLocator(anchor, ConstraintLocator::ApplyArgument)); + + return failure.diagnoseSingleMissingArgument(); +} + void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt( Expr *anchor) const { // If this is an array literal, offer to remove the brackets and pass the diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index a0a4fdc180786..b905876cb707a 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -794,7 +794,7 @@ class MissingExplicitConversionFailure final : public ContextualFailure { auto *DC = getDC(); auto &TC = getTypeChecker(); - auto asPG = TC.lookupPrecedenceGroup( + auto asPG = TypeChecker::lookupPrecedenceGroup( DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc()); if (!asPG) return true; @@ -805,7 +805,7 @@ class MissingExplicitConversionFailure final : public ContextualFailure { auto *DC = getDC(); auto &TC = getTypeChecker(); - auto asPG = TC.lookupPrecedenceGroup( + auto asPG = TypeChecker::lookupPrecedenceGroup( DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc()); if (!asPG) return true; @@ -1186,19 +1186,59 @@ class ImplicitInitOnNonConstMetatypeFailure final class MissingArgumentsFailure final : public FailureDiagnostic { using Param = AnyFunctionType::Param; - unsigned NumSynthesized; + SmallVector SynthesizedArgs; public: MissingArgumentsFailure(Expr *root, ConstraintSystem &cs, - unsigned numSynthesized, ConstraintLocator *locator) - : FailureDiagnostic(root, cs, locator), NumSynthesized(numSynthesized) {} + ArrayRef synthesizedArgs, + ConstraintLocator *locator) + : FailureDiagnostic(root, cs, locator), + SynthesizedArgs(synthesizedArgs.begin(), synthesizedArgs.end()) { + assert(!SynthesizedArgs.empty() && "No missing arguments?!"); + } bool diagnoseAsError() override; + bool diagnoseSingleMissingArgument() const; + private: /// If missing arguments come from a closure, /// let's produce tailored diagnostics. bool diagnoseClosure(ClosureExpr *closure); + + /// Diagnose cases when instead of multiple distinct arguments + /// call got a single tuple argument with expected arity/types. + bool diagnoseInvalidTupleDestructuring() const; + + /// Determine whether missing arguments are associated with + /// an implicit call to a property wrapper initializer e.g. + /// `@Foo(answer: 42) var question = "ultimate question"` + bool isPropertyWrapperInitialization() const; + + /// Gather informatioin associated with expression that represents + /// a call - function, arguments, # of arguments and whether it has + /// a trailing closure. + std::tuple getCallInfo(Expr *anchor) const; + + /// Transform given argument into format suitable for a fix-it + /// text e.g. `[