diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dae3d306273f..2d834ba12aa97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -933,7 +933,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") endif() endif() -find_package(Python2 COMPONENTS Interpreter REQUIRED) find_package(Python3 COMPONENTS Interpreter REQUIRED) # diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index f35339c9ebb70..9e60d04a4f5e3 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -176,6 +176,11 @@ Globals global ::= global 'MJ' // noncanonical specialized generic type metadata instantiation cache associated with global global ::= global 'MN' // noncanonical specialized generic type metadata for global + #if SWIFT_RUNTIME_VERSION >= 5.4 + global ::= context (decl-name '_')+ 'WZ' // global variable one-time initialization function + global ::= context (decl-name '_')+ 'Wz' // global variable one-time initialization token + #endif + A direct symbol resolves directly to the address of an object. An indirect symbol resolves to the address of a pointer to the object. They are distinct manglings to make a certain class of bugs diff --git a/docs/DynamicCasting.md b/docs/DynamicCasting.md index add2524d59e33..72b369bbb3c7c 100644 --- a/docs/DynamicCasting.md +++ b/docs/DynamicCasting.md @@ -191,7 +191,7 @@ Implementation Note: `AnyObject` is represented in memory as a pointer to a refc ### Objective-C Interactions Note the invariant above cannot be an equality because Objective-C bridging allows libraries to introduce new relationships that can alter the behavior of seemingly-unrelated casts. -One example of this is Foundation's `Number` (or `NSNumber`) type which conditionally bridges to several Swift numeric types. +One example of this is Foundation's `NSNumber` type which conditionally bridges to several Swift numeric types. As a result, when Foundation is in scope, `Int(7) is Double == false` but `(Int(7) as! AnyObject) is Double == true`. In general, the ability to add new bridging behaviors from a single type to several distinct types implies that Swift casting cannot be transitive. @@ -407,9 +407,10 @@ S.self.svar // 2 ``` Invariants -* If `T` conforms to `P` and `t` is an instance of `T`, then `t is P`, and `T.self is P.Type` +* If `T` conforms to `P` and `t` is an instance of `T`, then `t is P` and `T.self is P.Type` +* If `P` is a sub-protocol of `P1` and `T` is any type, then `T.self is P.Type` implies that `T.self is P1.Type` * Since every type `T` conforms to `Any`, `T.self is Any.Type` is always true -* `Any` self-conforms: `Any.self is Any.Type == true` +* Since every class type `C` conforms to `AnyObject`, `C.self is AnyObject.Type` is always true (this includes Objective-C class types) ### Note: "Self conforming" protocols @@ -439,10 +440,14 @@ let b : MyGenericType(a) As above, since `a` has type `P`, this code is instantiating `MyGenericType` with `T = P`, which is only valid if `P` conforms to `P`. Note that any protocol that specifies static methods, static properties, associated types, or initializers cannot possibly be self-conforming. -As of Swift 5.3, there are only three kinds of self-conforming protocols: -* `Any` must be self-conforming since every `T.self` is an instance of `Any.Type` -* `Error` is a self-conforming protocol -* Objective-C protocols that have no static requirements are self-conforming +As of Swift 5.3, the only self-conforming protocols are `Any`, `Error`, and Objective-C protocols that have no static requirements. + +Invariants +* `Any` self-conforms: `Any.self is Any.Type == true` +* `Error` self-conforms: `Error.self is Error.Type == true` +* If `P` self-conforms and is a sub-protocol of `P1`, then `P.self is P1.Type == true` + +For example, the last invariant here implies that for any Objective-C protocol `OP` that has no static requirements, `OP.self is AnyObject.Type`. This follows from the fact that `OP` self-conforms and that every Objective-C protocol has `AnyObject` as an implicit parent protocol. ## CoreFoundation types diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 01e7c69d225fc..c7642211ed533 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -62,6 +62,7 @@ namespace swift { class BoundGenericType; class ClangModuleLoader; class ClangNode; + class ClangTypeConverter; class ConcreteDeclRef; class ConstructorDecl; class Decl; @@ -618,6 +619,10 @@ class ASTContext final { Type getBridgedToObjC(const DeclContext *dc, Type type, Type *bridgedValueType = nullptr) const; +private: + ClangTypeConverter &getClangTypeConverter(); + +public: /// Get the Clang type corresponding to a Swift function type. /// /// \param params The function parameters. @@ -627,6 +632,14 @@ class ASTContext final { getClangFunctionType(ArrayRef params, Type resultTy, FunctionTypeRepresentation trueRep); + /// Get the canonical Clang type corresponding to a SIL function type. + /// + /// SIL analog of \c ASTContext::getClangFunctionType . + const clang::Type * + getCanonicalClangFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation trueRep); + /// Get the Swift declaration that a Clang declaration was exported from, /// if applicable. const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl); diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index d0118e48191b4..a62730af7777f 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -146,7 +146,8 @@ class ASTMangler : public Mangler { std::string mangleGlobalVariableFull(const VarDecl *decl); - std::string mangleGlobalInit(const VarDecl *decl, int counter, + std::string mangleGlobalInit(const PatternBindingDecl *decl, + unsigned entry, bool isInitFunc); std::string mangleReabstractionThunkHelper(CanSILFunctionType ThunkType, diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 0188ee25734df..8cf0815fd2246 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -63,6 +63,7 @@ namespace swift { class Type; class Expr; class DeclRefExpr; + class ForeignAsyncConvention; class ForeignErrorConvention; class LiteralExpr; class BraceStmt; @@ -6171,7 +6172,15 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// being dropped altogether. `None` is returned for a normal function /// or method. Optional getForeignFunctionAsMethodSelfParameterIndex() const; - + + /// Set information about the foreign async convention used by this + /// declaration. + void setForeignAsyncConvention(const ForeignAsyncConvention &convention); + + /// Get information about the foreign async convention used by this + /// declaration, given that it is @objc and 'async'. + Optional getForeignAsyncConvention() const; + static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_AbstractFunctionDecl && D->getKind() <= DeclKind::Last_AbstractFunctionDecl; @@ -6300,7 +6309,8 @@ class FuncDecl : public AbstractFunctionDecl { DeclContext *Parent); static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc, - DeclName Name, SourceLoc NameLoc, bool Throws, + DeclName Name, SourceLoc NameLoc, + bool Async, bool Throws, ParameterList *BodyParams, Type FnRetType, DeclContext *Parent, ClangNode ClangN); diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index f4c39ce036d06..72d8d64bbecb7 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -188,5 +188,19 @@ ERROR(scanner_find_cycle, none, ERROR(scanner_arguments_invalid, none, "dependencies scanner cannot be configured with arguments: '%0'", (StringRef)) +//------------------------------------------------------------------------------ +// MARK: custom attribute diagnostics +//------------------------------------------------------------------------------ + +ERROR(ambiguous_custom_attribute_ref,none, + "ambiguous use of attribute %0", (Identifier)) +NOTE(ambiguous_custom_attribute_ref_fix,none, + "use '%0.' to reference the attribute %1 in module %2", + (StringRef, Identifier, Identifier)) +NOTE(found_attribute_candidate,none, + "found this attribute", ()) +ERROR(unknown_attribute,none, + "unknown attribute '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index ac26d2e9b5e97..f21a9586ffd18 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1324,8 +1324,6 @@ ERROR(replace_equal_with_colon_for_value,none, "'=' has been replaced with ':' in attribute arguments", ()) ERROR(expected_attribute_name,none, "expected an attribute name", ()) -ERROR(unknown_attribute,none, - "unknown attribute '%0'", (StringRef)) ERROR(unexpected_lparen_in_attribute,none, "unexpected '(' in attribute '%0'", (StringRef)) ERROR(duplicate_attribute,none, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 476483db15ddc..741992c24280c 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -112,6 +112,9 @@ ERROR(expected_argument_in_contextual_member,none, "member %0 expects argument of type %1", (DeclName, Type)) ERROR(expected_parens_in_contextual_member,none, "member %0 is a function; did you mean to call it?", (DeclName)) +ERROR(expected_parens_in_contextual_member_type,none, + "member %0 is a function that produces expected type %1; did you mean to " + "call it?", (DeclName, Type)) ERROR(expected_result_in_contextual_member,none, "member %0 in %2 produces result of type %1, but context expects %2", @@ -453,6 +456,10 @@ ERROR(cannot_convert_closure_result_nil,none, ERROR(cannot_convert_parent_type,none, "cannot convert parent type %0 to expected type %1", (Type, Type)) +ERROR(cannot_convert_chain_result_type,none, + "member chain produces result of type %0 but contextual base was " + "inferred as %1", + (Type, Type)) NOTE(generic_argument_mismatch,none, "arguments to generic parameter %0 (%1 and %2) are expected to be equal", @@ -1082,6 +1089,9 @@ NOTE(unwrap_with_guard,none, ERROR(optional_base_not_unwrapped,none, "value of optional type %0 must be unwrapped to refer to member %1 of " "wrapped base type %2", (Type, DeclNameRef, Type)) +ERROR(invalid_optional_infered_keypath_root, none, + "key path root inferred as optional type %0 must be unwrapped to refer to member %1 " + "of unwrapped type %2", (Type, DeclNameRef, Type)) NOTE(optional_base_chain,none, "chain the optional using '?' to access member %0 only for non-'nil' " "base values", (DeclNameRef)) @@ -1089,6 +1099,12 @@ NOTE(optional_base_remove_optional_for_keypath_root, none, "use unwrapped type %0 as key path root", (Type)) NOTE(optional_keypath_application_base, none, "use '?' to access key path subscript only for non-'nil' base values", ()) +NOTE(optional_key_path_root_base_chain, none, + "chain the optional using '?.' to access unwrapped type member %0", + (DeclNameRef)) +NOTE(optional_key_path_root_base_unwrap, none, + "unwrap the optional using '!.' to access unwrapped type member %0", + (DeclNameRef)) ERROR(missing_unwrap_optional_try,none, "value of optional type %0 not unwrapped; did you mean to use 'try!' " @@ -1295,8 +1311,9 @@ ERROR(nominal_type_not_attribute,none, ERROR(mutating_invalid_global_scope,none, "%0 is only valid on methods", (SelfAccessKind)) -ERROR(mutating_invalid_classes,none, "%0 isn't valid on methods in " - "classes or class-bound protocols", (SelfAccessKind)) +ERROR(mutating_invalid_classes,none, "%0 is not valid on %1s in " + "%select{classes|class-bound protocols}2", + (SelfAccessKind, DescriptiveDeclKind, bool)) ERROR(functions_mutating_and_not,none, "method must not be declared both %0 and %1", diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 6e9b24921b1ff..b53a279a93b4c 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -249,17 +249,8 @@ class alignas(8) Expr { NumArgLabels : 16 ); - SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 1+1+1+16, - /// Whether the UnresolvedMemberExpr has arguments. - HasArguments : 1, - /// Whether the UnresolvedMemberExpr also has source locations for the - /// argument label. - HasArgLabelLocs : 1, - /// Whether the last argument is a trailing closure. - HasTrailingClosure : 1, - : NumPadBits, - /// # of argument labels stored after the UnresolvedMemberExpr. - NumArgLabels : 16 + SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 2, + FunctionRefKind : 2 ); SWIFT_INLINE_BITFIELD(OverloadSetRefExpr, Expr, 2, @@ -1841,71 +1832,49 @@ class DynamicSubscriptExpr final /// member, which is to be resolved with context sensitive type information into /// bar.foo. These always have unresolved type. class UnresolvedMemberExpr final - : public Expr, - public TrailingCallArguments { + : public Expr { SourceLoc DotLoc; DeclNameLoc NameLoc; DeclNameRef Name; - Expr *Argument; - - UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, - DeclNameRef name, Expr *argument, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit); public: - /// Create a new unresolved member expression with no arguments. - static UnresolvedMemberExpr *create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - bool implicit); - - /// Create a new unresolved member expression. - static UnresolvedMemberExpr *create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit); + UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, DeclNameRef name, + bool implicit) + : Expr(ExprKind::UnresolvedMember, implicit), DotLoc(dotLoc), + NameLoc(nameLoc), Name(name) { + // FIXME: Really, we should be setting this to `FunctionRefKind::Compound` + // if `NameLoc` is compound, but this would be a source break for cases like + // ``` + // struct S { + // static func makeS(_: Int) -> S! { S() } + // } + // + // let s: S = .makeS(_:)(0) + // ``` + // Instead, we should store compound-ness as a separate bit from applied/ + // unapplied. + Bits.UnresolvedMemberExpr.FunctionRefKind = + static_cast(FunctionRefKind::Unapplied); + } DeclNameRef getName() const { return Name; } DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getDotLoc() const { return DotLoc; } - Expr *getArgument() const { return Argument; } - void setArgument(Expr *argument) { Argument = argument; } - /// Whether this reference has arguments. - bool hasArguments() const { - return Bits.UnresolvedMemberExpr.HasArguments; - } - - unsigned getNumArguments() const { - return Bits.UnresolvedMemberExpr.NumArgLabels; - } - - bool hasArgumentLabelLocs() const { - return Bits.UnresolvedMemberExpr.HasArgLabelLocs; - } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } - /// Whether this call with written with a trailing closure. - bool hasTrailingClosure() const { - return Bits.UnresolvedMemberExpr.HasTrailingClosure; - } + SourceLoc getStartLoc() const { return DotLoc; } + SourceLoc getEndLoc() const { return NameLoc.getSourceRange().End; } - /// Return the index of the unlabeled trailing closure argument. - Optional getUnlabeledTrailingClosureIndex() const { - return getArgument()->getUnlabeledTrailingClosureIndexOfPackedArgument(); + /// Retrieve the kind of function reference. + FunctionRefKind getFunctionRefKind() const { + return static_cast( + Bits.UnresolvedMemberExpr.FunctionRefKind); } - SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } - - SourceLoc getStartLoc() const { return DotLoc; } - SourceLoc getEndLoc() const { - return (Argument ? Argument->getEndLoc() : NameLoc.getSourceRange().End); + /// Set the kind of function reference. + void setFunctionRefKind(FunctionRefKind refKind) { + Bits.UnresolvedMemberExpr.FunctionRefKind = static_cast(refKind); } static bool classof(const Expr *E) { @@ -2088,6 +2057,31 @@ class ParenExpr : public IdentityExpr { static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; } }; + +/// Represents the result of a chain of accesses or calls hanging off of an +/// \c UnresolvedMemberExpr at the root. This is only used during type checking +/// to give the result type of such a chain representation in the AST. This +/// expression type is always implicit. +class UnresolvedMemberChainResultExpr : public IdentityExpr { + /// The base of this chain of member accesses. + UnresolvedMemberExpr *ChainBase; +public: + UnresolvedMemberChainResultExpr(Expr *subExpr, UnresolvedMemberExpr *base, + Type ty = Type()) + : IdentityExpr(ExprKind::UnresolvedMemberChainResult, subExpr, ty, + /*isImplicit=*/true), + ChainBase(base) { + assert(base); + } + + UnresolvedMemberExpr *getChainBase() const { return ChainBase; } + + SWIFT_FORWARD_SOURCE_LOCS_TO(getSubExpr()) + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::UnresolvedMemberChainResult; + } +}; /// AwaitExpr - An 'await' surrounding an expression, marking that the /// expression contains code which is a coroutine that may block. diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 53ee2da310a42..7c98a83c0afd9 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -104,7 +104,8 @@ ABSTRACT_EXPR(Identity, Expr) EXPR(Paren, IdentityExpr) EXPR(DotSelf, IdentityExpr) EXPR(Await, IdentityExpr) - EXPR_RANGE(Identity, Paren, Await) + EXPR(UnresolvedMemberChainResult, IdentityExpr) + EXPR_RANGE(Identity, Paren, UnresolvedMemberChainResult) ABSTRACT_EXPR(AnyTry, Expr) EXPR(Try, AnyTryExpr) EXPR(ForceTry, AnyTryExpr) diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index a19023f621042..55ea27bc47dc8 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -194,16 +194,8 @@ class ASTExtInfoBuilder { using Representation = FunctionTypeRepresentation; - static void assertIsFunctionType(const clang::Type *); - ASTExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) - : bits(bits), clangTypeInfo(clangTypeInfo) { - // TODO: [clang-function-type-serialization] Once we start serializing - // the Clang type, we should also assert that the pointer is non-null. - auto Rep = Representation(bits & RepresentationMask); - if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type) - assertIsFunctionType(clangTypeInfo.type); - } + : bits(bits), clangTypeInfo(clangTypeInfo) {} public: // Constructor with all defaults. @@ -254,10 +246,7 @@ class ASTExtInfoBuilder { DifferentiabilityKind::NonDifferentiable; } - /// Get the underlying ClangTypeInfo value if it is not the default value. - Optional getClangTypeInfo() const { - return clangTypeInfo.empty() ? Optional() : clangTypeInfo; - } + ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; } constexpr SILFunctionTypeRepresentation getSILRepresentation() const { unsigned rawRep = bits & RepresentationMask; @@ -404,9 +393,7 @@ class ASTExtInfo { constexpr bool isDifferentiable() const { return builder.isDifferentiable(); } - Optional getClangTypeInfo() const { - return builder.getClangTypeInfo(); - } + ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); } constexpr bool hasSelfParam() const { return builder.hasSelfParam(); } @@ -495,16 +482,17 @@ class SILExtInfoBuilder { // If bits are added or removed, then TypeBase::SILFunctionTypeBits // and NumMaskBits must be updated, and they must match. - // |representation|pseudogeneric| noescape |differentiability| - // | 0 .. 3 | 4 | 5 | 6 .. 7 | + // |representation|pseudogeneric| noescape | async | differentiability| + // | 0 .. 3 | 4 | 5 | 6 | 7 .. 8 | // enum : unsigned { RepresentationMask = 0xF << 0, PseudogenericMask = 1 << 4, NoEscapeMask = 1 << 5, - DifferentiabilityMaskOffset = 6, + AsyncMask = 1 << 6, + DifferentiabilityMaskOffset = 7, DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset, - NumMaskBits = 8 + NumMaskBits = 9 }; unsigned bits; // Naturally sized for speed. @@ -517,19 +505,32 @@ class SILExtInfoBuilder { SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo) : bits(bits), clangTypeInfo(clangTypeInfo) {} + static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric, + bool isNoEscape, bool isAsync, + DifferentiabilityKind diffKind) { + return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | + (isNoEscape ? NoEscapeMask : 0) | (isAsync ? AsyncMask : 0) | + (((unsigned)diffKind << DifferentiabilityMaskOffset) & + DifferentiabilityMask); + } + public: // Constructor with all defaults. - SILExtInfoBuilder() : bits(0), clangTypeInfo(ClangTypeInfo(nullptr)) {} + SILExtInfoBuilder() : SILExtInfoBuilder(0, ClangTypeInfo(nullptr)) {} // Constructor for polymorphic type. SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape, - DifferentiabilityKind diffKind, const clang::Type *type) - : SILExtInfoBuilder( - ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) | - (isNoEscape ? NoEscapeMask : 0) | - (((unsigned)diffKind << DifferentiabilityMaskOffset) & - DifferentiabilityMask), - ClangTypeInfo(type)) {} + bool isAsync, DifferentiabilityKind diffKind, + const clang::Type *type) + : SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isAsync, + diffKind), + ClangTypeInfo(type)) {} + + SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric) + : SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric, + info.isNoEscape(), info.isAsync(), + info.getDifferentiabilityKind()), + info.getClangTypeInfo()) {} void checkInvariants() const; @@ -552,6 +553,8 @@ class SILExtInfoBuilder { // Is this function guaranteed to be no-escape by the type system? constexpr bool isNoEscape() const { return bits & NoEscapeMask; } + constexpr bool isAsync() const { return bits & AsyncMask; } + constexpr DifferentiabilityKind getDifferentiabilityKind() const { return DifferentiabilityKind((bits & DifferentiabilityMask) >> DifferentiabilityMaskOffset); @@ -562,10 +565,8 @@ class SILExtInfoBuilder { DifferentiabilityKind::NonDifferentiable; } - /// Get the underlying ClangTypeInfo value if it is not the default value. - Optional getClangTypeInfo() const { - return clangTypeInfo.empty() ? Optional() : clangTypeInfo; - } + /// Get the underlying ClangTypeInfo value. + ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; } constexpr bool hasSelfParam() const { switch (getRepresentation()) { @@ -616,6 +617,10 @@ class SILExtInfoBuilder { : (bits & ~NoEscapeMask), clangTypeInfo); } + SILExtInfoBuilder withAsync(bool isAsync = true) const { + return SILExtInfoBuilder(isAsync ? (bits | AsyncMask) : (bits & ~AsyncMask), + clangTypeInfo); + } SILExtInfoBuilder withDifferentiabilityKind(DifferentiabilityKind differentiability) const { return SILExtInfoBuilder( @@ -657,8 +662,8 @@ class SILExtInfo { static SILExtInfo getThin() { return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false, - false, DifferentiabilityKind::NonDifferentiable, - nullptr) + false, false, + DifferentiabilityKind::NonDifferentiable, nullptr) .build(); } @@ -681,15 +686,15 @@ class SILExtInfo { constexpr bool isNoEscape() const { return builder.isNoEscape(); } + constexpr bool isAsync() const { return builder.isAsync(); } + constexpr DifferentiabilityKind getDifferentiabilityKind() const { return builder.getDifferentiabilityKind(); } constexpr bool isDifferentiable() const { return builder.isDifferentiable(); } - Optional getClangTypeInfo() const { - return builder.getClangTypeInfo(); - } + ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); } constexpr bool hasSelfParam() const { return builder.hasSelfParam(); } diff --git a/include/swift/AST/ForeignAsyncConvention.h b/include/swift/AST/ForeignAsyncConvention.h new file mode 100644 index 0000000000000..f3657766e02af --- /dev/null +++ b/include/swift/AST/ForeignAsyncConvention.h @@ -0,0 +1,81 @@ +//===--- ForeignAsyncConvention.h - Async conventions -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the ForeignAsyncConvention structure, which +// describes the rules for how to detect that a foreign API is asynchronous. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_FOREIGN_ASYNC_CONVENTION_H +#define SWIFT_FOREIGN_ASYNC_CONVENTION_H + +#include "swift/AST/Type.h" + +namespace swift { + +/// A small structure describing the async convention of a foreign declaration. +class ForeignAsyncConvention { + /// The index of the completion handler parameters. + unsigned CompletionHandlerParamIndex; + + /// When non-zero, indicates which parameter to the completion handler is the + /// Error? parameter (minus one) that makes this async function also throwing. + unsigned CompletionHandlerErrorParamIndex; +public: + ForeignAsyncConvention() + : CompletionHandlerParamIndex(0), CompletionHandlerErrorParamIndex(0) { } + + ForeignAsyncConvention(unsigned completionHandlerParamIndex, + Optional completionHandlerErrorParamIndex) + : CompletionHandlerParamIndex(completionHandlerParamIndex), + CompletionHandlerErrorParamIndex( + completionHandlerErrorParamIndex + ? *completionHandlerErrorParamIndex + 1 + : 0) {} + + /// Retrieve the index of the completion handler parameter, which will be + /// erased from the Swift signature of the imported async function. + unsigned completionHandlerParamIndex() const { + return CompletionHandlerParamIndex; + } + + /// Retrieve the index of the \c Error? parameter in the completion handler's + /// parameter list. When argument passed to this parameter is non-null, the + /// provided error will be thrown by the async function. + Optional completionHandlerErrorParamIndex() const { + if (CompletionHandlerErrorParamIndex == 0) + return None; + + return CompletionHandlerErrorParamIndex - 1; + } + + /// Whether the async function is throwing due to the completion handler + /// having an \c Error? parameter. + /// + /// Equivalent to \c static_cast(completionHandlerErrorParamIndex()). + bool isThrowing() const { + return CompletionHandlerErrorParamIndex != 0; + } + + bool operator==(ForeignAsyncConvention other) const { + return CompletionHandlerParamIndex == other.CompletionHandlerParamIndex + && CompletionHandlerErrorParamIndex == + other.CompletionHandlerErrorParamIndex; + } + bool operator!=(ForeignAsyncConvention other) const { + return !(*this == other); + } +}; + +} + +#endif diff --git a/include/swift/AST/ForeignErrorConvention.h b/include/swift/AST/ForeignErrorConvention.h index 48d65d4612856..d09a7a80c0d86 100644 --- a/include/swift/AST/ForeignErrorConvention.h +++ b/include/swift/AST/ForeignErrorConvention.h @@ -81,6 +81,10 @@ class ForeignErrorConvention { } Info() = default; + + Kind getKind() const { + return static_cast(TheKind); + } }; private: @@ -178,11 +182,24 @@ class ForeignErrorConvention { /// Returns the physical result type of the function, for functions /// that completely erase this information. CanType getResultType() const { - assert(getKind() == ZeroResult || - getKind() == NonZeroResult); + assert(resultTypeErasedToVoid(getKind())); return ResultType; } - + + /// Whether this kind of error import erases the result type to 'Void'. + static bool resultTypeErasedToVoid(Kind kind) { + switch (kind) { + case ZeroResult: + case NonZeroResult: + return true; + + case ZeroPreservedResult: + case NilResult: + case NonNilError: + return false; + } + } + bool operator==(ForeignErrorConvention other) const { return info.TheKind == other.info.TheKind && info.ErrorIsOwned == other.info.ErrorIsOwned diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h index 6424dd12a72f2..13630507bb3a5 100644 --- a/include/swift/AST/Pattern.h +++ b/include/swift/AST/Pattern.h @@ -554,6 +554,9 @@ class EnumElementPattern : public Pattern { bool hasUnresolvedOriginalExpr() const { return ElementDeclOrUnresolvedOriginalExpr.is(); } + void setUnresolvedOriginalExpr(Expr *e) { + ElementDeclOrUnresolvedOriginalExpr = e; + } DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 1136fb5be73cd..1f61cdf438175 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -465,21 +465,22 @@ class NormalProtocolConformance : public RootProtocolConformance, uint64_t LoaderContextData; friend class ASTContext; + void resolveLazyInfo() const; + + void differenceAndStoreConditionalRequirements() const; + +public: NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol, SourceLoc loc, DeclContext *dc, ProtocolConformanceState state) - : RootProtocolConformance(ProtocolConformanceKind::Normal, conformingType), - ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false) - { + : RootProtocolConformance(ProtocolConformanceKind::Normal, + conformingType), + ProtocolAndState(protocol, state), Loc(loc), + ContextAndInvalid(dc, false) { assert(!conformingType->hasArchetype() && "ProtocolConformances should store interface types"); } - void resolveLazyInfo() const; - - void differenceAndStoreConditionalRequirements() const; - -public: /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); } diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index b04f82bb9a8de..f827339dd5064 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -89,6 +89,7 @@ TYPE(Error, Type) UNCHECKED_TYPE(Unresolved, Type) +UNCHECKED_TYPE(Hole, Type) ABSTRACT_TYPE(Builtin, Type) ABSTRACT_TYPE(AnyBuiltinInteger, BuiltinType) BUILTIN_TYPE(BuiltinInteger, AnyBuiltinIntegerType) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index e55c8bf7be3d5..328f4c0aff762 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -148,7 +148,10 @@ class RecursiveTypeProperties { /// This type contains an OpaqueTypeArchetype. HasOpaqueArchetype = 0x400, - Last_Property = HasOpaqueArchetype + /// This type contains a type hole. + HasTypeHole = 0x800, + + Last_Property = HasTypeHole }; enum { BitWidth = countBitsUsed(Property::Last_Property) }; @@ -203,6 +206,10 @@ class RecursiveTypeProperties { /// generic type? bool hasUnboundGeneric() const { return Bits & HasUnboundGeneric; } + /// Does a type with these properties structurally contain a + /// type hole? + bool hasTypeHole() const { return Bits & HasTypeHole; } + /// Returns the set of properties present in either set. friend RecursiveTypeProperties operator|(Property lhs, Property rhs) { return RecursiveTypeProperties(unsigned(lhs) | unsigned(rhs)); @@ -308,7 +315,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { protected: enum { NumAFTExtInfoBits = 9 }; - enum { NumSILExtInfoBits = 8 }; + enum { NumSILExtInfoBits = 9 }; union { uint64_t OpaqueBits; SWIFT_INLINE_BITFIELD_BASE(TypeBase, bitmax(NumTypeKindBits,8) + @@ -362,12 +369,11 @@ class alignas(1 << TypeAlignInBits) TypeBase { ID : 32 ); - SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+1+2+1+1, + SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+3+1+2+1+1, ExtInfoBits : NumSILExtInfoBits, HasClangTypeInfo : 1, CalleeConvention : 3, HasErrorResult : 1, - IsAsync : 1, CoroutineKind : 2, HasInvocationSubs : 1, HasPatternSubs : 1 @@ -574,9 +580,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { } /// Determine whether this type involves a hole. - bool hasHole() const { - return getRecursiveProperties().hasUnresolvedType(); - } + bool hasHole() const { return getRecursiveProperties().hasTypeHole(); } /// Determine whether the type involves a context-dependent archetype. bool hasArchetype() const { @@ -2873,7 +2877,7 @@ class AnyFunctionType : public TypeBase { unsigned NumParams, ExtInfo Info) : TypeBase(Kind, CanTypeContext, properties), Output(Output) { Bits.AnyFunctionType.ExtInfoBits = Info.getBits(); - Bits.AnyFunctionType.HasClangTypeInfo = Info.getClangTypeInfo().hasValue(); + Bits.AnyFunctionType.HasClangTypeInfo = !Info.getClangTypeInfo().empty(); Bits.AnyFunctionType.NumParams = NumParams; assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!"); // The use of both assert() and static_assert() is intentional. @@ -3980,7 +3984,7 @@ class SILFunctionType final + 1); } - SILFunctionType(GenericSignature genericSig, ExtInfo ext, bool isAsync, + SILFunctionType(GenericSignature genericSig, ExtInfo ext, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3994,8 +3998,7 @@ class SILFunctionType final public: static CanSILFunctionType - get(GenericSignature genericSig, ExtInfo ext, bool isAsync, - SILCoroutineKind coroutineKind, + get(GenericSignature genericSig, ExtInfo ext, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef interfaceParams, ArrayRef interfaceYields, @@ -4048,7 +4051,7 @@ class SILFunctionType final return SILCoroutineKind(Bits.SILFunctionType.CoroutineKind); } - bool isAsync() const { return Bits.SILFunctionType.IsAsync; } + bool isAsync() const { return getExtInfo().isAsync(); } /// Return the array of all the yields. ArrayRef getYields() const { @@ -4577,14 +4580,14 @@ class SILFunctionType final void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInvocationGenericSignature(), - getExtInfo(), isAsync(), getCoroutineKind(), getCalleeConvention(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), getWitnessMethodConformanceOrInvalid(), getPatternSubstitutions(), getInvocationSubstitutions()); } static void Profile(llvm::FoldingSetNodeID &ID, GenericSignature genericSig, ExtInfo info, - bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, + SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, ArrayRef yields, ArrayRef results, Optional errorResult, ProtocolConformanceRef conformance, @@ -5728,6 +5731,31 @@ TypeVariableType : public TypeBase { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type) +/// HoleType - This represents a placeholder type for a type variable +/// or dependent member type that cannot be resolved to a concrete type +/// because the expression is ambiguous. This type is only used by the +/// constraint solver and transformed into UnresolvedType to be used in AST. +class HoleType : public TypeBase { + using OriginatorType = + llvm::PointerUnion; + + OriginatorType Originator; + + HoleType(ASTContext &C, OriginatorType originator, + RecursiveTypeProperties properties) + : TypeBase(TypeKind::Hole, &C, properties), Originator(originator) {} + +public: + static Type get(ASTContext &ctx, OriginatorType originatorType); + + OriginatorType getOriginatorType() const { return Originator; } + + static bool classof(const TypeBase *T) { + return T->getKind() == TypeKind::Hole; + } +}; +DEFINE_EMPTY_CAN_TYPE_WRAPPER(HoleType, Type) + inline bool TypeBase::isTypeVariableOrMember() { if (is()) return true; diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 468a0711f90f4..1c3c612f9e98a 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -294,6 +294,9 @@ NODE(CanonicalSpecializedGenericTypeMetadataAccessFunction) NODE(MetadataInstantiationCache) NODE(NoncanonicalSpecializedGenericTypeMetadata) NODE(NoncanonicalSpecializedGenericTypeMetadataCache) +NODE(GlobalVariableOnceFunction) +NODE(GlobalVariableOnceToken) +NODE(GlobalVariableOnceDeclList) #undef CONTEXT_NODE #undef NODE diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index a97033597cdc5..84f74b1b26f0b 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -18,10 +18,12 @@ #ifndef SWIFT_DEMANGLING_TYPEDECODER_H #define SWIFT_DEMANGLING_TYPEDECODER_H +#include "TypeLookupError.h" #include "swift/ABI/MetadataValues.h" +#include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/NamespaceMacros.h" -#include "swift/Basic/LLVM.h" +#include "swift/Runtime/Portability.h" #include "swift/Runtime/Unreachable.h" #include "swift/Strings.h" #include "llvm/ADT/ArrayRef.h" @@ -238,49 +240,60 @@ class ImplFunctionTypeFlags { unsigned Rep : 3; unsigned Pseudogeneric : 1; unsigned Escaping : 1; + unsigned Async : 1; unsigned DifferentiabilityKind : 2; public: ImplFunctionTypeFlags() - : Rep(0), Pseudogeneric(0), Escaping(0), DifferentiabilityKind(0) {} + : Rep(0), Pseudogeneric(0), Escaping(0), Async(0), + DifferentiabilityKind(0) {} ImplFunctionTypeFlags(ImplFunctionRepresentation rep, bool pseudogeneric, - bool noescape, + bool noescape, bool async, ImplFunctionDifferentiabilityKind diffKind) : Rep(unsigned(rep)), Pseudogeneric(pseudogeneric), Escaping(noescape), - DifferentiabilityKind(unsigned(diffKind)) {} + Async(async), DifferentiabilityKind(unsigned(diffKind)) {} ImplFunctionTypeFlags withRepresentation(ImplFunctionRepresentation rep) const { return ImplFunctionTypeFlags( - rep, Pseudogeneric, Escaping, + rep, Pseudogeneric, Escaping, Async, + ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); + } + + ImplFunctionTypeFlags + withAsync() const { + return ImplFunctionTypeFlags( + ImplFunctionRepresentation(Rep), Pseudogeneric, Escaping, true, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withEscaping() const { return ImplFunctionTypeFlags( - ImplFunctionRepresentation(Rep), Pseudogeneric, true, + ImplFunctionRepresentation(Rep), Pseudogeneric, true, Async, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withPseudogeneric() const { return ImplFunctionTypeFlags( - ImplFunctionRepresentation(Rep), true, Escaping, + ImplFunctionRepresentation(Rep), true, Escaping, Async, ImplFunctionDifferentiabilityKind(DifferentiabilityKind)); } ImplFunctionTypeFlags withDifferentiabilityKind(ImplFunctionDifferentiabilityKind diffKind) const { return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep), Pseudogeneric, - Escaping, diffKind); + Escaping, Async, diffKind); } ImplFunctionRepresentation getRepresentation() const { return ImplFunctionRepresentation(Rep); } + bool isAsync() const { return Async; } + bool isEscaping() const { return Escaping; } bool isPseudogeneric() const { return Pseudogeneric; } @@ -317,6 +330,14 @@ getObjCClassOrProtocolName(NodePointer node) { } #endif +#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \ + TypeLookupError("TypeDecoder.h:%d: Node kind %u \"%.*s\" - " Fmt, __LINE__, \ + Node->getKind(), \ + Node->hasText() ? (int)Node->getText().size() : 0, \ + Node->hasText() ? Node->getText().data() : "", __VA_ARGS__) + +#define MAKE_NODE_TYPE_ERROR0(Node, Str) MAKE_NODE_TYPE_ERROR(Node, "%s", Str) + /// Decode a mangled type to construct an abstract type, forming such /// types by invoking a custom builder. template @@ -333,24 +354,25 @@ class TypeDecoder { : Builder(Builder) {} /// Given a demangle tree, attempt to turn it into a type. - BuiltType decodeMangledType(NodePointer Node) { - if (!Node) return BuiltType(); + TypeLookupErrorOr decodeMangledType(NodePointer Node) { + if (!Node) + return TypeLookupError("Node is NULL"); using NodeKind = Demangle::Node::Kind; switch (Node->getKind()) { case NodeKind::Global: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::TypeMangling: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::Type: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children."); return decodeMangledType(Node->getChild(0)); case NodeKind::Class: @@ -369,8 +391,8 @@ class TypeDecoder { BuiltTypeDecl typeDecl = BuiltTypeDecl(); BuiltType parent = BuiltType(); bool typeAlias = false; - if (!decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias)) - return BuiltType(); + if (auto error = decodeMangledTypeDecl(Node, typeDecl, parent, typeAlias)) + return *error; if (typeAlias) return Builder.createTypeAliasType(typeDecl, parent); @@ -384,19 +406,21 @@ class TypeDecoder { case NodeKind::BoundGenericTypeAlias: case NodeKind::BoundGenericOtherNominalType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); llvm::SmallVector args; const auto &genericArgs = Node->getChild(1); if (genericArgs->getKind() != NodeKind::TypeList) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList"); for (auto genericArg : *genericArgs) { auto paramType = decodeMangledType(genericArg); - if (!paramType) - return BuiltType(); - args.push_back(paramType); + if (paramType.isError()) + return paramType; + args.push_back(paramType.getType()); } auto ChildNode = Node->getChild(0); @@ -413,9 +437,9 @@ class TypeDecoder { BuiltTypeDecl typeDecl = BuiltTypeDecl(); BuiltType parent = BuiltType(); bool typeAlias = false; - if (!decodeMangledTypeDecl(ChildNode, typeDecl, - parent, typeAlias)) - return BuiltType(); + if (auto error = + decodeMangledTypeDecl(ChildNode, typeDecl, parent, typeAlias)) + return *error; return Builder.createBoundGenericType(typeDecl, args, parent); } @@ -445,11 +469,15 @@ class TypeDecoder { // But when resolving it to a type, we want to *keep* the argument // so that the parent type becomes 'S' and not 'P'. if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); const auto &genericArgs = Node->getChild(1); if (genericArgs->getNumChildren() != 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(genericArgs, + "expected 1 generic argument, saw %u", + genericArgs->getNumChildren()); return decodeMangledType(genericArgs->getChild(0)); } @@ -469,7 +497,7 @@ class TypeDecoder { auto reprNode = Node->getChild(i++); if (reprNode->getKind() != NodeKind::MetatypeRepresentation || !reprNode->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(reprNode, "wrong node kind or no text"); if (reprNode->getText() == "@thin") repr = ImplMetatypeRepresentation::Thin; else if (reprNode->getText() == "@thick") @@ -477,26 +505,28 @@ class TypeDecoder { else if (reprNode->getText() == "@objc_metatype") repr = ImplMetatypeRepresentation::ObjC; } else if (Node->getNumChildren() < 1) { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); } auto instance = decodeMangledType(Node->getChild(i)); - if (!instance) - return BuiltType(); + if (instance.isError()) + return instance; if (Node->getKind() == NodeKind::Metatype) { - return Builder.createMetatypeType(instance, repr); + return Builder.createMetatypeType(instance.getType(), repr); } else if (Node->getKind() == NodeKind::ExistentialMetatype) { - return Builder.createExistentialMetatypeType(instance, repr); + return Builder.createExistentialMetatypeType(instance.getType(), repr); } else { assert(false); - return nullptr; + return MAKE_NODE_TYPE_ERROR0(Node, + "Metatype/ExistentialMetatype Node " + "had a different kind when re-checked"); } } case NodeKind::ProtocolList: case NodeKind::ProtocolListWithAnyObject: case NodeKind::ProtocolListWithClass: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); // Find the protocol list. llvm::SmallVector Protocols; @@ -511,7 +541,8 @@ class TypeDecoder { if (auto Protocol = decodeMangledProtocolType(componentType)) Protocols.push_back(Protocol); else - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(componentType, + "failed to decode protocol type"); } // Superclass or AnyObject, if present. @@ -519,11 +550,15 @@ class TypeDecoder { auto Superclass = BuiltType(); if (Node->getKind() == NodeKind::ProtocolListWithClass) { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto superclassNode = Node->getChild(1); - Superclass = decodeMangledType(superclassNode); - if (!Superclass) return BuiltType(); + auto result = decodeMangledType(superclassNode); + if (result.isError()) + return result; + Superclass = result.getType(); IsClassBound = true; } else if (Node->getKind() == NodeKind::ProtocolListWithAnyObject) { @@ -541,17 +576,18 @@ class TypeDecoder { /*IsClassBound=*/false); } - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "failed to decode protocol type"); } case NodeKind::DynamicSelf: { if (Node->getNumChildren() != 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, "expected 1 child, saw %u", + Node->getNumChildren()); auto selfType = decodeMangledType(Node->getChild(0)); - if (!selfType) - return BuiltType(); + if (selfType.isError()) + return selfType; - return Builder.createDynamicSelfType(selfType); + return Builder.createDynamicSelfType(selfType.getType()); } case NodeKind::DependentGenericParamType: { auto depth = Node->getChild(0)->getIndex(); @@ -571,7 +607,9 @@ class TypeDecoder { case NodeKind::EscapingLinearFunctionType: case NodeKind::FunctionType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); FunctionTypeFlags flags; if (Node->getKind() == NodeKind::ObjCBlock || @@ -622,13 +660,16 @@ class TypeDecoder { flags = flags.withAsync(isAsync).withThrows(isThrow); if (Node->getNumChildren() < firstChildIdx + 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (%u)", + Node->getNumChildren(), firstChildIdx + 2); bool hasParamFlags = false; llvm::SmallVector, 8> parameters; if (!decodeMangledFunctionInputType(Node->getChild(firstChildIdx), parameters, hasParamFlags)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node->getChild(firstChildIdx), + "failed to decode function type"); flags = flags.withNumParameters(parameters.size()) .withParameterFlags(hasParamFlags) @@ -642,8 +683,9 @@ class TypeDecoder { NodeKind::EscapingLinearFunctionType); auto result = decodeMangledType(Node->getChild(firstChildIdx+1)); - if (!result) return BuiltType(); - return Builder.createFunctionType(parameters, result, flags); + if (result.isError()) + return result; + return Builder.createFunctionType(parameters, result.getType(), flags); } case NodeKind::ImplFunctionType: { auto calleeConvention = ImplParameterConvention::Direct_Unowned; @@ -657,7 +699,7 @@ class TypeDecoder { if (child->getKind() == NodeKind::ImplConvention) { if (!child->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); if (child->getText() == "@convention(thin)") { flags = @@ -667,7 +709,7 @@ class TypeDecoder { } } else if (child->getKind() == NodeKind::ImplFunctionAttribute) { if (!child->hasText()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "expected text"); StringRef text = child->getText(); if (text == "@convention(c)") { @@ -687,15 +729,18 @@ class TypeDecoder { flags = flags.withEscaping(); } else if (child->getKind() == NodeKind::ImplParameter) { if (decodeImplFunctionParam(child, parameters)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function parameter"); } else if (child->getKind() == NodeKind::ImplResult) { if (decodeImplFunctionParam(child, results)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function parameter"); } else if (child->getKind() == NodeKind::ImplErrorResult) { if (decodeImplFunctionPart(child, errorResults)) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, + "failed to decode function part"); } else { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(child, "unexpected kind"); } } @@ -707,7 +752,8 @@ class TypeDecoder { errorResult = errorResults.front(); break; default: - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, "got %zu errors", + errorResults.size()); } // TODO: Some cases not handled above, but *probably* they cannot @@ -722,13 +768,13 @@ class TypeDecoder { case NodeKind::ArgumentTuple: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); return decodeMangledType(Node->getChild(0)); case NodeKind::ReturnType: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); return decodeMangledType(Node->getChild(0)); @@ -737,12 +783,13 @@ class TypeDecoder { std::string labels; for (auto &element : *Node) { if (element->getKind() != NodeKind::TupleElement) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind"); // If the tuple element is labeled, add its label to 'labels'. unsigned typeChildIndex = 0; if (element->getChild(typeChildIndex)->getKind() == NodeKind::VariadicMarker) { - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(element->getChild(typeChildIndex), + "no children"); } if (element->getChild(typeChildIndex)->getKind() == NodeKind::TupleElementName) { // Add spaces to terminate all the previous labels if this @@ -760,22 +807,23 @@ class TypeDecoder { } // Decode the element type. - BuiltType elementType = - decodeMangledType(element->getChild(typeChildIndex)); - if (!elementType) - return BuiltType(); + auto elementType = decodeMangledType(element->getChild(typeChildIndex)); + if (elementType.isError()) + return elementType; - elements.push_back(elementType); + elements.push_back(elementType.getType()); } return Builder.createTupleType(elements, std::move(labels)); } case NodeKind::TupleElement: if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); if (Node->getChild(0)->getKind() == NodeKind::TupleElementName) { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } @@ -783,68 +831,75 @@ class TypeDecoder { case NodeKind::DependentGenericType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } case NodeKind::DependentMemberType: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; auto assocTypeChild = Node->getChild(1); auto member = assocTypeChild->getFirstChild()->getText(); if (assocTypeChild->getNumChildren() < 2) - return Builder.createDependentMemberType(member.str(), base); + return Builder.createDependentMemberType(member.str(), base.getType()); auto protocol = decodeMangledProtocolType(assocTypeChild->getChild(1)); if (!protocol) return BuiltType(); - return Builder.createDependentMemberType(member.str(), base, protocol); + return Builder.createDependentMemberType(member.str(), base.getType(), + protocol); } case NodeKind::DependentAssociatedTypeRef: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); return decodeMangledType(Node->getChild(1)); } case NodeKind::Unowned: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createUnownedStorageType(base); + if (base.isError()) + return base; + return Builder.createUnownedStorageType(base.getType()); } case NodeKind::Unmanaged: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createUnmanagedStorageType(base); + if (base.isError()) + return base; + return Builder.createUnmanagedStorageType(base.getType()); } case NodeKind::Weak: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createWeakStorageType(base); + if (base.isError()) + return base; + return Builder.createWeakStorageType(base.getType()); } case NodeKind::SILBoxType: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); - return Builder.createSILBoxType(base); + if (base.isError()) + return base; + return Builder.createSILBoxType(base.getType()); } case NodeKind::SILBoxTypeWithLayout: { // TODO: Implement SILBoxTypeRefs with layout. As a stopgap, specify the @@ -853,57 +908,62 @@ class TypeDecoder { } case NodeKind::SugaredOptional: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createOptionalType(base); + return Builder.createOptionalType(base.getType()); } case NodeKind::SugaredArray: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createArrayType(base); + return Builder.createArrayType(base.getType()); } case NodeKind::SugaredDictionary: { if (Node->getNumChildren() < 2) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (2)", + Node->getNumChildren()); auto key = decodeMangledType(Node->getChild(0)); - if (!key) - return BuiltType(); + if (key.isError()) + return key; auto value = decodeMangledType(Node->getChild(1)); - if (!key) - return BuiltType(); + if (value.isError()) + return value; - return Builder.createDictionaryType(key, value); + return Builder.createDictionaryType(key.getType(), value.getType()); } case NodeKind::SugaredParen: { if (Node->getNumChildren() < 1) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "no children"); auto base = decodeMangledType(Node->getChild(0)); - if (!base) - return BuiltType(); + if (base.isError()) + return base; - return Builder.createParenType(base); + return Builder.createParenType(base.getType()); } case NodeKind::OpaqueType: { if (Node->getNumChildren() < 3) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%u) than required (3)", + Node->getNumChildren()); auto descriptor = Node->getChild(0); auto ordinalNode = Node->getChild(1); if (ordinalNode->getKind() != NodeKind::Index || !ordinalNode->hasIndex()) - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(ordinalNode, + "unexpected kind or no index"); auto ordinal = ordinalNode->getIndex(); std::vector genericArgsBuf; @@ -916,9 +976,9 @@ class TypeDecoder { break; for (auto argNode : *genericsNode) { auto arg = decodeMangledType(argNode); - if (!arg) - return BuiltType(); - genericArgsBuf.push_back(arg); + if (arg.isError()) + return arg; + genericArgsBuf.push_back(arg.getType()); } } genericArgsLevels.push_back(genericArgsBuf.size()); @@ -934,7 +994,7 @@ class TypeDecoder { // TODO: Handle OpaqueReturnType, when we're in the middle of reconstructing // the defining decl default: - return BuiltType(); + return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind"); } } @@ -954,11 +1014,11 @@ class TypeDecoder { T::getConventionFromString(conventionString); if (!convention) return true; - BuiltType type = decodeMangledType(node->getChild(1)); - if (!type) + auto type = decodeMangledType(node->getChild(1)); + if (type.isError()) return true; - results.emplace_back(type, *convention); + results.emplace_back(type.getType(), *convention); return false; } @@ -979,8 +1039,8 @@ class TypeDecoder { auto convention = T::getConventionFromString(conventionString); if (!convention) return true; - BuiltType type = decodeMangledType(typeNode); - if (!type) + auto result = decodeMangledType(typeNode); + if (result.isError()) return true; auto diffKind = T::DifferentiabilityType::DifferentiableOrNotApplicable; @@ -995,14 +1055,13 @@ class TypeDecoder { diffKind = *optDiffKind; } - results.emplace_back(type, *convention, diffKind); + results.emplace_back(result.getType(), *convention, diffKind); return false; } - bool decodeMangledTypeDecl(Demangle::NodePointer node, - BuiltTypeDecl &typeDecl, - BuiltType &parent, - bool &typeAlias) { + llvm::Optional + decodeMangledTypeDecl(Demangle::NodePointer node, BuiltTypeDecl &typeDecl, + BuiltType &parent, bool &typeAlias) { if (node->getKind() == NodeKind::Type) return decodeMangledTypeDecl(node->getChild(0), typeDecl, parent, typeAlias); @@ -1013,7 +1072,9 @@ class TypeDecoder { declNode = node; } else { if (node->getNumChildren() < 2) - return false; + return MAKE_NODE_TYPE_ERROR( + node, "Number of node children (%u) less than required (2)", + node->getNumChildren()); auto parentContext = node->getChild(0); @@ -1029,11 +1090,14 @@ class TypeDecoder { case Node::Kind::Extension: // Decode the type being extended. if (parentContext->getNumChildren() < 2) - return false; + return MAKE_NODE_TYPE_ERROR(parentContext, + "Number of parentContext children (%u) " + "less than required (2)", + node->getNumChildren()); parentContext = parentContext->getChild(1); LLVM_FALLTHROUGH; default: - parent = decodeMangledType(parentContext); + parent = decodeMangledType(parentContext).getType(); // Remove any generic arguments from the context node, producing a // node that references the nominal type declaration. declNode = Demangle::getUnspecialized(node, Builder.getNodeFactory()); @@ -1041,9 +1105,10 @@ class TypeDecoder { } } typeDecl = Builder.createTypeDecl(declNode, typeAlias); - if (!typeDecl) return false; + if (!typeDecl) + return TypeLookupError("Failed to create type decl"); - return true; + return llvm::None; } BuiltProtocolDecl decodeMangledProtocolType(Demangle::NodePointer node) { @@ -1108,10 +1173,10 @@ class TypeDecoder { } auto paramType = decodeMangledType(node); - if (!paramType) + if (paramType.isError()) return false; - param.setType(paramType); + param.setType(paramType.getType()); return true; }; @@ -1169,14 +1234,12 @@ class TypeDecoder { } }; -template -inline typename BuilderType::BuiltType -decodeMangledType(BuilderType &Builder, - NodePointer Node) { +template +inline TypeLookupErrorOr +decodeMangledType(BuilderType &Builder, NodePointer Node) { return TypeDecoder(Builder).decodeMangledType(Node); } - SWIFT_END_INLINE_NAMESPACE } // end namespace Demangle } // end namespace swift diff --git a/include/swift/Demangling/TypeLookupError.h b/include/swift/Demangling/TypeLookupError.h new file mode 100644 index 0000000000000..c67fc35598be8 --- /dev/null +++ b/include/swift/Demangling/TypeLookupError.h @@ -0,0 +1,198 @@ +//===--- TypeLookupError.h - Type lookup error value. -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 +// +//===----------------------------------------------------------------------===// +// +// Provides the TypeLookupError class, which represents errors when demangling +// or looking up types. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_DEMANGLING_TypeLookupError_H +#define SWIFT_DEMANGLING_TypeLookupError_H + +#include "swift/Basic/TaggedUnion.h" +#include "swift/Runtime/Portability.h" + +namespace swift { + +/// An error that occurred while looking up a type at runtime from a mangled +/// name. +/// /// +/// This ultimately just provides a string, but is built to take up minimal +/// space when passed around, and perform as much work lazily as possible. We +/// don't want to spend a lot of time building strings when the caller is going +/// to handle the error gracefully and try a fallback. We only want to waste +/// time/space on that when the error message is actually relevant, so build it +/// as late as possible. +/// /// +/// To be as compact as possible, this type holds a context pointer and a +/// callback function. The callback function uses the context pointer to return +/// an error string when requested. The callback function also does quadruple +/// duty to copy/destroy the context as needed, and free the returned error +/// string if needed. Commands are passed to the callback to request the +/// different operations, which means we only have to store one function pointer +/// instead of four. +class TypeLookupError { +public: + /// The commands that can be passed to the callback function. + enum class Command { + /// Return the error string to the caller, as a char *. + CopyErrorString, + + /// Destroy the error string returned from CopyErrorString, if necessary. + /// The return value is ignored. + DestroyErrorString, + + /// Return a copy of the context pointer (used for copying TypeLookupError + /// objects.) + CopyContext, + + /// Destroy the context pointer. The return value is ignored. + DestroyContext, + }; + + /// The callback used to respond to the commands. The parameters are: + /// - `context`: the context that the value was initialized with, or the + /// context returned from a CopyContext call + /// - `command`: the command to respond to + /// - `param`: when `command` is `DestroyErrorString`, the string pointer to + /// destroy, otherwise NULL + using Callback = void *(*)(void *context, Command command, void *param); + +private: + void *Context; + Callback Fn; + + /// A no-op callback used to avoid a bunch of `if (Fn)` checks. + static void *nop(void *context, Command command, void *param) { + return nullptr; + } + + /// Helper functions for getting a C string from a lambda. These allow us to + /// wrap lambdas returning `char *` or `std::string` and standardize them on + /// `char *`. + static char *getCString(char *str) { return str; } + + static char *getCString(const std::string &str) { + return strdup(str.c_str()); + } + +public: + TypeLookupError(const TypeLookupError &other) { + Fn = other.Fn; + Context = other.Fn(other.Context, Command::CopyContext, nullptr); + } + + TypeLookupError(TypeLookupError &&other) { + Fn = other.Fn; + Context = other.Context; + + other.Fn = nop; + other.Context = nullptr; + } + + ~TypeLookupError() { Fn(Context, Command::DestroyContext, nullptr); } + + TypeLookupError(void *context, Callback fn) : Context(context), Fn(fn ? fn : nop) {} + + TypeLookupError &operator=(const TypeLookupError &other) { + if (this == &other) + return *this; + + Fn(Context, Command::DestroyContext, nullptr); + Fn = other.Fn; + Context = Fn(Context, Command::CopyContext, nullptr); + + return *this; + } + + /// Construct a TypeLookupError that just returns a constant C string. + TypeLookupError(const char *str) + : TypeLookupError([=] { return const_cast(str); }) {} + + /// Construct a TypeLookupError that creates a string using asprintf. The passed-in + /// format string and arguments are passed directly to swift_asprintf when + /// the string is requested. The arguments are captured and the string is only + /// formatted when needed. + template + TypeLookupError(const char *fmt, Args... args) + : TypeLookupError([=] { + char *str; + swift_asprintf(&str, fmt, args...); + return str; + }) {} + + /// Construct a TypeLookupError that wraps a function returning a string. The + /// passed-in function can return either a `std::string` or `char *`. If it + /// returns `char *` then the string will be destroyed with `free()`. + template TypeLookupError(const F &fn) { + Context = new F(fn); + Fn = [](void *context, Command command, void *param) -> void * { + auto castContext = reinterpret_cast(context); + switch (command) { + case Command::CopyErrorString: { + return TypeLookupError::getCString((*castContext)()); + } + case Command::DestroyErrorString: + free(param); + return nullptr; + case Command::CopyContext: + return new F(*castContext); + case Command::DestroyContext: + delete castContext; + return nullptr; + } + }; + } + + /// Get the error string from the error value. The value must be passed to + /// `freeErrorString` when done. (Unless you're just calling a `fatalError` + /// in which case there's no point.) + char *copyErrorString() { + return reinterpret_cast( + Fn(Context, Command::CopyErrorString, nullptr)); + } + + /// Free an error string previously obtained from `copyErrorString`. + void freeErrorString(char *str) { + Fn(Context, Command::DestroyErrorString, str); + } +}; + +/// A value that's either a `TypeLookupError` or some parameterized type value `T`. A +/// convenience wrapper around `TaggedUnion`. +template class TypeLookupErrorOr { + TaggedUnion Value; + +public: + TypeLookupErrorOr(const T &t) : Value(t) { + if (!t) + Value = TypeLookupError("unknown error"); + } + + TypeLookupErrorOr(const TypeLookupError &te) : Value(te) {} + + T getType() { + if (auto *ptr = Value.template dyn_cast()) + return *ptr; + return T(); + } + + TypeLookupError *getError() { + return Value.template dyn_cast(); + } + + bool isError() { return getError() != nullptr; } +}; + +} // namespace swift + +#endif // SWIFT_DEMANGLING_TypeLookupError_H diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index f5f75f13e7694..39ab041dbcc1b 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -621,7 +621,7 @@ class CompilerInstance { /// /// This is similar to a parse-only invocation, but module imports will also /// be processed. - void performParseAndResolveImportsOnly(); + bool performParseAndResolveImportsOnly(); /// Performs mandatory, diagnostic, and optimization passes over the SIL. /// \param silModule The SIL module that was generated during SILGen. diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 724cf7e6efa31..c961794d35582 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -294,9 +294,16 @@ class FrontendOptions { /// '.../lib/swift', otherwise '.../lib/swift_static'. bool UseSharedResourceFolder = true; - /// \return true if action only parses without doing other compilation steps. + /// \return true if the given action only parses without doing other compilation steps. static bool shouldActionOnlyParse(ActionType); + /// \return true if the given action requires the standard library to be + /// loaded before it is run. + static bool doesActionRequireSwiftStandardLibrary(ActionType); + + /// \return true if the given action requires input files to be provided. + static bool doesActionRequireInputs(ActionType action); + /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { diff --git a/include/swift/IDE/CodeCompletionResultPrinter.h b/include/swift/IDE/CodeCompletionResultPrinter.h index 717d6282a4309..86e1233246dc9 100644 --- a/include/swift/IDE/CodeCompletionResultPrinter.h +++ b/include/swift/IDE/CodeCompletionResultPrinter.h @@ -34,6 +34,12 @@ void printCodeCompletionResultTypeName( void printCodeCompletionResultTypeNameAnnotated( const CodeCompletionResult &Result, llvm::raw_ostream &OS); +void printCodeCompletionResultSourceText( + const CodeCompletionResult &Result, llvm::raw_ostream &OS); + +void printCodeCompletionResultFilterName( + const CodeCompletionResult &Result, llvm::raw_ostream &OS); + } // namespace ide } // namespace swift diff --git a/tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h b/include/swift/IDE/FuzzyStringMatcher.h similarity index 83% rename from tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h rename to include/swift/IDE/FuzzyStringMatcher.h index cb53e962de0d7..af80647e37c3e 100644 --- a/tools/SourceKit/include/SourceKit/Support/FuzzyStringMatcher.h +++ b/include/swift/IDE/FuzzyStringMatcher.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 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 @@ -10,14 +10,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H -#define LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H +#ifndef SWIFT_IDE_FUZZYSTRINGMATCHER_H +#define SWIFT_IDE_FUZZYSTRINGMATCHER_H -#include "SourceKit/Core/LLVM.h" +#include "swift/Basic/LLVM.h" #include "llvm/ADT/BitVector.h" #include -namespace SourceKit { +namespace swift { +namespace ide { /// FuzzyStringMatcher compares candidate strings against a pattern /// string using a fuzzy matching algorithm and provides a numerical @@ -49,6 +50,7 @@ class FuzzyStringMatcher { double scoreCandidate(StringRef candidate) const; }; -} // end namespace SourceKit +} // namespace ide +} // namespace swift -#endif // LLVM_SOURCEKIT_LIB_SUPPORT_FUZZYSTRINGMATCHER_H +#endif // SWIFT_IDE_FUZZYSTRINGMATCHER_H diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index f847b188f1b42..aec73ac37fd9c 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -22,6 +22,9 @@ #include "swift/IDE/SourceEntityWalker.h" #include "swift/Parse/Token.h" #include "llvm/ADT/StringRef.h" +// SWIFT_ENABLE_TENSORFLOW +#include "clang/Basic/InMemoryOutputFileSystem.h" +// SWIFT_ENABLE_TENSORFLOW END #include #include #include @@ -81,6 +84,17 @@ SourceCompleteResult isSourceInputComplete(std::unique_ptr MemBuf, SourceFileKind SFKind); SourceCompleteResult isSourceInputComplete(StringRef Text, SourceFileKind SFKind); +bool initCompilerInvocation( + CompilerInvocation &Invocation, ArrayRef OrigArgs, + DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + // SWIFT_ENABLE_TENSORFLOW + llvm::IntrusiveRefCntPtr InMemoryOutputFileSystem, + // SWIFT_ENABLE_TENSORFLOW END + const std::string &runtimeResourcePath, + const std::string &diagnosticDocumentationPath, + bool shouldOptimizeForIDE, time_t sessionTimestamp, std::string &Error); + bool initInvocationByClangArguments(ArrayRef ArgList, CompilerInvocation &Invok, std::string &Error); diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index a52fb0b7b09de..c985635297e45 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1133,8 +1133,7 @@ class Parser { ParseDeclOptions Flags, DeclAttributes &Attributes, bool HasFuncKeyword = true); - ParserResult - parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); + BraceStmt *parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); void parseAbstractFunctionBody(AbstractFunctionDecl *AFD); BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); ParserResult parseDeclProtocol(ParseDeclOptions Flags, diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index f375918a5ff5d..3914810cbfd8f 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -618,8 +618,8 @@ class TypeRefBuilder { }), OpaqueUnderlyingTypeReader( [&reader](uint64_t descriptorAddr, unsigned ordinal) -> const TypeRef* { - return reader.readUnderlyingTypeForOpaqueTypeDescriptor(descriptorAddr, - ordinal); + return reader.readUnderlyingTypeForOpaqueTypeDescriptor( + descriptorAddr, ordinal).getType(); }) {} diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 4450066283afc..0090ae0746ed6 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -463,7 +463,8 @@ class MetadataReader { } /// Given a demangle tree, attempt to turn it into a type. - BuiltType decodeMangledType(NodePointer Node) { + TypeLookupErrorOr + decodeMangledType(NodePointer Node) { return swift::Demangle::decodeMangledType(Builder, Node); } @@ -925,8 +926,8 @@ class MetadataReader { swift_runtime_unreachable("Unhandled MetadataKind in switch"); } - BuiltType readTypeFromMangledName(const char *MangledTypeName, - size_t Length) { + TypeLookupErrorOr + readTypeFromMangledName(const char *MangledTypeName, size_t Length) { Demangle::Demangler Dem; Demangle::NodePointer Demangled = Dem.demangleSymbol(StringRef(MangledTypeName, Length)); @@ -1183,14 +1184,14 @@ class MetadataReader { MangledNameKind::Type, Dem); } - BuiltType + TypeLookupErrorOr readUnderlyingTypeForOpaqueTypeDescriptor(StoredPointer contextAddr, unsigned ordinal) { Demangle::Demangler Dem; auto node = readUnderlyingTypeManglingForOpaqueTypeDescriptor(contextAddr, ordinal, Dem); if (!node) - return BuiltType(); + return TypeLookupError("Failed to read type mangling for descriptor."); return decodeMangledType(node); } diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 10269653284df..e634fbc25660d 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -517,7 +517,7 @@ template struct ConcurrentReadableArray { auto *newStorage = Storage::allocate(newCapacity); if (storage) { std::copy(storage->data(), storage->data() + count, newStorage->data()); - newStorage->Count.store(count, std::memory_order_relaxed); + newStorage->Count.store(count, std::memory_order_release); FreeList.push_back(storage); } @@ -635,30 +635,49 @@ template struct ConcurrentReadableHashMap { std::atomic &at(size_t i) { return (&Mask)[i]; } }; + /// A simple linked list representing pointers that need to be freed. + struct FreeListNode { + FreeListNode *Next; + void *Ptr; + + static void add(FreeListNode **head, void *ptr) { + auto *newNode = new FreeListNode{*head, ptr}; + *head = newNode; + } + + static void freeAll(FreeListNode **head) { + auto *node = *head; + while (node) { + auto *next = node->Next; + free(node->Ptr); + delete node; + node = next; + } + *head = nullptr; + } + }; + /// The number of readers currently active, equal to the number of snapshot /// objects currently alive. - std::atomic ReaderCount; + std::atomic ReaderCount{0}; /// The number of elements in the elements array. - std::atomic ElementCount; + std::atomic ElementCount{0}; /// The array of elements. - std::atomic Elements; + std::atomic Elements{nullptr}; /// The array of indices. - std::atomic Indices; + std::atomic Indices{nullptr}; /// The writer lock, which must be taken before any mutation of the table. Mutex WriterLock; /// The maximum number of elements that the current elements array can hold. - size_t ElementCapacity; - - /// The list of element arrays to be freed once no readers are active. - std::vector ElementFreeList; + uint32_t ElementCapacity{0}; - /// The list of index arrays to be freed once no readers are active. - std::vector IndicesFreeList; + /// The list of pointers to be freed once no readers are active. + FreeListNode *FreeList{nullptr}; void incrementReaders() { ReaderCount.fetch_add(1, std::memory_order_acquire); @@ -668,24 +687,11 @@ template struct ConcurrentReadableHashMap { ReaderCount.fetch_sub(1, std::memory_order_release); } - /// Free all the arrays in the free lists. - void deallocateFreeList() { - for (auto *storage : ElementFreeList) - free(storage); - ElementFreeList.clear(); - ElementFreeList.shrink_to_fit(); - - for (auto *indices : IndicesFreeList) - free(indices); - IndicesFreeList.clear(); - IndicesFreeList.shrink_to_fit(); - } - /// Free all the arrays in the free lists if there are no active readers. If /// there are active readers, do nothing. void deallocateFreeListIfSafe() { if (ReaderCount.load(std::memory_order_acquire) == 0) - deallocateFreeList(); + FreeListNode::freeAll(&FreeList); } /// Grow the elements array, adding the old array to the free list and @@ -702,7 +708,7 @@ template struct ConcurrentReadableHashMap { ElemTy *newElements = static_cast(malloc(newSize)); if (elements) { memcpy(newElements, elements, elementCount * sizeof(ElemTy)); - ElementFreeList.push_back(elements); + FreeListNode::add(&FreeList, elements); } ElementCapacity = newCapacity; @@ -739,7 +745,7 @@ template struct ConcurrentReadableHashMap { Indices.store(newIndices, std::memory_order_release); - IndicesFreeList.push_back(indices); + FreeListNode::add(&FreeList, indices); return newIndices; } @@ -792,7 +798,7 @@ template struct ConcurrentReadableHashMap { ~ConcurrentReadableHashMap() { assert(ReaderCount.load(std::memory_order_acquire) == 0 && "deallocating ConcurrentReadableHashMap with outstanding snapshots"); - deallocateFreeList(); + FreeListNode::freeAll(&FreeList); } /// Readers take a snapshot of the hash map, then work with the snapshot. @@ -943,8 +949,8 @@ template struct ConcurrentReadableHashMap { Elements.store(nullptr, std::memory_order_relaxed); ElementCapacity = 0; - IndicesFreeList.push_back(indices); - ElementFreeList.push_back(elements); + FreeListNode::add(&FreeList, indices); + FreeListNode::add(&FreeList, elements); deallocateFreeListIfSafe(); } diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h index 86e19642e51a7..f14e8d16f1554 100644 --- a/include/swift/Runtime/Debug.h +++ b/include/swift/Runtime/Debug.h @@ -21,7 +21,6 @@ #include "swift/Runtime/Unreachable.h" #include #include -#include #include #include @@ -248,39 +247,6 @@ std::atomic _swift_debug_metadataAllocationBacktraceList; SWIFT_RUNTIME_STDLIB_SPI const void * const _swift_debug_protocolConformanceStatePointer; -SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE -inline static int swift_asprintf(char **strp, const char *fmt, ...) { - va_list args; - va_start(args, fmt); -#if defined(_WIN32) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuninitialized" - int len = _vscprintf(fmt, args); -#pragma GCC diagnostic pop - if (len < 0) { - va_end(args); - return -1; - } - char *buffer = static_cast(malloc(len + 1)); - if (!buffer) { - va_end(args); - return -1; - } - int result = vsprintf(buffer, fmt, args); - if (result < 0) { - va_end(args); - free(buffer); - return -1; - } - *strp = buffer; -#else - int result = vasprintf(strp, fmt, args); -#endif - va_end(args); - return result; -} - - // namespace swift } diff --git a/include/swift/Runtime/Portability.h b/include/swift/Runtime/Portability.h index 9e4fc418e162f..cd19b2c4193ba 100644 --- a/include/swift/Runtime/Portability.h +++ b/include/swift/Runtime/Portability.h @@ -16,8 +16,47 @@ #ifndef SWIFT_RUNTIME_PORTABILITY_H #define SWIFT_RUNTIME_PORTABILITY_H + +#include #include +#include +#include size_t _swift_strlcpy(char *dst, const char *src, size_t maxlen); +// Skip the attribute when included by the compiler. +#ifdef SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE +#endif +inline static int swift_asprintf(char **strp, const char *fmt, ...) { + va_list args; + va_start(args, fmt); +#if defined(_WIN32) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + int len = _vscprintf(fmt, args); +#pragma GCC diagnostic pop + if (len < 0) { + va_end(args); + return -1; + } + char *buffer = static_cast(malloc(len + 1)); + if (!buffer) { + va_end(args); + return -1; + } + int result = vsprintf(buffer, fmt, args); + if (result < 0) { + va_end(args); + free(buffer); + return -1; + } + *strp = buffer; +#else + int result = vasprintf(strp, fmt, args); +#endif + va_end(args); + return result; +} + #endif diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 5297539e43494..ec81558ab3179 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -121,6 +121,7 @@ class SILFunction enum class Purpose : uint8_t { None, GlobalInit, + GlobalInitOnceFunction, LazyPropertyGetter }; @@ -832,6 +833,10 @@ class SILFunction /// function itself does not need this attribute. It is private and only /// called within the addressor. bool isGlobalInit() const { return specialPurpose == Purpose::GlobalInit; } + + bool isGlobalInitOnceFunction() const { + return specialPurpose == Purpose::GlobalInitOnceFunction; + } bool isLazyPropertyGetter() const { return specialPurpose == Purpose::LazyPropertyGetter; diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index aba919ee0090c..344087f0a1aaf 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -992,7 +992,6 @@ class TypeConverter { /// Given a function type, yield its bridged formal type. CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern, CanAnyFunctionType fnType, - AnyFunctionType::ExtInfo extInfo, Bridgeability bridging); /// Given a referenced value and the substituted formal type of a diff --git a/include/swift/Serialization/ModuleDependencyScanner.h b/include/swift/Serialization/ModuleDependencyScanner.h new file mode 100644 index 0000000000000..07006770d8f49 --- /dev/null +++ b/include/swift/Serialization/ModuleDependencyScanner.h @@ -0,0 +1,110 @@ +//===--- ModuleDependencyScanner.h - Import Swift modules --------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 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/AST/ASTContext.h" +#include "swift/Frontend/ModuleInterfaceLoader.h" +#include "swift/Serialization/SerializedModuleLoader.h" + +namespace swift { + /// A module "loader" that looks for .swiftinterface and .swiftmodule files + /// for the purpose of determining dependencies, but does not attempt to + /// load the module files. + class ModuleDependencyScanner : public SerializedModuleLoaderBase { + /// The module we're scanning dependencies of. + Identifier moduleName; + + /// Scan the given interface file to determine dependencies. + llvm::ErrorOr scanInterfaceFile( + Twine moduleInterfacePath, bool isFramework); + + InterfaceSubContextDelegate &astDelegate; + public: + Optional dependencies; + + /// Describes the kind of dependencies this scanner is able to identify + ModuleDependenciesKind dependencyKind; + + ModuleDependencyScanner( + ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, + InterfaceSubContextDelegate &astDelegate, + ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift) + : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, + /*IgnoreSwiftSourceInfoFile=*/true), + moduleName(moduleName), astDelegate(astDelegate), + dependencyKind(dependencyKind) {} + + std::error_code findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; + + virtual void collectVisibleTopLevelModuleNames( + SmallVectorImpl &names) const override { + llvm_unreachable("Not used"); + } + }; + + /// A ModuleLoader that loads placeholder dependency module stubs specified in + /// -placeholder-dependency-module-map-file + /// This loader is used only in dependency scanning to inform the scanner that a + /// set of modules constitute placeholder dependencies that are not visible to the + /// scanner but will nevertheless be provided by the scanner's clients. + /// This "loader" will not attempt to load any module files. + class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { + /// Scan the given placeholder module map + void parsePlaceholderModuleMap(StringRef fileName) { + ExplicitModuleMapParser parser(Allocator); + auto result = + parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap); + if (result == std::errc::invalid_argument) { + Ctx.Diags.diagnose(SourceLoc(), + diag::placeholder_dependency_module_map_corrupted, + fileName); + } + else if (result == std::errc::no_such_file_or_directory) { + Ctx.Diags.diagnose(SourceLoc(), + diag::placeholder_dependency_module_map_missing, + fileName); + } + } + + llvm::StringMap PlaceholderDependencyModuleMap; + llvm::BumpPtrAllocator Allocator; + + public: + PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, + Identifier moduleName, + StringRef PlaceholderDependencyModuleMap, + InterfaceSubContextDelegate &astDelegate) + : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, + ModuleDependenciesKind::SwiftPlaceholder) { + + // FIXME: Find a better place for this map to live, to avoid + // doing the parsing on every module. + if (!PlaceholderDependencyModuleMap.empty()) { + parsePlaceholderModuleMap(PlaceholderDependencyModuleMap); + } + } + + std::error_code findModuleFilesInDirectory( + AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) override; + }; +} diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0dbfeb803d83e..3571a475af1c8 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -18,6 +18,7 @@ #include "ClangTypeConverter.h" #include "ForeignRepresentationInfo.h" #include "SubstitutionMapStorage.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DiagnosticEngine.h" @@ -296,6 +297,10 @@ struct ASTContext::Implementation { llvm::DenseMap ForeignErrorConventions; + /// Map from declarations to foreign async conventions. + llvm::DenseMap ForeignAsyncConventions; + /// Cache of previously looked-up precedence queries. AssociativityCacheType AssociativityCache; @@ -1634,8 +1639,9 @@ bool ASTContext::hadError() const { /// Retrieve the arena from which we should allocate storage for a type. static AllocationArena getArena(RecursiveTypeProperties properties) { bool hasTypeVariable = properties.hasTypeVariable(); - return hasTypeVariable? AllocationArena::ConstraintSolver - : AllocationArena::Permanent; + bool hasHole = properties.hasTypeHole(); + return hasTypeVariable || hasHole ? AllocationArena::ConstraintSolver + : AllocationArena::Permanent; } void ASTContext::addSearchPath(StringRef searchPath, bool isFramework, @@ -2406,6 +2412,24 @@ AbstractFunctionDecl::getForeignErrorConvention() const { return it->second; } +void AbstractFunctionDecl::setForeignAsyncConvention( + const ForeignAsyncConvention &conv) { + assert(hasAsync() && "setting error convention on non-throwing decl"); + auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions; + assert(!conventionsMap.count(this) && "error convention already set"); + conventionsMap.insert({this, conv}); +} + +Optional +AbstractFunctionDecl::getForeignAsyncConvention() const { + if (!hasAsync()) + return None; + auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions; + auto it = conventionsMap.find(this); + if (it == conventionsMap.end()) return None; + return it->second; +} + Optional swift::getKnownFoundationEntity(StringRef name){ return llvm::StringSwitch>(name) #define FOUNDATION_ENTITY(Name) .Case(#Name, KnownFoundationEntity::Name) @@ -2526,6 +2550,17 @@ Type ErrorType::get(Type originalType) { return entry = new (mem) ErrorType(ctx, originalType, properties); } +Type HoleType::get(ASTContext &ctx, OriginatorType originator) { + assert(originator); + auto properties = reinterpret_cast(originator.getOpaqueValue()) + ->getRecursiveProperties(); + properties |= RecursiveTypeProperties::HasTypeHole; + + auto arena = getArena(properties); + return new (ctx, arena) + HoleType(ctx, originator, RecursiveTypeProperties::HasTypeHole); +} + BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth, const ASTContext &C) { assert(!BitWidth.isArbitraryWidth()); @@ -2967,6 +3002,7 @@ ReferenceStorageType *ReferenceStorageType::get(Type T, ReferenceOwnership ownership, const ASTContext &C) { assert(!T->hasTypeVariable()); // not meaningful in type-checker + assert(!T->hasHole()); switch (optionalityOf(ownership)) { case ReferenceOwnershipOptionality::Disallowed: assert(!T->getOptionalObjectType() && "optional type is disallowed"); @@ -3125,7 +3161,7 @@ isFunctionTypeCanonical(ArrayRef params, static RecursiveTypeProperties getGenericFunctionRecursiveProperties(ArrayRef params, Type result) { - static_assert(RecursiveTypeProperties::BitWidth == 11, + static_assert(RecursiveTypeProperties::BitWidth == 12, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; @@ -3299,16 +3335,16 @@ FunctionType *FunctionType::get(ArrayRef params, return funcTy; } - Optional clangTypeInfo = info.getClangTypeInfo(); + auto clangTypeInfo = info.getClangTypeInfo(); size_t allocSize = totalSizeToAlloc( - params.size(), clangTypeInfo.hasValue() ? 1 : 0); + params.size(), clangTypeInfo.empty() ? 0 : 1); void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena); bool isCanonical = isFunctionTypeCanonical(params, result); - if (clangTypeInfo.hasValue()) { + if (!clangTypeInfo.empty()) { if (ctx.LangOpts.UseClangFunctionTypes) - isCanonical &= clangTypeInfo->type->isCanonicalUnqualified(); + isCanonical &= clangTypeInfo.getType()->isCanonicalUnqualified(); else isCanonical = false; } @@ -3330,8 +3366,8 @@ FunctionType::FunctionType(ArrayRef params, std::uninitialized_copy(params.begin(), params.end(), getTrailingObjects()); auto clangTypeInfo = info.getClangTypeInfo(); - if (clangTypeInfo.hasValue()) - *getTrailingObjects() = clangTypeInfo.getValue(); + if (!clangTypeInfo.empty()) + *getTrailingObjects() = clangTypeInfo; } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, @@ -3353,6 +3389,7 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig, ExtInfo info) { assert(sig && "no generic signature for generic function type?!"); assert(!result->hasTypeVariable()); + assert(!result->hasHole()); llvm::FoldingSetNodeID id; GenericFunctionType::Profile(id, sig, params, result, info); @@ -3428,7 +3465,6 @@ void SILFunctionType::Profile( llvm::FoldingSetNodeID &id, GenericSignature genericParams, ExtInfo info, - bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3442,7 +3478,6 @@ void SILFunctionType::Profile( auto infoKey = info.getFuncAttrKey(); id.AddInteger(infoKey.first); id.AddPointer(infoKey.second); - id.AddBoolean(isAsync); id.AddInteger(unsigned(coroutineKind)); id.AddInteger(unsigned(calleeConvention)); id.AddInteger(params.size()); @@ -3468,7 +3503,6 @@ void SILFunctionType::Profile( SILFunctionType::SILFunctionType( GenericSignature genericSig, ExtInfo ext, - bool isAsync, SILCoroutineKind coroutineKind, ParameterConvention calleeConvention, ArrayRef params, @@ -3494,7 +3528,6 @@ SILFunctionType::SILFunctionType( "Bits were dropped!"); static_assert(SILExtInfoBuilder::NumMaskBits == NumSILExtInfoBits, "ExtInfo and SILFunctionTypeBitfields must agree on bit size"); - Bits.SILFunctionType.IsAsync = isAsync; Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind); NumParameters = params.size(); if (coroutineKind == SILCoroutineKind::None) { @@ -3638,7 +3671,7 @@ CanSILBlockStorageType SILBlockStorageType::get(CanType captureType) { CanSILFunctionType SILFunctionType::get( GenericSignature genericSig, - ExtInfo ext, bool isAsync, SILCoroutineKind coroutineKind, + ExtInfo ext, SILCoroutineKind coroutineKind, ParameterConvention callee, ArrayRef params, ArrayRef yields, @@ -3656,8 +3689,8 @@ CanSILFunctionType SILFunctionType::get( invocationSubs = invocationSubs.getCanonical(); llvm::FoldingSetNodeID id; - SILFunctionType::Profile(id, genericSig, ext, isAsync, coroutineKind, callee, - params, yields, normalResults, errorResult, + SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee, params, + yields, normalResults, errorResult, witnessMethodConformance, patternSubs, invocationSubs); @@ -3681,7 +3714,7 @@ CanSILFunctionType SILFunctionType::get( void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; - static_assert(RecursiveTypeProperties::BitWidth == 11, + static_assert(RecursiveTypeProperties::BitWidth == 12, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getInterfaceType()->getRecursiveProperties(); @@ -3705,7 +3738,7 @@ CanSILFunctionType SILFunctionType::get( } auto fnType = - new (mem) SILFunctionType(genericSig, ext, isAsync, coroutineKind, callee, + new (mem) SILFunctionType(genericSig, ext, coroutineKind, callee, params, yields, normalResults, errorResult, patternSubs, invocationSubs, ctx, properties, witnessMethodConformance); @@ -4629,16 +4662,29 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, return Type(); } -const clang::Type * -ASTContext::getClangFunctionType(ArrayRef params, - Type resultTy, - FunctionTypeRepresentation trueRep) { +ClangTypeConverter &ASTContext::getClangTypeConverter() { auto &impl = getImpl(); if (!impl.Converter) { auto *cml = getClangModuleLoader(); impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target); } - return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep); + return impl.Converter.getValue(); +} + +const clang::Type * +ASTContext::getClangFunctionType(ArrayRef params, + Type resultTy, + FunctionTypeRepresentation trueRep) { + return getClangTypeConverter().getFunctionType(params, resultTy, trueRep); +} + +const clang::Type * +ASTContext::getCanonicalClangFunctionType( + ArrayRef params, + Optional result, + SILFunctionType::Representation trueRep) { + auto *ty = getClangTypeConverter().getFunctionType(params, result, trueRep); + return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr; } const Decl * diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 6e44fd70da0ef..bf72c01eae702 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -44,7 +44,7 @@ Type swift::Demangle::getTypeForMangling(ASTContext &ctx, return Type(); ASTBuilder builder(ctx); - return swift::Demangle::decodeMangledType(builder, node); + return swift::Demangle::decodeMangledType(builder, node).getType(); } TypeDecl *swift::Demangle::getTypeDeclForMangling(ASTContext &ctx, @@ -530,7 +530,7 @@ Type ASTBuilder::createImplFunctionType( // [TODO: Store-SIL-Clang-type] auto einfo = SILExtInfoBuilder(representation, flags.isPseudogeneric(), - !flags.isEscaping(), diffKind, + !flags.isEscaping(), flags.isAsync(), diffKind, /*clangFunctionType*/ nullptr) .build(); @@ -558,8 +558,7 @@ Type ASTBuilder::createImplFunctionType( auto conv = getResultConvention(errorResult->getConvention()); funcErrorResult.emplace(type, conv); } - return SILFunctionType::get(genericSig, einfo, - /*isAsync*/ false, funcCoroutineKind, + return SILFunctionType::get(genericSig, einfo, funcCoroutineKind, funcCalleeConvention, funcParams, funcYields, funcResults, funcErrorResult, SubstitutionMap(), SubstitutionMap(), Ctx); @@ -847,8 +846,8 @@ CanGenericSignature ASTBuilder::demangleGenericSignature( if (child->getNumChildren() != 2) return CanGenericSignature(); - auto subjectType = swift::Demangle::decodeMangledType( - *this, child->getChild(0)); + auto subjectType = + swift::Demangle::decodeMangledType(*this, child->getChild(0)).getType(); if (!subjectType) return CanGenericSignature(); @@ -857,8 +856,9 @@ CanGenericSignature ASTBuilder::demangleGenericSignature( Demangle::Node::Kind::DependentGenericConformanceRequirement || child->getKind() == Demangle::Node::Kind::DependentGenericSameTypeRequirement) { - constraintType = swift::Demangle::decodeMangledType( - *this, child->getChild(1)); + constraintType = + swift::Demangle::decodeMangledType(*this, child->getChild(1)) + .getType(); if (!constraintType) return CanGenericSignature(); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index d8352e9c62e2c..16fd1f6141eba 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2108,11 +2108,8 @@ class PrintExpr : public ExprVisitor { void visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { printCommon(E, "unresolved_member_expr") << " name='" << E->getName() << "'"; - printArgumentLabels(E->getArgumentLabels()); - if (E->getArgument()) { - OS << '\n'; - printRec(E->getArgument()); - } + PrintWithColorRAII(OS, ExprModifierColor) + << " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } void visitDotSelfExpr(DotSelfExpr *E) { @@ -2135,7 +2132,12 @@ class PrintExpr : public ExprVisitor { printRec(E->getSubExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitUnresolvedMemberChainResultExpr(UnresolvedMemberChainResultExpr *E){ + printCommon(E, "unresolved_member_chain_expr"); + OS << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitTupleExpr(TupleExpr *E) { printCommon(E, "tuple_expr"); if (E->hasTrailingClosure()) @@ -3496,6 +3498,18 @@ namespace { TRIVIAL_TYPE_PRINTER(Unresolved, unresolved) + void visitHoleType(HoleType *T, StringRef label) { + printCommon(label, "hole_type"); + auto originatorTy = T->getOriginatorType(); + if (auto *typeVar = originatorTy.dyn_cast()) { + printRec("type_variable", typeVar); + } else { + printRec("dependent_member_type", + originatorTy.get()); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitBuiltinIntegerType(BuiltinIntegerType *T, StringRef label) { printCommon(label, "builtin_integer_type"); if (T->isFixedWidth()) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index be1c4af4e0ea1..8da9843183986 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -336,21 +336,29 @@ std::string ASTMangler::mangleKeyPathHashHelper(ArrayRef indices, return finalize(); } -std::string ASTMangler::mangleGlobalInit(const VarDecl *decl, int counter, +std::string ASTMangler::mangleGlobalInit(const PatternBindingDecl *pd, + unsigned pbdEntry, bool isInitFunc) { - auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); - auto fileUnit = cast(topLevelContext); - Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl); - assert(!discriminator.empty()); - assert(!isNonAscii(discriminator.str()) && - "discriminator contains non-ASCII characters"); - assert(!clang::isDigit(discriminator.str().front()) && - "not a valid identifier"); - - Buffer << "globalinit_"; - appendIdentifier(discriminator.str()); - Buffer << (isInitFunc ? "_func" : "_token"); - Buffer << counter; + beginMangling(); + + Pattern *pattern = pd->getPattern(pbdEntry); + bool first = true; + pattern->forEachVariable([&](VarDecl *D) { + if (first) { + appendContextOf(D); + first = false; + } + appendDeclName(D); + appendListSeparator(); + }); + assert(!first && "no variables in pattern binding?!"); + + if (isInitFunc) { + appendOperator("WZ"); + } else { + appendOperator("Wz"); + } + return finalize(); } @@ -915,6 +923,7 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) { TypeBase *tybase = type.getPointer(); switch (type->getKind()) { case TypeKind::TypeVariable: + case TypeKind::Hole: llvm_unreachable("mangling type variable"); case TypeKind::Module: diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index dcd8e40c34237..6a6307bba08d4 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3629,7 +3629,7 @@ void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) { auto *cml = Ctx.getClangModuleLoader(); SmallString<64> buf; llvm::raw_svector_ostream os(buf); - info.getClangTypeInfo().getValue().printType(cml, os); + info.getClangTypeInfo().printType(cml, os); Printer << ", cType: " << QuotedString(os.str()); } @@ -3829,6 +3829,17 @@ class TypePrinter : public TypeVisitor { Printer << "_"; } + void visitHoleType(HoleType *T) { + if (Options.PrintTypesForDebugging) { + Printer << "<getOriginatorType(); + visit(Type(reinterpret_cast(originatorTy.getOpaqueValue()))); + Printer << ">>"; + } else { + Printer << "<>"; + } + } + #ifdef ASTPRINTER_HANDLE_BUILTINTYPE #error "ASTPRINTER_HANDLE_BUILTINTYPE should not be defined?!" #endif @@ -4070,7 +4081,7 @@ class TypePrinter : public TypeVisitor { case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || !info.getClangTypeInfo().hasValue()) + if (printNameOnly || info.getClangTypeInfo().empty()) break; printCType(Ctx, Printer, info); break; @@ -4136,7 +4147,7 @@ class TypePrinter : public TypeVisitor { case SILFunctionType::Representation::CFunctionPointer: Printer << "c"; // [TODO: Clang-type-plumbing] Remove the second check. - if (printNameOnly || !info.getClangTypeInfo().hasValue()) + if (printNameOnly || info.getClangTypeInfo().empty()) break; printCType(Ctx, Printer, info); break; @@ -4167,6 +4178,9 @@ class TypePrinter : public TypeVisitor { if (info.isNoEscape()) { Printer.printSimpleAttr("@noescape") << " "; } + if (info.isAsync()) { + Printer.printSimpleAttr("@async") << " "; + } } void visitAnyFunctionTypeParams(ArrayRef Params, @@ -4311,7 +4325,6 @@ class TypePrinter : public TypeVisitor { void visitSILFunctionType(SILFunctionType *T) { printSILCoroutineKind(T->getCoroutineKind()); - printSILAsyncAttr(T->isAsync()); printFunctionExtInfo(T->getASTContext(), T->getExtInfo(), T->getWitnessMethodConformanceOrInvalid()); printCalleeConvention(T->getCalleeConvention()); diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 250f2ad6c0678..7896e009534a2 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -519,7 +519,7 @@ bool BraceStmtScope::lookupLocalsOrMembers(ArrayRef, bool PatternEntryInitializerScope::lookupLocalsOrMembers( ArrayRef, DeclConsumer consumer) const { // 'self' is available within the pattern initializer of a 'lazy' variable. - auto *initContext = cast_or_null( + auto *initContext = dyn_cast_or_null( decl->getInitContext(0)); if (initContext) { if (auto *selfParam = initContext->getImplicitSelfDecl()) { @@ -816,7 +816,7 @@ Optional ClosureBodyScope::resolveIsCascadingUseForThisScope( Optional PatternEntryInitializerScope::resolveIsCascadingUseForThisScope( Optional isCascadingUse) const { auto *const initContext = getPatternEntry().getInitContext(); - auto *PBI = cast_or_null(initContext); + auto *PBI = dyn_cast_or_null(initContext); auto *isd = PBI ? PBI->getImplicitSelfDecl() : nullptr; // 'self' is available within the pattern initializer of a 'lazy' variable. diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index c6884f049b44e..ef2ba5afb7cbf 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -504,17 +504,7 @@ class Traversal : public ASTVisitorgetArgument()) { - if (auto arg = doIt(E->getArgument())) { - E->setArgument(arg); - return E; - } - - return nullptr; - } - return E; - } + Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { return E; } Expr *visitOpaqueValueExpr(OpaqueValueExpr *E) { return E; } diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index d4ccea512f069..9fd13f797798d 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -158,6 +158,57 @@ const clang::Type *ClangTypeConverter::getFunctionType( llvm_unreachable("invalid representation"); } +const clang::Type *ClangTypeConverter::getFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation repr) { + + // Using the interface type is sufficient as type parameters get mapped to + // `id`, since ObjC lightweight generics use type erasure. (See also: SE-0057) + auto resultClangTy = result.hasValue() + ? convert(result.getValue().getInterfaceType()) + : ClangASTContext.VoidTy; + + if (resultClangTy.isNull()) + return nullptr; + + SmallVector extParamInfos; + SmallVector paramsClangTy; + bool someParamIsConsumed = false; + for (auto &p : params) { + auto pc = convert(p.getInterfaceType()); + if (pc.isNull()) + return nullptr; + clang::FunctionProtoType::ExtParameterInfo extParamInfo; + if (p.isConsumed()) { + someParamIsConsumed = true; + extParamInfo = extParamInfo.withIsConsumed(true); + } + extParamInfos.push_back(extParamInfo); + paramsClangTy.push_back(pc); + } + + clang::FunctionProtoType::ExtProtoInfo info(clang::CallingConv::CC_C); + if (someParamIsConsumed) + info.ExtParameterInfos = extParamInfos.begin(); + auto fn = ClangASTContext.getFunctionType(resultClangTy, paramsClangTy, info); + if (fn.isNull()) + return nullptr; + + switch (repr) { + case SILFunctionType::Representation::CFunctionPointer: + return ClangASTContext.getPointerType(fn).getTypePtr(); + case SILFunctionType::Representation::Block: + return ClangASTContext.getBlockPointerType(fn).getTypePtr(); + case SILFunctionType::Representation::Thick: + case SILFunctionType::Representation::Thin: + case SILFunctionType::Representation::Method: + case SILFunctionType::Representation::ObjCMethod: + case SILFunctionType::Representation::WitnessMethod: + case SILFunctionType::Representation::Closure: + llvm_unreachable("Expected a C-compatible representation."); + } +} + clang::QualType ClangTypeConverter::convertMemberType(NominalTypeDecl *DC, StringRef memberName) { auto memberTypeDecl = cast( @@ -576,12 +627,19 @@ clang::QualType ClangTypeConverter::visitFunctionType(FunctionType *type) { } clang::QualType ClangTypeConverter::visitSILFunctionType(SILFunctionType *type) { - llvm::report_fatal_error("Expected only AST types but found a SIL function."); + // We must've already computed it before if applicable. + return clang::QualType(type->getClangTypeInfo().getType(), 0); } clang::QualType ClangTypeConverter::visitSILBlockStorageType(SILBlockStorageType *type) { - llvm::report_fatal_error("Expected only AST types but found a SIL block."); + // We'll select (void)(^)(). This isn't correct for all blocks, but block + // storage type should only be converted for function signature lowering, + // where the parameter types do not matter. + auto &clangCtx = ClangASTContext; + auto fnTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); + auto blockTy = clangCtx.getBlockPointerType(fnTy); + return clangCtx.getCanonicalType(blockTy); } clang::QualType diff --git a/lib/AST/ClangTypeConverter.h b/lib/AST/ClangTypeConverter.h index 450b9e30cf19a..e41a824163312 100644 --- a/lib/AST/ClangTypeConverter.h +++ b/lib/AST/ClangTypeConverter.h @@ -74,6 +74,11 @@ class ClangTypeConverter : ArrayRef params, Type resultTy, AnyFunctionType::Representation repr); + /// Compute the C function type for a SIL function type. + const clang::Type *getFunctionType( + ArrayRef params, Optional result, + SILFunctionType::Representation repr); + /// Check whether the given Clang declaration is an export of a Swift /// declaration introduced by this converter, and if so, return the original /// Swift declaration. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5bddead38a0d4..0e0dc2e17ad00 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7307,13 +7307,14 @@ FuncDecl *FuncDecl::createImplicit(ASTContext &Context, FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, - bool Throws, ParameterList *BodyParams, + bool Async, bool Throws, + ParameterList *BodyParams, Type FnRetType, DeclContext *Parent, ClangNode ClangN) { assert(ClangN && FnRetType); auto *const FD = FuncDecl::createImpl( Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc, - /*Async=*/false, SourceLoc(), Throws, SourceLoc(), + Async, SourceLoc(), Throws, SourceLoc(), /*GenericParams=*/nullptr, Parent, ClangN); FD->setParameters(BodyParams); FD->setResultInterfaceType(FnRetType); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 95a290a0d303c..ea39fdece934e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -126,7 +126,7 @@ namespace { } // end anonymous namespace void Expr::setType(Type T) { - assert(!T || !T->hasTypeVariable()); + assert(!T || !T->hasTypeVariable() || !T->hasHole()); Ty = T; } @@ -288,6 +288,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { return cast(this) ->getSubExpr()->getReferencedDecl(stopAtParenExpr); + PASS_THROUGH_REFERENCE(UnresolvedMemberChainResult, getSubExpr); PASS_THROUGH_REFERENCE(DotSelf, getSubExpr); PASS_THROUGH_REFERENCE(Await, getSubExpr); PASS_THROUGH_REFERENCE(Try, getSubExpr); @@ -606,6 +607,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::Paren: case ExprKind::DotSelf: + case ExprKind::UnresolvedMemberChainResult: case ExprKind::Tuple: case ExprKind::Array: case ExprKind::Dictionary: @@ -1606,61 +1608,6 @@ DynamicSubscriptExpr::create(ASTContext &ctx, Expr *base, Expr *index, hasTrailingClosure, decl, implicit); } -UnresolvedMemberExpr::UnresolvedMemberExpr(SourceLoc dotLoc, - DeclNameLoc nameLoc, - DeclNameRef name, Expr *argument, - ArrayRef argLabels, - ArrayRef argLabelLocs, - bool hasTrailingClosure, - bool implicit) - : Expr(ExprKind::UnresolvedMember, implicit), - DotLoc(dotLoc), NameLoc(nameLoc), Name(name), Argument(argument) { - Bits.UnresolvedMemberExpr.HasArguments = (argument != nullptr); - Bits.UnresolvedMemberExpr.NumArgLabels = argLabels.size(); - Bits.UnresolvedMemberExpr.HasArgLabelLocs = !argLabelLocs.empty(); - Bits.UnresolvedMemberExpr.HasTrailingClosure = hasTrailingClosure; - initializeCallArguments(argLabels, argLabelLocs); -} - -UnresolvedMemberExpr *UnresolvedMemberExpr::create(ASTContext &ctx, - SourceLoc dotLoc, - DeclNameLoc nameLoc, - DeclNameRef name, - bool implicit) { - size_t size = totalSizeToAlloc({ }, { }); - - void *memory = ctx.Allocate(size, alignof(UnresolvedMemberExpr)); - return new (memory) UnresolvedMemberExpr(dotLoc, nameLoc, name, nullptr, - { }, { }, - /*hasTrailingClosure=*/false, - implicit); -} - -UnresolvedMemberExpr * -UnresolvedMemberExpr::create(ASTContext &ctx, SourceLoc dotLoc, - DeclNameLoc nameLoc, DeclNameRef name, - SourceLoc lParenLoc, - ArrayRef args, - ArrayRef argLabels, - ArrayRef argLabelLocs, - SourceLoc rParenLoc, - ArrayRef trailingClosures, - bool implicit) { - SmallVector argLabelsScratch; - SmallVector argLabelLocsScratch; - Expr *arg = packSingleArgument(ctx, lParenLoc, args, argLabels, argLabelLocs, - rParenLoc, trailingClosures, implicit, - argLabelsScratch, argLabelLocsScratch); - - size_t size = totalSizeToAlloc(argLabels, argLabelLocs); - - void *memory = ctx.Allocate(size, alignof(UnresolvedMemberExpr)); - return new (memory) UnresolvedMemberExpr(dotLoc, nameLoc, name, arg, - argLabels, argLabelLocs, - trailingClosures.size() == 1, - implicit); -} - ArrayRef ApplyExpr::getArgumentLabels( SmallVectorImpl &scratch) const { // Unary operators and 'self' applications have a single, unlabeled argument. @@ -2001,7 +1948,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const { } void ClosureExpr::setExplicitResultType(Type ty) { - assert(ty && !ty->hasTypeVariable()); + assert(ty && !ty->hasTypeVariable() && !ty->hasHole()); ExplicitResultTypeAndBodyState.getPointer() ->setType(MetatypeType::get(ty)); } diff --git a/lib/AST/ExtInfo.cpp b/lib/AST/ExtInfo.cpp index a75a3ff1d9f5e..5b779920ace0b 100644 --- a/lib/AST/ExtInfo.cpp +++ b/lib/AST/ExtInfo.cpp @@ -19,6 +19,20 @@ #include "clang/AST/Type.h" +static void assertIsFunctionType(const clang::Type *type) { +#ifndef NDEBUG + if (!(type->isFunctionPointerType() || type->isBlockPointerType() || + type->isFunctionReferenceType())) { + llvm::SmallString<256> buf; + llvm::raw_svector_ostream os(buf); + os << "Expected a Clang function type wrapped in a pointer type or " + << "a block pointer type but found:\n"; + type->dump(os); + llvm_unreachable(os.str().data()); + } +#endif +} + namespace swift { // MARK: - ClangTypeInfo @@ -53,23 +67,12 @@ void ClangTypeInfo::dump(llvm::raw_ostream &os) const { // MARK: - ASTExtInfoBuilder -void ASTExtInfoBuilder::assertIsFunctionType(const clang::Type *type) { -#ifndef NDEBUG - if (!(type->isFunctionPointerType() || type->isBlockPointerType() || - type->isFunctionReferenceType())) { - SmallString<256> buf; - llvm::raw_svector_ostream os(buf); - os << "Expected a Clang function type wrapped in a pointer type or " - << "a block pointer type but found:\n"; - type->dump(os); - llvm_unreachable(os.str().data()); - } -#endif - return; -} - void ASTExtInfoBuilder::checkInvariants() const { - // TODO: Add validation checks here while making sure things don't blow up. + // TODO: [clang-function-type-serialization] Once we start serializing + // the Clang type, we should also assert that the pointer is non-null. + auto Rep = Representation(bits & RepresentationMask); + if ((Rep == Representation::CFunctionPointer) && clangTypeInfo.type) + assertIsFunctionType(clangTypeInfo.type); } // MARK: - ASTExtInfo diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index b581137926415..7ef21cadcb205 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -2434,6 +2434,53 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator, } } + // If we have more than one attribute declaration, we have an ambiguity. + // So, emit an ambiguity diagnostic. + if (auto typeRepr = attr->getTypeRepr()) { + if (nominals.size() > 1) { + SmallVector ambiguousCandidates; + // Filter out declarations that cannot be attributes. + for (auto decl : nominals) { + if (isa(decl)) { + continue; + } + ambiguousCandidates.push_back(decl); + } + if (ambiguousCandidates.size() > 1) { + auto attrName = nominals.front()->getName(); + ctx.Diags.diagnose(typeRepr->getLoc(), + diag::ambiguous_custom_attribute_ref, attrName); + for (auto candidate : ambiguousCandidates) { + ctx.Diags.diagnose(candidate->getLoc(), + diag::found_attribute_candidate); + // If the candidate is a top-level attribute, let's suggest + // adding module name to resolve the ambiguity. + if (candidate->getDeclContext()->isModuleScopeContext()) { + auto moduleName = candidate->getParentModule()->getName(); + ctx.Diags + .diagnose(typeRepr->getLoc(), + diag::ambiguous_custom_attribute_ref_fix, + moduleName.str(), attrName, moduleName) + .fixItInsert(typeRepr->getLoc(), moduleName.str().str() + "."); + } + } + return nullptr; + } + } + } + + // There is no nominal type with this name, so complain about this being + // an unknown attribute. + std::string typeName; + if (auto typeRepr = attr->getTypeRepr()) { + llvm::raw_string_ostream out(typeName); + typeRepr->print(out); + } else { + typeName = attr->getType().getString(); + } + + ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attribute, typeName); + return nullptr; } diff --git a/lib/AST/SILLayout.cpp b/lib/AST/SILLayout.cpp index da70ccd300917..ffbd35175d226 100644 --- a/lib/AST/SILLayout.cpp +++ b/lib/AST/SILLayout.cpp @@ -52,6 +52,8 @@ static void verifyFields(CanGenericSignature Sig, ArrayRef Fields) { && "SILLayout field cannot have an archetype type"); assert(!ty->hasTypeVariable() && "SILLayout cannot contain constraint system type variables"); + assert(!ty->hasHole() && + "SILLayout cannot contain constraint system type holes"); if (!ty->hasTypeParameter()) continue; field.getLoweredType().findIf([Sig](Type t) -> bool { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index bc7d9b780b659..402a33ab65356 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -76,7 +76,7 @@ Type QuerySubstitutionMap::operator()(SubstitutableType *type) const { } void TypeLoc::setType(Type Ty) { - assert(!Ty || !Ty->hasTypeVariable()); + assert(!Ty || !Ty->hasTypeVariable() || !Ty->hasHole()); this->Ty = Ty; } @@ -153,9 +153,7 @@ bool TypeBase::isAny() { return isEqual(getASTContext().TheAnyType); } -bool TypeBase::isHole() { - return isEqual(getASTContext().TheUnresolvedType); -} +bool TypeBase::isHole() { return getCanonicalType()->is(); } bool TypeBase::isAnyClassReferenceType() { return getCanonicalType().isAnyClassReferenceType(); @@ -221,6 +219,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig, case TypeKind::LValue: case TypeKind::InOut: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::SILToken: @@ -1149,6 +1148,7 @@ CanType TypeBase::computeCanonicalType() { case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: + case TypeKind::Hole: llvm_unreachable("these types are always canonical"); #define SUGARED_TYPE(id, parent) \ @@ -4244,6 +4244,7 @@ case TypeKind::Id: case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::GenericTypeParam: case TypeKind::SILToken: case TypeKind::Module: @@ -4378,7 +4379,6 @@ case TypeKind::Id: return SILFunctionType::get( fnTy->getInvocationGenericSignature(), fnTy->getExtInfo(), - fnTy->isAsync(), fnTy->getCoroutineKind(), fnTy->getCalleeConvention(), transInterfaceParams, @@ -4983,6 +4983,7 @@ ReferenceCounting TypeBase::getReferenceCounting() { case TypeKind::LValue: case TypeKind::InOut: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: case TypeKind::SILToken: @@ -5372,7 +5373,7 @@ SILFunctionType::withInvocationSubstitutions(SubstitutionMap subs) const { assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getInvocationGenericSignature()); return SILFunctionType::get(getInvocationGenericSignature(), - getExtInfo(), isAsync(), getCoroutineKind(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), @@ -5390,7 +5391,7 @@ SILFunctionType::withPatternSubstitutions(SubstitutionMap subs) const { assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getPatternGenericSignature()); return SILFunctionType::get(getInvocationGenericSignature(), - getExtInfo(), isAsync(), getCoroutineKind(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), @@ -5409,7 +5410,7 @@ SILFunctionType::withPatternSpecialization(CanGenericSignature sig, assert(!subs || CanGenericSignature(subs.getGenericSignature()) == getSubstGenericSignature()); return SILFunctionType::get(sig, - getExtInfo(), isAsync(), getCoroutineKind(), + getExtInfo(), getCoroutineKind(), getCalleeConvention(), getParameters(), getYields(), getResults(), getOptionalErrorResult(), diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 2185a207bacc4..b2dabac1e1acf 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1018,6 +1018,7 @@ void InterfaceTypeRequest::cacheResult(Type type) const { auto *decl = std::get<0>(getStorage()); if (type) { assert(!type->hasTypeVariable() && "Type variable in interface type"); + assert(!type->hasHole() && "Type hole in interface type"); assert(!type->is() && "Interface type must be materializable"); assert(!type->hasArchetype() && "Archetype in interface type"); } diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp index a5609f8b669fb..468cb6810fc1a 100644 --- a/lib/AST/TypeJoinMeet.cpp +++ b/lib/AST/TypeJoinMeet.cpp @@ -87,6 +87,9 @@ struct TypeJoin : CanTypeVisitor { assert(!first->hasTypeVariable() && !second->hasTypeVariable() && "Cannot compute join of types involving type variables"); + assert(!first->hasHole() && !second->hasHole() && + "Cannot compute join of types involving type holes"); + assert(first->getWithoutSpecifierType()->isEqual(first) && "Expected simple type!"); assert(second->getWithoutSpecifierType()->isEqual(second) && diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index f5be4e10b5223..f95bdb01366f9 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -34,6 +34,7 @@ class Traversal : public TypeVisitor bool visitErrorType(ErrorType *ty) { return false; } bool visitUnresolvedType(UnresolvedType *ty) { return false; } + bool visitHoleType(HoleType *ty) { return false; } bool visitBuiltinType(BuiltinType *ty) { return false; } bool visitTypeAliasType(TypeAliasType *ty) { if (auto parent = ty->getParent()) diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index eddac5d46b3bf..a2ff1426bf477 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -714,8 +714,7 @@ bool importer::isUnavailableInSwift( return false; } -OptionalTypeKind importer::getParamOptionality(version::Version swiftVersion, - const clang::ParmVarDecl *param, +OptionalTypeKind importer::getParamOptionality(const clang::ParmVarDecl *param, bool knownNonNull) { auto &clangCtx = param->getASTContext(); diff --git a/lib/ClangImporter/ClangAdapter.h b/lib/ClangImporter/ClangAdapter.h index 0b066364bd622..9a15bbd523efa 100644 --- a/lib/ClangImporter/ClangAdapter.h +++ b/lib/ClangImporter/ClangAdapter.h @@ -161,15 +161,11 @@ bool isUnavailableInSwift(const clang::Decl *decl, const PlatformAvailability &, /// Determine the optionality of the given Clang parameter. /// -/// \param swiftLanguageVersion What version of Swift we're using, which affects -/// how optionality is inferred. -/// /// \param param The Clang parameter. /// /// \param knownNonNull Whether a function- or method-level "nonnull" attribute /// applies to this parameter. -OptionalTypeKind getParamOptionality(version::Version swiftLanguageVersion, - const clang::ParmVarDecl *param, +OptionalTypeKind getParamOptionality(const clang::ParmVarDecl *param, bool knownNonNull); } } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 419cc50828e7d..b0c131121267b 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3707,6 +3707,7 @@ void ClangImporter::Implementation::lookupValue( clangDecl->getMostRecentDecl(); CurrentVersion.forEachOtherImportNameVersion( + SwiftContext.LangOpts.EnableExperimentalConcurrency, [&](ImportNameVersion nameVersion) { if (anyMatching) return; @@ -3716,6 +3717,12 @@ void ClangImporter::Implementation::lookupValue( if (!newName.getDeclName().matchesRef(name)) return; + // If we asked for an async import and didn't find one, skip this. + // This filters out duplicates. + if (nameVersion.supportsConcurrency() && + !newName.getAsyncInfo()) + return; + const clang::DeclContext *clangDC = newName.getEffectiveContext().getAsDeclContext(); if (!clangDC || !clangDC->isFileContext()) diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index ed49b5213ead5..c465b1eb2473c 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -254,6 +254,18 @@ void ClangImporter::recordModuleDependencies( swiftArgs.push_back("-module-name"); swiftArgs.push_back(clangModuleDep.ModuleName); + // Pass down search paths to the -emit-module action. + // Unlike building Swift modules, we need to include all search paths to + // the clang invocation to build PCMs because transitive headers can only + // be found via search paths. Passing these headers as explicit inputs can + // be quite challenging. + for (auto &path: Impl.SwiftContext.SearchPathOpts.ImportSearchPaths) { + addClangArg("-I" + path); + } + for (auto &path: Impl.SwiftContext.SearchPathOpts.FrameworkSearchPaths) { + addClangArg((path.IsSystem ? "-Fsystem": "-F") + path.Path); + } + // Swift frontend option for input file path (Foo.modulemap). swiftArgs.push_back(clangModuleDep.ClangModuleMapFile); // Module-level dependencies. @@ -294,6 +306,7 @@ Optional ClangImporter::getModuleDependencies( // Reform the Clang importer options. // FIXME: Just save a reference or copy so we can get this back. ClangImporterOptions importerOpts; + importerOpts.ExtraArgs = getExtraClangArgs(); // Determine the command-line arguments for dependency scanning. auto &ctx = Impl.SwiftContext; @@ -337,6 +350,7 @@ bool ClangImporter::addBridgingHeaderDependencies( // Reform the Clang importer options. // FIXME: Just save a reference or copy so we can get this back. ClangImporterOptions importerOpts; + importerOpts.ExtraArgs = getExtraClangArgs(); // Retrieve the bridging header. std::string bridgingHeader = *targetModule.getBridgingHeader(); diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 0a6f172ece6e9..96264e391643c 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -160,6 +160,7 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, DeclName name, SourceLoc nameLoc, ParameterList *bodyParams, Type resultTy, + bool async, bool throws, DeclContext *dc, ClangNode clangNode) { @@ -176,7 +177,7 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc, bodyParams, resultTy, dc, clangNode); } else { - return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, throws, + return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, async, throws, bodyParams, resultTy, dc, clangNode); } } @@ -2254,7 +2255,7 @@ namespace { /// Whether the names we're importing are from the language version the user /// requested, or if these are decls from another version bool isActiveSwiftVersion() const { - return getVersion() == getActiveSwiftVersion(); + return getVersion().withConcurrency(false) == getActiveSwiftVersion().withConcurrency(false); } void recordMemberInContext(const DeclContext *dc, ValueDecl *member) { @@ -2300,7 +2301,7 @@ namespace { return canonicalName; } - // Special handling when we import using the older Swift name. + // Special handling when we import using the alternate Swift name. // // Import using the alternate Swift name. If that fails, or if it's // identical to the active Swift name, we won't introduce an alternate @@ -2309,6 +2310,19 @@ namespace { if (!alternateName) return ImportedName(); + // Importing for concurrency is special in that the same declaration + // is imported both with a completion handler parameter and as 'async', + // creating two separate declarations. + if (getVersion().supportsConcurrency()) { + // If the resulting name isn't special for concurrency, it's not + // different. + if (!alternateName.getAsyncInfo()) + return ImportedName(); + + // Otherwise, it's a legitimately different import. + return alternateName; + } + if (alternateName.getDeclName() == canonicalName.getDeclName() && alternateName.getEffectiveContext().equalsWithoutResolving( canonicalName.getEffectiveContext())) { @@ -2470,6 +2484,13 @@ namespace { return; } + // If this the active and current Swift versions differ based on + // concurrency, it's not actually a variant. + if (getVersion().supportsConcurrency() != + getActiveSwiftVersion().supportsConcurrency()) { + return; + } + // TODO: some versions should be deprecated instead of unavailable ASTContext &ctx = decl->getASTContext(); @@ -3843,9 +3864,10 @@ namespace { // FIXME: Poor location info. auto nameLoc = Impl.importSourceLoc(decl->getLocation()); - result = createFuncOrAccessor(Impl.SwiftContext, loc, accessorInfo, name, - nameLoc, bodyParams, resultTy, - /*throws*/ false, dc, decl); + result = createFuncOrAccessor( + Impl.SwiftContext, loc, accessorInfo, name, + nameLoc, bodyParams, resultTy, + /*async*/ false, /*throws*/ false, dc, decl); if (!dc->isModuleScopeContext()) { if (selfIsInOut) @@ -4416,6 +4438,16 @@ namespace { } } + // Determine whether the function is throwing and/or async. + bool throws = importedName.getErrorInfo().hasValue(); + bool async = false; + auto asyncConvention = importedName.getAsyncInfo(); + if (asyncConvention) { + async = true; + if (asyncConvention->isThrowing()) + throws = true; + } + auto resultTy = importedType.getType(); auto isIUO = importedType.isImplicitlyUnwrapped(); @@ -4445,8 +4477,7 @@ namespace { importedName.getDeclName(), /*nameLoc*/SourceLoc(), bodyParams, resultTy, - importedName.getErrorInfo().hasValue(), - dc, decl); + async, throws, dc, decl); result->setAccess(getOverridableAccessLevel(dc)); @@ -4478,6 +4509,11 @@ namespace { result->setForeignErrorConvention(*errorConvention); } + // Record the async convention. + if (asyncConvention) { + result->setForeignAsyncConvention(*asyncConvention); + } + // Handle attributes. if (decl->hasAttr() && isa(result) && @@ -4509,6 +4545,7 @@ namespace { Impl.addAlternateDecl(result, cast(imported)); } } + return result; } @@ -6449,6 +6486,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( return known->second; // Create the actual constructor. + assert(!importedName.getAsyncInfo()); auto result = Impl.createDeclWithClangNode( objcMethod, AccessLevel::Public, importedName.getDeclName(), /*NameLoc=*/SourceLoc(), failability, /*FailabilityLoc=*/SourceLoc(), @@ -7151,6 +7189,11 @@ void SwiftDeclConverter::importMirroredProtocolMembers( if (isa(afd)) return; + // Asynch methods are also always imported without async, so don't + // record them here. + if (afd->hasAsync()) + return; + auto objcMethod = dyn_cast_or_null(member->getClangDecl()); if (!objcMethod) diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 46817ce93de2a..fc0313bbc91df 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -807,8 +807,6 @@ static bool omitNeedlessWordsInFunctionName( Optional errorParamIndex, bool returnsSelf, bool isInstanceMethod, NameImporter &nameImporter) { clang::ASTContext &clangCtx = nameImporter.getClangContext(); - const version::Version &swiftLanguageVersion = - nameImporter.getLangOpts().EffectiveLanguageVersion; // Collect the parameter type names. StringRef firstParamName; @@ -837,8 +835,7 @@ static bool omitNeedlessWordsInFunctionName( bool hasDefaultArg = ClangImporter::Implementation::inferDefaultArgument( param->getType(), - getParamOptionality(swiftLanguageVersion, param, - !nonNullArgs.empty() && nonNullArgs[i]), + getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[i]), nameImporter.getIdentifier(baseName), argumentName, i == 0, isLastParameter, nameImporter) != DefaultArgumentKind::None; @@ -1139,6 +1136,181 @@ Optional NameImporter::considerErrorImport( return None; } +/// Whether the given parameter name identifies a completion handler. +static bool isCompletionHandlerParamName(StringRef paramName) { + return paramName == "completionHandler" || paramName == "completion" || + paramName == "withCompletionHandler"; +} + +/// Whether the give base name implies that the first parameter is a completion +/// handler. +/// +/// \returns a trimmed base name when it does, \c None others +static Optional isCompletionHandlerInBaseName(StringRef basename) { + if (basename.endswith("WithCompletionHandler")) { + return basename.drop_back(strlen("WithCompletionHandler")); + } + + if (basename.endswith("WithCompletion")) { + return basename.drop_back(strlen("WithCompletion")); + } + + return None; +} + + +// Determine whether the given type is a nullable NSError type. +static bool isNullableNSErrorType( + clang::ASTContext &clangCtx, clang::QualType type) { + auto objcPtrType = type->getAs(); + if (!objcPtrType) + return false; + + auto iface = objcPtrType->getInterfaceDecl(); + if (!iface || iface->getName() != "NSError") + return false; + + // If nullability is specified, check it. + if (auto nullability = type->getNullability(clangCtx)) { + switch (translateNullability(*nullability)) { + case OTK_None: + return false; + + case OTK_ImplicitlyUnwrappedOptional: + case OTK_Optional: + return true; + } + } + + // Otherwise, assume it's nullable. + return true; +} + +Optional +NameImporter::considerAsyncImport( + const clang::ObjCMethodDecl *clangDecl, + StringRef &baseName, + SmallVectorImpl ¶mNames, + ArrayRef params, + bool isInitializer, bool hasCustomName, + Optional errorInfo) { + // If there are no unclaimed parameters, there's no . + unsigned errorParamAdjust = errorInfo ? 1 : 0; + if (params.size() - errorParamAdjust == 0) + return None; + + // If the # of parameter names doesn't line up with the # of parameters, + // bail out. There are extra C parameters on the method or a custom name + // was incorrect. + if (params.size() != paramNames.size() + errorParamAdjust) + return None; + + // The last parameter will be the completion handler for an async function. + unsigned completionHandlerParamIndex = params.size() - 1; + unsigned completionHandlerParamNameIndex = paramNames.size() - 1; + + // Determine whether the naming indicates that this is a completion + // handler. + Optional newBaseName; + if (isCompletionHandlerParamName(paramNames[completionHandlerParamNameIndex])) { + // The argument label itself has an appropriate name. + } else if (!hasCustomName && completionHandlerParamIndex == 0 && + (newBaseName = isCompletionHandlerInBaseName(baseName))) { + // The base name implies that the first parameter is a completion handler. + } else if (isCompletionHandlerParamName( + params[completionHandlerParamIndex]->getName())) { + // The parameter has an appropriate name. + } else { + return None; + } + + // Used for returns once we've determined that the method cannot be + // imported as async, even though it has what looks like a completion handler + // parameter. + auto notAsync = [&](const char *reason) -> Optional { +#ifdef ASYNC_IMPORT_DEBUG + llvm::errs() << "*** failed async import: " << reason << "\n"; + clangDecl->dump(llvm::errs()); +#endif + + return None; + }; + + // Initializers cannot be 'async'. + // FIXME: We might eventually allow this. + if (isInitializer) + return notAsync("initializers cannot be async"); + + // Accessors are never imported as async. + if (clangDecl->isPropertyAccessor()) + return notAsync("method is a property accessor"); + + // Check whether we method has a suitable return type. + if (clangDecl->getReturnType()->isVoidType()) { + // 'void' is the common case; the method produces no synchronous result. + } else if (errorInfo && + ForeignErrorConvention::resultTypeErasedToVoid( + errorInfo->getKind())) { + // The method has been imported as throwing in a manner that erased the + // result type to Void. + } else { + return notAsync("method does not return void"); + } + + // The completion handler parameter must have block type. + auto completionHandlerParam = params[completionHandlerParamIndex]; + if (!isBlockParameter(completionHandlerParam)) + return notAsync("parameter is not a block"); + + // Dig out the function type of the completion handler's block type. + // If there is no prototype, (e.g., the completion handler is of type + // void (^)()), we cannot importer it. + auto completionHandlerFunctionType = + completionHandlerParam->getType()->castAs() + ->getPointeeType()->getAs(); + if (!completionHandlerFunctionType) + return notAsync("block parameter does not have a prototype"); + + // The completion handler parameter must itself return 'void'. + if (!completionHandlerFunctionType->getReturnType()->isVoidType()) + return notAsync("completion handler parameter does not return 'void'"); + + // Scan the parameters of the block type to look for a parameter of a + // nullable NSError type, which would indicate that the async method could + // throw. + Optional completionHandlerErrorParamIndex; + auto completionHandlerParamTypes = + completionHandlerFunctionType->getParamTypes(); + auto &clangCtx = clangDecl->getASTContext(); + for (unsigned paramIdx : indices(completionHandlerParamTypes)) { + auto paramType = completionHandlerParamTypes[paramIdx]; + + // We are only interested in nullable NSError parameters. + if (!isNullableNSErrorType(clangCtx, paramType)) + continue; + + // If this is the first nullable error parameter, note that. + if (!completionHandlerErrorParamIndex) { + completionHandlerErrorParamIndex = paramIdx; + continue; + } + + // More than one nullable NSError parameter. Don't import as throwing. + completionHandlerErrorParamIndex = None; + break; + } + + // Drop the completion handler parameter name. + paramNames.erase(paramNames.begin() + completionHandlerParamNameIndex); + + // Update the base name, if needed. + if (newBaseName && !hasCustomName) + baseName = *newBaseName; + + return ForeignAsyncConvention( + completionHandlerParamIndex, completionHandlerErrorParamIndex); +} + bool NameImporter::hasErrorMethodNameCollision( const clang::ObjCMethodDecl *method, unsigned paramIndex, StringRef suffixToStrip) { @@ -1350,7 +1522,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, else if (parsedName.IsSetter) result.info.accessorKind = ImportedAccessorKind::PropertySetter; - if (method && parsedName.IsFunctionName) { + if (method && parsedName.IsFunctionName && + result.info.accessorKind == ImportedAccessorKind::None) { // Get the parameters. ArrayRef params{method->param_begin(), method->param_end()}; @@ -1362,6 +1535,21 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.hasErrorInfo = true; result.info.errorInfo = *errorInfo; } + + if (version.supportsConcurrency()) { + if (auto asyncInfo = considerAsyncImport( + method, parsedName.BaseName, parsedName.ArgumentLabels, + params, isInitializer, /*hasCustomName=*/true, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + + // Update the name to reflect the new parameter labels. + result.declName = formDeclName( + swiftCtx, parsedName.BaseName, parsedName.ArgumentLabels, + /*isFunction=*/true, isInitializer); + } + } } return result; @@ -1624,6 +1812,17 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, result.info.accessorKind = ImportedAccessorKind::SubscriptSetter; } + if (version.supportsConcurrency() && + result.info.accessorKind == ImportedAccessorKind::None) { + if (auto asyncInfo = considerAsyncImport( + objcMethod, baseName, argumentNames, params, isInitializer, + /*hasCustomName=*/false, + result.getErrorInfo())) { + result.info.hasAsyncInfo = true; + result.info.asyncInfo = *asyncInfo; + } + } + break; } } @@ -1895,6 +2094,7 @@ bool NameImporter::forEachDistinctImportName( seenNames.push_back(key); activeVersion.forEachOtherImportNameVersion( + swiftCtx.LangOpts.EnableExperimentalConcurrency, [&](ImportNameVersion nameVersion) { // Check to see if the name is different. ImportedName newName = importName(decl, nameVersion); diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h index ddb4b0aa4105c..09d90703563c9 100644 --- a/lib/ClangImporter/ImportName.h +++ b/lib/ClangImporter/ImportName.h @@ -23,6 +23,7 @@ #include "swift/Basic/Version.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/ForeignAsyncConvention.h" #include "swift/AST/ForeignErrorConvention.h" #include "clang/Sema/Sema.h" @@ -42,15 +43,18 @@ enum { NumImportedAccessorKindBits = 3 }; /// The name version class ImportNameVersion : public RelationalOperationsBase { - unsigned rawValue; + unsigned rawValue : 31; + unsigned concurrency : 1; + friend llvm::DenseMapInfo; enum AsConstExpr_t { AsConstExpr }; - constexpr ImportNameVersion() : rawValue(0) {} + constexpr ImportNameVersion() : rawValue(0), concurrency(false) {} constexpr ImportNameVersion(unsigned version, AsConstExpr_t) - : rawValue(version) {} - explicit ImportNameVersion(unsigned version) : rawValue(version) { + : rawValue(version), concurrency(false) {} + explicit ImportNameVersion(unsigned version, bool concurrency = false) + : rawValue(version), concurrency(concurrency) { assert(version >= 2 && "only Swift 2 and later are supported"); } public: @@ -67,7 +71,7 @@ class ImportNameVersion : public RelationalOperationsBase { return ImportNameVersion::swift4_2(); } unsigned major = version[0]; - return ImportNameVersion(major >= 5 ? major + 1 : major); + return ImportNameVersion(major >= 5 ? major + 1 : major, false); } unsigned majorVersionNumber() const { @@ -89,11 +93,21 @@ class ImportNameVersion : public RelationalOperationsBase { return llvm::VersionTuple(majorVersionNumber(), minorVersionNumber()); } + /// Whether to consider importing functions as 'async'. + bool supportsConcurrency() const { return concurrency; } + + ImportNameVersion withConcurrency(bool concurrency) const { + ImportNameVersion result = *this; + result.concurrency = concurrency; + return result; + } + bool operator==(ImportNameVersion other) const { - return rawValue == other.rawValue; + return rawValue == other.rawValue && concurrency == other.concurrency; } bool operator<(ImportNameVersion other) const { - return rawValue < other.rawValue; + return rawValue < other.rawValue || + (rawValue == other.rawValue && concurrency < other.concurrency); } /// Calls \p action for each name version other than this one, first going @@ -102,10 +116,19 @@ class ImportNameVersion : public RelationalOperationsBase { /// /// This is the most useful order for importing compatibility stubs. void forEachOtherImportNameVersion( + bool withConcurrency, llvm::function_ref action) const { assert(*this >= ImportNameVersion::swift2()); ImportNameVersion nameVersion = *this; + assert(!nameVersion.supportsConcurrency()); + + // If we've been asked to also consider concurrency, do so for the + // primary version (only). + if (withConcurrency) { + action(nameVersion.withConcurrency(true)); + } + while (nameVersion > ImportNameVersion::swift2()) { --nameVersion.rawValue; action(nameVersion); @@ -175,6 +198,10 @@ class ImportedName { /// throwing Swift methods, describes how the mapping is performed. ForeignErrorConvention::Info errorInfo; + /// For names that map Objective-C completion handlers into async + /// Swift methods, describes how the mapping is performed. + ForeignAsyncConvention asyncInfo; + /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. unsigned selfIndex; @@ -201,11 +228,13 @@ class ImportedName { unsigned hasErrorInfo : 1; + unsigned hasAsyncInfo : 1; + Info() : errorInfo(), selfIndex(), initKind(CtorInitializerKind::Designated), accessorKind(ImportedAccessorKind::None), hasCustomName(false), droppedVariadic(false), importAsMember(false), hasSelfIndex(false), - hasErrorInfo(false) {} + hasErrorInfo(false), hasAsyncInfo(false) {} } info; public: @@ -239,6 +268,14 @@ class ImportedName { return None; } + /// For names that map Objective-C methods with completion handlers into + /// async Swift methods, describes how the mapping is performed. + Optional getAsyncInfo() const { + if (info.hasAsyncInfo) + return info.asyncInfo; + return None; + } + /// For a declaration name that makes the declaration into an /// instance member, the index of the "Self" parameter. Optional getSelfIndex() const { @@ -416,6 +453,14 @@ class NameImporter { ArrayRef params, bool isInitializer, bool hasCustomName); + Optional + considerAsyncImport(const clang::ObjCMethodDecl *clangDecl, + StringRef &baseName, + SmallVectorImpl ¶mNames, + ArrayRef params, + bool isInitializer, bool hasCustomName, + Optional errorInfo); + EffectiveClangContext determineEffectiveContext(const clang::NamedDecl *, const clang::DeclContext *, ImportNameVersion version); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index a13fb40d28210..e9e0599b5f8fc 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1747,8 +1747,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( // Check nullability of the parameter. OptionalTypeKind OptionalityOfParam = - getParamOptionality(SwiftContext.LangOpts.EffectiveLanguageVersion, - param, !nonNullArgs.empty() && nonNullArgs[index]); + getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[index]); ImportTypeKind importKind = ImportTypeKind::Parameter; if (param->hasAttr()) @@ -1989,6 +1988,42 @@ static Type mapGenericArgs(const DeclContext *fromDC, return type.subst(subs); } +/// Decompose the type of a completion handler parameter in a function +/// imported as 'async' and produce the result type of the 'async' function. +static Type decomposeCompletionHandlerType( + Type paramTy, ForeignAsyncConvention info) { + auto fnType = paramTy->lookThroughAllOptionalTypes()->getAs(); + if (!fnType) + return Type(); + + SmallVector resultTypeElts; + auto params = fnType->getParams(); + for (unsigned paramIdx : indices(params)) { + const auto ¶m = params[paramIdx]; + if (param.isInOut() || param.isVariadic()) + return Type(); + + // If there is an error parameter to the completion handler, it is + // not part of the result type of the asynchronous function. + if (info.completionHandlerErrorParamIndex() && + paramIdx == *info.completionHandlerErrorParamIndex()) + continue; + + resultTypeElts.push_back(param.getPlainType()); + } + + switch (resultTypeElts.size()) { + case 0: + return paramTy->getASTContext().getVoidDecl()->getDeclaredInterfaceType(); + + case 1: + return resultTypeElts.front().getType(); + + default: + return TupleType::get(resultTypeElts, paramTy->getASTContext()); + } +} + ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( const DeclContext *dc, const clang::ObjCMethodDecl *clangDecl, ArrayRef params, bool isVariadic, @@ -2025,6 +2060,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( CanType origSwiftResultTy; Optional errorInfo = importedName.getErrorInfo(); + auto asyncInfo = importedName.getAsyncInfo(); OptionalTypeKind OptionalityOfReturn; if (clangDecl->hasAttr()) { OptionalityOfReturn = OTK_None; @@ -2123,12 +2159,14 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( continue; } + bool paramIsCompletionHandler = + asyncInfo && paramIndex == asyncInfo->completionHandlerParamIndex(); + // Import the parameter type into Swift. // Check nullability of the parameter. OptionalTypeKind optionalityOfParam - = getParamOptionality(SwiftContext.LangOpts.EffectiveLanguageVersion, - param, + = getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[paramIndex]); bool allowNSUIntegerAsIntInParam = isFromSystemModule; @@ -2193,6 +2231,21 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( continue; } + // If this is a completion handler, figure out it's effect on the result + // type but don't build it into the parameter type. + if (paramIsCompletionHandler) { + if (Type replacedSwiftResultTy = + decomposeCompletionHandlerType(swiftParamTy, *asyncInfo)) { + swiftResultTy = replacedSwiftResultTy; + + // FIXME: We will need an equivalent to "error parameter is replaced" + // for asynchronous functions. Perhaps add "async: ()"? + continue; + } + + llvm_unreachable("async info computed incorrectly?"); + } + // Map __attribute__((noescape)) to @noescape. bool addNoEscapeAttr = false; if (param->hasAttr()) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 3ac0d0fe45d0c..6653b2d0ee38d 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1857,6 +1857,7 @@ SwiftNameLookupExtension::hashExtension(llvm::hash_code code) const { SWIFT_LOOKUP_TABLE_VERSION_MAJOR, SWIFT_LOOKUP_TABLE_VERSION_MINOR, inferImportAsMember, + swiftCtx.LangOpts.EnableExperimentalConcurrency, version::getSwiftFullVersion()); } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 3628481d8a47e..f49ba90261714 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2669,7 +2669,7 @@ NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind) { } NodePointer Demangler::demangleWitness() { - switch (nextChar()) { + switch (char c = nextChar()) { case 'C': return createWithChild(Node::Kind::EnumCase, popNode(isEntity)); @@ -2811,6 +2811,30 @@ NodePointer Demangler::demangleWitness() { return nullptr; } } + case 'Z': + case 'z': { + auto declList = createNode(Node::Kind::GlobalVariableOnceDeclList); + std::vector vars; + while (auto sig = popNode(Node::Kind::FirstElementMarker)) { + auto identifier = popNode(isDeclName); + if (!identifier) + return nullptr; + vars.push_back(identifier); + } + for (auto i = vars.rbegin(); i != vars.rend(); ++i) { + declList->addChild(*i, *this); + } + + auto context = popContext(); + if (!context) + return nullptr; + Node::Kind kind = c == 'Z' + ? Node::Kind::GlobalVariableOnceFunction + : Node::Kind::GlobalVariableOnceToken; + return createWithChildren(kind, + context, + declList); + } default: return nullptr; } diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index e7ea0e52e29d6..3a7fc824699b2 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -552,6 +552,9 @@ class NodePrinter { case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache: + case Node::Kind::GlobalVariableOnceDeclList: + case Node::Kind::GlobalVariableOnceFunction: + case Node::Kind::GlobalVariableOnceToken: return false; } printer_unreachable("bad node kind"); @@ -2466,6 +2469,28 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { Printer << "cache variable for noncanonical specialized generic type metadata for "; print(Node->getChild(0)); return nullptr; + case Node::Kind::GlobalVariableOnceToken: + case Node::Kind::GlobalVariableOnceFunction: + Printer << (kind == Node::Kind::GlobalVariableOnceToken + ? "one-time initialization token for " + : "one-time initialization function for "); + printContext(Node->getChild(0)); + print(Node->getChild(1)); + return nullptr; + case Node::Kind::GlobalVariableOnceDeclList: + if (Node->getNumChildren() == 1) { + print(Node->getChild(0)); + } else { + Printer << '('; + for (unsigned i = 0, e = Node->getNumChildren(); i < e; ++i) { + if (i != 0) { + Printer << ", "; + } + print(Node->getChild(i)); + } + Printer << ')'; + } + return nullptr; } printer_unreachable("bad node kind!"); } diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index ba7ca2eb51960..7df26cbfad047 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2139,6 +2139,15 @@ void Remangler::mangleAccessorFunctionReference(Node *node) { void Remangler::mangleMetadataInstantiationCache(Node *node) { unreachable("unsupported"); } +void Remangler::mangleGlobalVariableOnceToken(Node *node) { + unreachable("unsupported"); +} +void Remangler::mangleGlobalVariableOnceFunction(Node *node) { + unreachable("unsupported"); +} +void Remangler::mangleGlobalVariableOnceDeclList(Node *node) { + unreachable("unsupported"); +} void Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node) { Buffer << "MM"; diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 60dfeafaee925..8abad3f38cf0f 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2566,6 +2566,23 @@ void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadataCache(Node *node Buffer << "MJ"; } +void Remangler::mangleGlobalVariableOnceToken(Node *node) { + mangleChildNodes(node); + Buffer << "Wz"; +} + +void Remangler::mangleGlobalVariableOnceFunction(Node *node) { + mangleChildNodes(node); + Buffer << "WZ"; +} + +void Remangler::mangleGlobalVariableOnceDeclList(Node *node) { + for (unsigned i = 0, e = node->getNumChildren(); i < e; ++i) { + mangle(node->getChild(i)); + Buffer << '_'; + } +} + } // anonymous namespace /// The top-level interface to the remangler. diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 4e12495bb35df..c876a44f87383 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -406,8 +406,7 @@ bool ArgsToFrontendOptionsConverter::setUpInputKindAndImmediateArgs() { if (Opts.InputsAndOutputs.verifyInputs( Diags, treatAsSIL, Opts.RequestedAction == FrontendOptions::ActionType::REPL, - (Opts.RequestedAction == FrontendOptions::ActionType::NoneAction || - Opts.RequestedAction == FrontendOptions::ActionType::PrintVersion))){ + !FrontendOptions::doesActionRequireInputs(Opts.RequestedAction))) { return true; } if (Opts.RequestedAction == FrontendOptions::ActionType::Immediate) { diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 7b2fa3ef30d4a..688acbf0b29dd 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -33,6 +33,7 @@ #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/Serialization/SerializationOptions.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Strings.h" #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" @@ -522,9 +523,36 @@ bool CompilerInstance::setUpModuleLoaders() { this->DefaultSerializedLoader = ISML.get(); Context->addModuleLoader(std::move(ISML)); } - + Context->addModuleLoader(std::move(clangImporter), /*isClang*/ true); + // When scanning for dependencies, we must add the scanner loaders in order to handle + // ASTContext operations such as canImportModule + if (Invocation.getFrontendOptions().RequestedAction == + FrontendOptions::ActionType::ScanDependencies) { + auto ModuleCachePath = getModuleCachePathFromClang(Context + ->getClangModuleLoader()->getClangInstance()); + auto &FEOpts = Invocation.getFrontendOptions(); + ModuleInterfaceLoaderOptions LoaderOpts(FEOpts); + InterfaceSubContextDelegateImpl ASTDelegate(Context->SourceMgr, Context->Diags, + Context->SearchPathOpts, Context->LangOpts, + LoaderOpts, + Context->getClangModuleLoader(), + /*buildModuleCacheDirIfAbsent*/false, + ModuleCachePath, + FEOpts.PrebuiltModuleCachePath, + FEOpts.SerializeModuleInterfaceDependencyHashes, + FEOpts.shouldTrackSystemDependencies()); + auto mainModuleName = Context->getIdentifier(FEOpts.ModuleName); + std::unique_ptr PSMS = + std::make_unique(*Context, + MLM, + mainModuleName, + Context->SearchPathOpts.PlaceholderDependencyModuleMap, + ASTDelegate); + Context->addModuleLoader(std::move(PSMS)); + } + return false; } @@ -820,7 +848,7 @@ void CompilerInstance::setMainModule(ModuleDecl *newMod) { Context->addLoadedModule(newMod); } -void CompilerInstance::performParseAndResolveImportsOnly() { +bool CompilerInstance::performParseAndResolveImportsOnly() { FrontendStatsTracer tracer(getStatsReporter(), "parse-and-resolve-imports"); // Resolve imports for all the source files. @@ -839,6 +867,7 @@ void CompilerInstance::performParseAndResolveImportsOnly() { mainModule->setHasResolvedImports(); bindExtensions(*mainModule); + return Context->hadError(); } void CompilerInstance::performSema() { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 83718a733666e..16fe1877a6d25 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -73,20 +73,104 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { bool FrontendOptions::shouldActionOnlyParse(ActionType action) { switch (action) { - case FrontendOptions::ActionType::Parse: - case FrontendOptions::ActionType::DumpParse: - case FrontendOptions::ActionType::EmitSyntax: - case FrontendOptions::ActionType::DumpInterfaceHash: - case FrontendOptions::ActionType::EmitImportedModules: - case FrontendOptions::ActionType::ScanDependencies: - case FrontendOptions::ActionType::ScanClangDependencies: - case FrontendOptions::ActionType::PrintVersion: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::PrintVersion: return true; default: return false; } } +bool FrontendOptions::doesActionRequireSwiftStandardLibrary(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::PrintVersion: + case ActionType::EmitPCH: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + return false; + case ActionType::ResolveImports: + case ActionType::Typecheck: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitModuleOnly: + case ActionType::MergeModules: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::Immediate: + case ActionType::REPL: + case ActionType::EmitAssembly: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitObject: + case ActionType::DumpTypeInfo: + assert(!FrontendOptions::shouldActionOnlyParse(action) && + "Parse-only actions should not load modules!"); + return true; + } + llvm_unreachable("Unknown ActionType"); +} + +bool FrontendOptions::doesActionRequireInputs(ActionType action) { + switch (action) { + case ActionType::NoneAction: + case ActionType::PrintVersion: + return false; + case ActionType::REPL: + case ActionType::Parse: + case ActionType::DumpParse: + case ActionType::EmitSyntax: + case ActionType::DumpInterfaceHash: + case ActionType::EmitImportedModules: + case ActionType::ScanDependencies: + case ActionType::ScanClangDependencies: + case ActionType::EmitPCH: + case ActionType::EmitPCM: + case ActionType::DumpPCM: + case ActionType::CompileModuleFromInterface: + case ActionType::TypecheckModuleFromInterface: + case ActionType::ResolveImports: + case ActionType::Typecheck: + case ActionType::DumpAST: + case ActionType::PrintAST: + case ActionType::DumpScopeMaps: + case ActionType::DumpTypeRefinementContexts: + case ActionType::EmitSILGen: + case ActionType::EmitSIL: + case ActionType::EmitModuleOnly: + case ActionType::MergeModules: + case ActionType::EmitSIBGen: + case ActionType::EmitSIB: + case ActionType::Immediate: + case ActionType::EmitAssembly: + case ActionType::EmitIR: + case ActionType::EmitBC: + case ActionType::EmitObject: + case ActionType::DumpTypeInfo: + return true; + } + llvm_unreachable("Unknown ActionType"); +} + void FrontendOptions::forAllOutputPaths( const InputFile &input, llvm::function_ref fn) const { if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly && diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 4221b53394e5f..f4b42016d7d46 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1229,7 +1229,7 @@ static void verifyGenericSignaturesIfNeeded(const CompilerInvocation &Invocation GenericSignatureBuilder::verifyGenericSignaturesInModule(module); } -static void dumpAndPrintScopeMap(const CompilerInstance &Instance, +static bool dumpAndPrintScopeMap(const CompilerInstance &Instance, SourceFile *SF) { // Not const because may require reexpansion ASTScope &scope = SF->getScope(); @@ -1239,13 +1239,14 @@ static void dumpAndPrintScopeMap(const CompilerInstance &Instance, llvm::errs() << "***Complete scope map***\n"; scope.buildFullyExpandedTree(); scope.print(llvm::errs()); - return; + return Instance.getASTContext().hadError(); } // Probe each of the locations, and dump what we find. for (auto lineColumn : opts.DumpScopeMapLocations) { scope.buildFullyExpandedTree(); scope.dumpOneScopeMapLocation(lineColumn); } + return Instance.getASTContext().hadError(); } static SourceFile * @@ -1260,7 +1261,7 @@ getPrimaryOrMainSourceFile(const CompilerInstance &Instance) { /// Dumps the AST of all available primary source files. If corresponding output /// files were specified, use them; otherwise, dump the AST to stdout. -static void dumpAST(CompilerInstance &Instance) { +static bool dumpAST(CompilerInstance &Instance) { auto primaryFiles = Instance.getPrimarySourceFiles(); if (!primaryFiles.empty()) { for (SourceFile *sourceFile: primaryFiles) { @@ -1275,55 +1276,7 @@ static void dumpAST(CompilerInstance &Instance) { auto *SF = getPrimaryOrMainSourceFile(Instance); SF->dump(llvm::outs(), /*parseIfNeeded*/ true); } -} - -/// We may have been told to dump the AST (either after parsing or -/// type-checking, which is already differentiated in -/// CompilerInstance::performSema()), so dump or print the main source file and -/// return. - -static Optional dumpASTIfNeeded(CompilerInstance &Instance) { - const auto &opts = Instance.getInvocation().getFrontendOptions(); - const FrontendOptions::ActionType Action = opts.RequestedAction; - ASTContext &Context = Instance.getASTContext(); - switch (Action) { - default: - return None; - - case FrontendOptions::ActionType::PrintAST: - getPrimaryOrMainSourceFile(Instance) - ->print(llvm::outs(), PrintOptions::printEverything()); - break; - - case FrontendOptions::ActionType::DumpScopeMaps: - dumpAndPrintScopeMap(Instance, getPrimaryOrMainSourceFile(Instance)); - break; - - case FrontendOptions::ActionType::DumpTypeRefinementContexts: - getPrimaryOrMainSourceFile(Instance) - ->getTypeRefinementContext() - ->dump(llvm::errs(), Context.SourceMgr); - break; - - case FrontendOptions::ActionType::DumpInterfaceHash: - getPrimaryOrMainSourceFile(Instance)->dumpInterfaceHash(llvm::errs()); - break; - - case FrontendOptions::ActionType::EmitSyntax: - emitSyntax(getPrimaryOrMainSourceFile(Instance), - opts.InputsAndOutputs.getSingleOutputFilename()); - break; - - case FrontendOptions::ActionType::DumpParse: - case FrontendOptions::ActionType::DumpAST: - dumpAST(Instance); - break; - - case FrontendOptions::ActionType::EmitImportedModules: - emitImportedModules(Context, Instance.getMainModule(), opts); - break; - } - return Context.hadError(); + return Instance.getASTContext().hadError(); } static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded( @@ -1700,6 +1653,7 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { // it's -emit-imported-modules, which can load modules. auto action = opts.RequestedAction; if (FrontendOptions::shouldActionOnlyParse(action) && + !ctx.getLoadedModules().empty() && action != FrontendOptions::ActionType::EmitImportedModules) { assert(ctx.getNumLoadedModules() == 1 && "Loaded a module during parse-only"); @@ -1736,9 +1690,15 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { } } - // Emit dependencies and index data. + // FIXME: This predicate matches the status quo, but there's no reason + // indexing cannot run for actions that do not require stdlib e.g. to better + // facilitate tests. + if (FrontendOptions::doesActionRequireSwiftStandardLibrary(action)) { + emitIndexData(Instance); + } + + // Emit dependencies. emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Instance); - emitIndexData(Instance); emitMakeDependenciesIfNeeded(Instance.getDiags(), Instance.getDependencyTracker(), opts); @@ -1747,39 +1707,190 @@ static void performEndOfPipelineActions(CompilerInstance &Instance) { emitCompiledSourceForAllPrimaryInputsIfNeeded(Instance); } -/// Performs the compile requested by the user. -/// \param Instance Will be reset after performIRGeneration when the verifier -/// mode is NoVerify and there were no errors. -/// \returns true on error -static bool performCompile(CompilerInvocation &Invok, - CompilerInstance &Instance, - ArrayRef Args, - int &ReturnValue, - FrontendObserver *observer) { +static bool printSwiftVersion(const CompilerInvocation &Invocation) { + llvm::outs() << version::getSwiftFullVersion( + version::Version::getCurrentLanguageVersion()) + << '\n'; + llvm::outs() << "Target: " << Invocation.getLangOptions().Target.str() + << '\n'; + return false; +} + +static bool +withSemanticAnalysis(CompilerInstance &Instance, FrontendObserver *observer, + llvm::function_ref cont) { const auto &Invocation = Instance.getInvocation(); const auto &opts = Invocation.getFrontendOptions(); - const FrontendOptions::ActionType Action = opts.RequestedAction; + assert(!FrontendOptions::shouldActionOnlyParse(opts.RequestedAction) && + "Action may only parse, but has requested semantic analysis!"); + + Instance.performSema(); + if (observer) + observer->performedSemanticAnalysis(Instance); + + switch (opts.CrashMode) { + case FrontendOptions::DebugCrashMode::AssertAfterParse: + debugFailWithAssertion(); + return true; + case FrontendOptions::DebugCrashMode::CrashAfterParse: + debugFailWithCrash(); + return true; + case FrontendOptions::DebugCrashMode::None: + break; + } + (void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance); + + if (Instance.getASTContext().hadError()) + return true; + + return cont(Instance); +} + +static bool performScanDependencies(CompilerInstance &Instance) { + auto batchScanInput = + Instance.getASTContext().SearchPathOpts.BatchScanInputFilePath; + if (batchScanInput.empty()) { + return scanDependencies(Instance); + } else { + return batchScanModuleDependencies(Instance, batchScanInput); + } +} + +static bool performParseOnly(ModuleDecl &MainModule) { + // A -parse invocation only cares about the side effects of parsing, so + // force the parsing of all the source files. + for (auto *file : MainModule.getFiles()) { + if (auto *SF = dyn_cast(file)) + (void)SF->getTopLevelDecls(); + } + return MainModule.getASTContext().hadError(); +} + +static bool performAction(CompilerInstance &Instance, + int &ReturnValue, + FrontendObserver *observer) { + const auto &opts = Instance.getInvocation().getFrontendOptions(); + auto &Context = Instance.getASTContext(); + switch (Instance.getInvocation().getFrontendOptions().RequestedAction) { + // MARK: Trivial Actions + case FrontendOptions::ActionType::NoneAction: + return Context.hadError(); + case FrontendOptions::ActionType::PrintVersion: + return printSwiftVersion(Instance.getInvocation()); + case FrontendOptions::ActionType::REPL: + llvm::report_fatal_error("Compiler-internal integrated REPL has been " + "removed; use the LLDB-enhanced REPL instead."); + + // MARK: Actions for Clang and Clang Modules // We've been asked to precompile a bridging header or module; we want to // avoid touching any other inputs and just parse, emit and exit. - if (Action == FrontendOptions::ActionType::EmitPCH) + case FrontendOptions::ActionType::EmitPCH: return precompileBridgingHeader(Instance); - if (Action == FrontendOptions::ActionType::EmitPCM) + case FrontendOptions::ActionType::EmitPCM: return precompileClangModule(Instance); - if (Action == FrontendOptions::ActionType::DumpPCM) + case FrontendOptions::ActionType::DumpPCM: return dumpPrecompiledClangModule(Instance); - if (Action == FrontendOptions::ActionType::PrintVersion) { - llvm::outs() << version::getSwiftFullVersion( - version::Version::getCurrentLanguageVersion()) << '\n'; - llvm::outs() << "Target: " - << Invocation.getLangOptions().Target.str() << '\n'; - return false; - } - if (Action == FrontendOptions::ActionType::CompileModuleFromInterface || - Action == FrontendOptions::ActionType::TypecheckModuleFromInterface) + + // MARK: Module Interface Actions + case FrontendOptions::ActionType::CompileModuleFromInterface: + case FrontendOptions::ActionType::TypecheckModuleFromInterface: return buildModuleFromInterface(Instance); - if (Invocation.getInputKind() == InputFileKind::LLVM) + // MARK: Actions that Dump + case FrontendOptions::ActionType::DumpParse: + return dumpAST(Instance); + case FrontendOptions::ActionType::DumpAST: { + // FIXME: -dump-ast expects to be able to write output even if type checking + // fails which does not cleanly fit the model \c withSemanticAnalysis is + // trying to impose. Once there is a request for the "semantic AST", this + // point is moot. + Instance.performSema(); + return dumpAST(Instance); + } + case FrontendOptions::ActionType::PrintAST: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + getPrimaryOrMainSourceFile(Instance)->print( + llvm::outs(), PrintOptions::printEverything()); + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::DumpScopeMaps: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + return dumpAndPrintScopeMap(Instance, + getPrimaryOrMainSourceFile(Instance)); + }); + case FrontendOptions::ActionType::DumpTypeRefinementContexts: + return withSemanticAnalysis( + Instance, observer, [](CompilerInstance &Instance) { + getPrimaryOrMainSourceFile(Instance) + ->getTypeRefinementContext() + ->dump(llvm::errs(), Instance.getASTContext().SourceMgr); + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::DumpInterfaceHash: + getPrimaryOrMainSourceFile(Instance)->dumpInterfaceHash(llvm::errs()); + return Context.hadError(); + case FrontendOptions::ActionType::EmitSyntax: + return emitSyntax(getPrimaryOrMainSourceFile(Instance), + opts.InputsAndOutputs.getSingleOutputFilename()); + case FrontendOptions::ActionType::EmitImportedModules: + return emitImportedModules(Instance.getMainModule(), opts); + + // MARK: Dependency Scanning Actions + case FrontendOptions::ActionType::ScanDependencies: + return performScanDependencies(Instance); + case FrontendOptions::ActionType::ScanClangDependencies: + return scanClangDependencies(Instance); + + // MARK: General Compilation Actions + case FrontendOptions::ActionType::Parse: + return performParseOnly(*Instance.getMainModule()); + case FrontendOptions::ActionType::ResolveImports: + return Instance.performParseAndResolveImportsOnly(); + case FrontendOptions::ActionType::Typecheck: + return withSemanticAnalysis(Instance, observer, + [](CompilerInstance &Instance) { + return Instance.getASTContext().hadError(); + }); + case FrontendOptions::ActionType::EmitSILGen: + case FrontendOptions::ActionType::EmitSIBGen: + case FrontendOptions::ActionType::EmitSIL: + case FrontendOptions::ActionType::EmitSIB: + case FrontendOptions::ActionType::EmitModuleOnly: + case FrontendOptions::ActionType::MergeModules: + case FrontendOptions::ActionType::Immediate: + case FrontendOptions::ActionType::EmitAssembly: + case FrontendOptions::ActionType::EmitIR: + case FrontendOptions::ActionType::EmitBC: + case FrontendOptions::ActionType::EmitObject: + case FrontendOptions::ActionType::DumpTypeInfo: + return withSemanticAnalysis( + Instance, observer, [&](CompilerInstance &Instance) { + assert(FrontendOptions::doesActionGenerateSIL(opts.RequestedAction) && + "All actions not requiring SILGen must have been handled!"); + return performCompileStepsPostSema(Instance, ReturnValue, observer); + }); + } + + assert(false && "Unhandled case in performCompile!"); + return Context.hadError(); +} + +/// Performs the compile requested by the user. +/// \param Instance Will be reset after performIRGeneration when the verifier +/// mode is NoVerify and there were no errors. +/// \returns true on error +static bool performCompile(CompilerInstance &Instance, + int &ReturnValue, + FrontendObserver *observer) { + const auto &Invocation = Instance.getInvocation(); + const auto &opts = Invocation.getFrontendOptions(); + const FrontendOptions::ActionType Action = opts.RequestedAction; + + // To compile LLVM IR, just pass it off unmodified. + if (Instance.getInvocation().getInputKind() == InputFileKind::LLVM) return compileLLVMIR(Instance); // If we aren't in a parse-only context and expect an implicit stdlib import, @@ -1788,100 +1899,33 @@ static bool performCompile(CompilerInvocation &Invok, // trigger a bunch of other errors due to the stdlib being missing, or at // worst crash downstream as many call sites don't currently handle a missing // stdlib. - if (!FrontendOptions::shouldActionOnlyParse(Action)) { + if (FrontendOptions::doesActionRequireSwiftStandardLibrary(Action)) { if (Instance.loadStdlibIfNeeded()) return true; } - bool didFinishPipeline = false; - SWIFT_DEFER { - assert(didFinishPipeline && "Returned without calling finishPipeline"); - }; - - auto finishPipeline = [&](bool hadError) -> bool { - // We might have freed the ASTContext already, but in that case we would - // have already performed these actions. - if (Instance.hasASTContext()) { - performEndOfPipelineActions(Instance); - hadError |= Instance.getASTContext().hadError(); + assert([&]() -> bool { + if (FrontendOptions::shouldActionOnlyParse(Action)) { + // Parsing gets triggered lazily, but let's make sure we have the right + // input kind. + auto kind = Invocation.getInputKind(); + return kind == InputFileKind::Swift || + kind == InputFileKind::SwiftLibrary || + kind == InputFileKind::SwiftModuleInterface; } - didFinishPipeline = true; - return hadError; - }; - - auto &Context = Instance.getASTContext(); - if (FrontendOptions::shouldActionOnlyParse(Action)) { - // Parsing gets triggered lazily, but let's make sure we have the right - // input kind. - auto kind = Invocation.getInputKind(); - assert((kind == InputFileKind::Swift || - kind == InputFileKind::SwiftLibrary || - kind == InputFileKind::SwiftModuleInterface) && - "Only supports parsing .swift files"); - (void)kind; - } else if (Action == FrontendOptions::ActionType::ResolveImports) { - Instance.performParseAndResolveImportsOnly(); - return finishPipeline(Context.hadError()); - } else { - Instance.performSema(); - } - - if (Action == FrontendOptions::ActionType::Parse) { - // A -parse invocation only cares about the side effects of parsing, so - // force the parsing of all the source files. - for (auto *file : Instance.getMainModule()->getFiles()) { - if (auto *SF = dyn_cast(file)) - (void)SF->getTopLevelDecls(); - } - return finishPipeline(Context.hadError()); - } - - if (Action == FrontendOptions::ActionType::ScanDependencies) { - auto batchScanInput = Instance.getASTContext().SearchPathOpts.BatchScanInputFilePath; - if (batchScanInput.empty()) - return finishPipeline(scanDependencies(Instance)); - else - return finishPipeline(batchScanModuleDependencies(Invok, - Instance, - batchScanInput)); - } - - if (Action == FrontendOptions::ActionType::ScanClangDependencies) - return finishPipeline(scanClangDependencies(Instance)); - - if (observer) - observer->performedSemanticAnalysis(Instance); - - { - FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode; - if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse) - debugFailWithAssertion(); - else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse) - debugFailWithCrash(); - } + return true; + }() && "Only supports parsing .swift files"); - (void)migrator::updateCodeAndEmitRemapIfNeeded(&Instance); + bool hadError = performAction(Instance, ReturnValue, observer); - if (Action == FrontendOptions::ActionType::REPL) { - llvm::report_fatal_error("Compiler-internal integrated REPL has been " - "removed; use the LLDB-enhanced REPL instead."); + // We might have freed the ASTContext already, but in that case we would + // have already performed these actions. + if (Instance.hasASTContext() && + FrontendOptions::doesActionRequireInputs(Action)) { + performEndOfPipelineActions(Instance); + hadError |= Instance.getASTContext().hadError(); } - - if (auto r = dumpASTIfNeeded(Instance)) - return finishPipeline(*r); - - if (Context.hadError()) - return finishPipeline(/*hadError*/ true); - - // We've just been told to perform a typecheck, so we can return now. - if (Action == FrontendOptions::ActionType::Typecheck) - return finishPipeline(/*hadError*/ false); - - assert(FrontendOptions::doesActionGenerateSIL(Action) && - "All actions not requiring SILGen must have been handled!"); - - return finishPipeline( - performCompileStepsPostSema(Instance, ReturnValue, observer)); + return hadError; } static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs, @@ -2655,7 +2699,7 @@ int swift::performFrontend(ArrayRef Args, } int ReturnValue = 0; - bool HadError = performCompile(Invocation, *Instance, Args, ReturnValue, observer); + bool HadError = performCompile(*Instance, ReturnValue, observer); if (verifierEnabled) { DiagnosticEngine &diags = Instance->getDiags(); diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp index 90a33895ee52a..d750417737264 100644 --- a/lib/FrontendTool/ImportedModules.cpp +++ b/lib/FrontendTool/ImportedModules.cpp @@ -42,9 +42,9 @@ static void findAllClangImports(const clang::Module *module, } } -bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, +bool swift::emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts) { - + auto &Context = mainModule->getASTContext(); std::string path = opts.InputsAndOutputs.getSingleOutputFilename(); std::error_code EC; llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); diff --git a/lib/FrontendTool/ImportedModules.h b/lib/FrontendTool/ImportedModules.h index 42b4e76babaf4..510fa4ccdedde 100644 --- a/lib/FrontendTool/ImportedModules.h +++ b/lib/FrontendTool/ImportedModules.h @@ -20,8 +20,7 @@ class FrontendOptions; class ModuleDecl; /// Emit the names of the modules imported by \c mainModule. -bool emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, - const FrontendOptions &opts); +bool emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts); } // end namespace swift #endif diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index fb0cd4b47a0bc..34e99395e1b17 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -690,9 +690,10 @@ bool swift::scanClangDependencies(CompilerInstance &instance) { .InputsAndOutputs.getSingleOutputFilename()); } -bool swift::batchScanModuleDependencies(CompilerInvocation &invok, - CompilerInstance &instance, +bool swift::batchScanModuleDependencies(CompilerInstance &instance, llvm::StringRef batchInputFile) { + const CompilerInvocation &invok = instance.getInvocation(); + (void)instance.getMainModule(); llvm::BumpPtrAllocator alloc; llvm::StringSaver saver(alloc); diff --git a/lib/FrontendTool/ScanDependencies.h b/lib/FrontendTool/ScanDependencies.h index 4604496ba66dc..fab7d26bbb190 100644 --- a/lib/FrontendTool/ScanDependencies.h +++ b/lib/FrontendTool/ScanDependencies.h @@ -21,8 +21,7 @@ class CompilerInvocation; class CompilerInstance; /// Batch scan the dependencies for modules specified in \c batchInputFile. -bool batchScanModuleDependencies(CompilerInvocation &invok, - CompilerInstance &instance, +bool batchScanModuleDependencies(CompilerInstance &instance, llvm::StringRef batchInputFile); /// Scans the dependencies of the main module of \c instance. diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index 7348c057ef63a..d028e874d39b7 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -7,6 +7,7 @@ add_swift_host_library(swiftIDE STATIC ConformingMethodList.cpp ExprContextAnalysis.cpp Formatting.cpp + FuzzyStringMatcher.cpp Refactoring.cpp ModuleInterfacePrinting.cpp REPLCodeCompletion.cpp @@ -21,6 +22,7 @@ add_swift_host_library(swiftIDE STATIC target_link_libraries(swiftIDE PRIVATE swiftAST swiftClangImporter + swiftDriver swiftFrontend swiftIndex swiftParse diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 2df72d50d66d8..e4534b65e195f 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -4290,14 +4290,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (!T->mayHaveMembers()) return; - DeclContext *DC = const_cast(CurrDeclContext); - // We can only say .foo where foo is a static member of the contextual // type and has the same type (or if the member is a function, then the // same result type) as the contextual type. FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind Reason) { - return isReferenceableByImplicitMemberExpr(CurrModule, DC, T, VD); + if (T->getOptionalObjectType() && + VD->getModuleContext()->isStdlibModule()) { + // In optional context, ignore '.init()', 'init(nilLiteral:)', + if (isa(VD)) + return false; + } + return true; }); auto baseType = MetatypeType::get(T); diff --git a/lib/IDE/CodeCompletionResultPrinter.cpp b/lib/IDE/CodeCompletionResultPrinter.cpp index e5c9986ab1fde..7b61aa1835153 100644 --- a/lib/IDE/CodeCompletionResultPrinter.cpp +++ b/lib/IDE/CodeCompletionResultPrinter.cpp @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/LLVM.h" #include "swift/IDE/CodeCompletionResultPrinter.h" +#include "swift/AST/ASTPrinter.h" +#include "swift/Basic/LLVM.h" #include "swift/IDE/CodeCompletion.h" #include "swift/Markup/XMLUtils.h" #include "llvm/Support/raw_ostream.h" @@ -255,3 +256,186 @@ void swift::ide::printCodeCompletionResultTypeNameAnnotated(const CodeCompletion AnnotatingResultPrinter printer(OS); printer.printTypeName(Result); } + +/// Provide the text for the call parameter, including constructing a typed +/// editor placeholder for it. +static void +constructTextForCallParam(ArrayRef ParamGroup, + raw_ostream &OS) { + assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); + + for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { + auto &C = ParamGroup.front(); + if (C.isAnnotation()) + continue; + if (C.is(ChunkKind::CallParameterInternalName) || + C.is(ChunkKind::CallParameterType) || + C.is(ChunkKind::CallParameterTypeBegin) || + C.is(ChunkKind::CallParameterClosureExpr)) { + break; + } + if (!C.hasText()) + continue; + OS << C.getText(); + } + + SmallString<32> DisplayString; + SmallString<32> TypeString; + SmallString<32> ExpansionTypeString; + + for (auto i = ParamGroup.begin(), e = ParamGroup.end(); i != e; ++i) { + auto &C = *i; + if (C.is(ChunkKind::CallParameterTypeBegin)) { + assert(TypeString.empty()); + auto nestingLevel = C.getNestingLevel(); + ++i; + for (; i != e; ++i) { + if (i->endsPreviousNestedGroup(nestingLevel)) + break; + if (!i->isAnnotation() && i->hasText()) { + TypeString += i->getText(); + DisplayString += i->getText(); + } + } + --i; + continue; + } + if (C.is(ChunkKind::CallParameterClosureType)) { + assert(ExpansionTypeString.empty()); + ExpansionTypeString = C.getText(); + continue; + } + if (C.is(ChunkKind::CallParameterType)) { + assert(TypeString.empty()); + TypeString = C.getText(); + } + if (C.is(ChunkKind::CallParameterClosureExpr)) { + // We have a closure expression, so provide it directly instead of in + // a placeholder. + OS << "{"; + if (!C.getText().empty()) + OS << " " << C.getText(); + OS << "\n" << getCodePlaceholder() << "\n}"; + return; + } + if (C.isAnnotation() || !C.hasText()) + continue; + DisplayString += C.getText(); + } + + StringRef Display = DisplayString.str(); + StringRef Type = TypeString.str(); + StringRef ExpansionType = ExpansionTypeString.str(); + if (ExpansionType.empty()) + ExpansionType = Type; + + OS << "<#T##" << Display; + if (Display == Type && Display == ExpansionType) { + // Short version, display and type are the same. + } else { + OS << "##" << Type; + if (ExpansionType != Type) + OS << "##" << ExpansionType; + } + OS << "#>"; +} + +void swift::ide::printCodeCompletionResultSourceText( + const CodeCompletionResult &Result, llvm::raw_ostream &OS) { + auto Chunks = Result.getCompletionString()->getChunks(); + for (size_t i = 0; i < Chunks.size(); ++i) { + auto &C = Chunks[i]; + if (C.is(ChunkKind::BraceStmtWithCursor)) { + OS << " {\n" << getCodePlaceholder() << "\n}"; + continue; + } + if (C.is(ChunkKind::CallParameterBegin)) { + size_t Start = i++; + for (; i < Chunks.size(); ++i) { + if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) + break; + } + constructTextForCallParam(Chunks.slice(Start, i - Start), OS); + --i; + continue; + } + if (C.is(ChunkKind::TypeAnnotationBegin)) { + // Skip type annotation structure. + auto level = C.getNestingLevel(); + do { + ++i; + } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); + --i; + } + if (!C.isAnnotation() && C.hasText()) { + OS << C.getText(); + } + } +} + +void swift::ide::printCodeCompletionResultFilterName( + const CodeCompletionResult &Result, llvm::raw_ostream &OS) { + auto str = Result.getCompletionString(); + // FIXME: we need a more uniform way to handle operator completions. + if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { + OS << "."; + return; + } else if (str->getChunks().size() == 2 && + str->getChunks()[0].is(ChunkKind::QuestionMark) && + str->getChunks()[1].is(ChunkKind::Dot)) { + OS << "?."; + return; + } + + auto FirstTextChunk = str->getFirstTextChunkIndex(); + if (FirstTextChunk.hasValue()) { + auto chunks = str->getChunks().slice(*FirstTextChunk); + for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) { + auto &C = *i; + + if (C.is(ChunkKind::BraceStmtWithCursor)) + break; // Don't include brace-stmt in filter name. + + if (C.is(ChunkKind::Equal)) { + OS << C.getText(); + break; + } + + bool shouldPrint = !C.isAnnotation(); + switch (C.getKind()) { + case ChunkKind::TypeAnnotation: + case ChunkKind::CallParameterInternalName: + case ChunkKind::CallParameterClosureType: + case ChunkKind::CallParameterClosureExpr: + case ChunkKind::CallParameterType: + case ChunkKind::DeclAttrParamColon: + case ChunkKind::Comma: + case ChunkKind::Whitespace: + case ChunkKind::Ellipsis: + case ChunkKind::Ampersand: + case ChunkKind::OptionalMethodCallTail: + continue; + case ChunkKind::CallParameterTypeBegin: + case ChunkKind::TypeAnnotationBegin: { + // Skip call parameter type or type annotation structure. + auto nestingLevel = C.getNestingLevel(); + do { + ++i; + } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); + --i; + continue; + } + case ChunkKind::CallParameterColon: + // Since we don't add the type, also don't add the space after ':'. + if (shouldPrint) + OS << ":"; + continue; + default: + break; + } + + if (C.hasText() && shouldPrint) + OS << C.getText(); + } + } +} diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 2f8a6cd7040b5..1aeffb3304356 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -485,8 +485,6 @@ bool CompletionInstance::performCachedOperationIfPossible( } CachedReuseCount += 1; - cacheDependencyHashIfNeeded(CI, SM.getCodeCompletionBufferID(), - InMemoryDependencyHash); return true; } diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 787606e321891..96f0b2126ce09 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -46,9 +46,11 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { while (isa(DC)) DC = DC->getParent(); - // Make sure the extension has been bound, in case it is in an inactive #if - // or something weird like that. + // Make sure the extension has been bound. { + // Even if the extension is invalid (e.g. nested in a function or another + // type), we want to know the "intended nominal" of the extension so that + // we can know the type of 'Self'. SmallVector extensions; for (auto typeCtx = DC->getInnermostTypeContext(); typeCtx != nullptr; typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { @@ -59,6 +61,20 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { extensions.back()->computeExtendedNominal(); extensions.pop_back(); } + + // If the completion happens in the inheritance clause of the extension, + // 'DC' is the parent of the extension. We need to iterate the top level + // decls to find it. In theory, we don't need the extended nominal in the + // inheritance clause, but ASTScope lookup requires that. We don't care + // unless 'DC' is not 'SourceFile' because non-toplevel extensions are + // 'canNeverBeBound()' anyway. + if (auto *SF = dyn_cast(DC)) { + auto &SM = DC->getASTContext().SourceMgr; + for (auto *decl : SF->getTopLevelDecls()) + if (auto *ext = dyn_cast(decl)) + if (SM.rangeContainsTokenLoc(ext->getSourceRange(), Loc)) + ext->computeExtendedNominal(); + } } // Type-check this context. @@ -85,6 +101,11 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { typeCheckPatternBinding(PBD, i); } } + } else if (auto *defaultArg = dyn_cast(DC)) { + if (auto *AFD = dyn_cast(defaultArg->getParent())) { + auto *Param = AFD->getParameters()->get(defaultArg->getIndex()); + (void*)Param->getTypeCheckedDefaultExpr(); + } } break; @@ -558,6 +579,31 @@ static void collectPossibleCalleesByQualifiedLookup( } } +/// For the given \p unresolvedMemberExpr, collect possible callee types and +/// declarations. +static bool collectPossibleCalleesForUnresolvedMember( + DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, + SmallVectorImpl &candidates) { + auto collectMembers = [&](Type expectedTy) { + if (!expectedTy->mayHaveMembers()) + return; + collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), + unresolvedMemberExpr->getName(), + candidates); + }; + + // Get the context of the expression itself. + ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); + for (auto expectedTy : contextInfo.getPossibleTypes()) { + collectMembers(expectedTy); + // If this is an optional type, let's also check its base type. + if (auto baseTy = expectedTy->getOptionalObjectType()) { + collectMembers(baseTy->lookThroughAllOptionalTypes()); + } + } + return !candidates.empty(); +} + /// For the given \c callExpr, collect possible callee types and declarations. static bool collectPossibleCalleesForApply( DeclContext &DC, ApplyExpr *callExpr, @@ -599,6 +645,8 @@ static bool collectPossibleCalleesForApply( } else if (auto CRCE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( DC, CRCE->getArg(), DeclNameRef::createConstructor(), candidates); + } else if (auto *UME = dyn_cast(fnExpr)) { + collectPossibleCalleesForUnresolvedMember(DC, UME, candidates); } if (!candidates.empty()) @@ -662,39 +710,6 @@ static bool collectPossibleCalleesForSubscript( return !candidates.empty(); } -/// For the given \p unresolvedMemberExpr, collect possible callee types and -/// declarations. -static bool collectPossibleCalleesForUnresolvedMember( - DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, - SmallVectorImpl &candidates) { - auto currModule = DC.getParentModule(); - - auto collectMembers = [&](Type expectedTy) { - if (!expectedTy->mayHaveMembers()) - return; - SmallVector members; - collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), - unresolvedMemberExpr->getName(), - members); - for (auto member : members) { - if (isReferenceableByImplicitMemberExpr(currModule, &DC, expectedTy, - member.Decl)) - candidates.push_back(member); - } - }; - - // Get the context of the expression itself. - ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); - for (auto expectedTy : contextInfo.getPossibleTypes()) { - collectMembers(expectedTy); - // If this is an optional type, let's also check its base type. - if (auto baseTy = expectedTy->getOptionalObjectType()) { - collectMembers(baseTy->lookThroughAllOptionalTypes()); - } - } - return !candidates.empty(); -} - /// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr /// or \c ParenExpr. /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. @@ -761,11 +776,6 @@ class ExprContextAnalyzer { if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates)) return false; Arg = subscriptExpr->getIndex(); - } else if (auto *unresolvedMemberExpr = dyn_cast(E)) { - if (!collectPossibleCalleesForUnresolvedMember(*DC, unresolvedMemberExpr, - Candidates)) - return false; - Arg = unresolvedMemberExpr->getArgument(); } else { llvm_unreachable("unexpected expression kind"); } @@ -840,7 +850,6 @@ class ExprContextAnalyzer { switch (Parent->getKind()) { case ExprKind::Call: case ExprKind::Subscript: - case ExprKind::UnresolvedMember: case ExprKind::Binary: case ExprKind::PrefixUnary: { analyzeApplyExpr(Parent); @@ -848,8 +857,10 @@ class ExprContextAnalyzer { } case ExprKind::Array: { if (auto type = ParsedExpr->getType()) { - recordPossibleType(type); - break; + if (!type->is()) { + recordPossibleType(type); + break; + } } // Check context types of the array literal expression. @@ -1144,7 +1155,6 @@ class ExprContextAnalyzer { case ExprKind::Assign: case ExprKind::Dictionary: case ExprKind::If: - case ExprKind::UnresolvedMember: return true; case ExprKind::Array: return (!Parent.getAsExpr() || @@ -1153,8 +1163,7 @@ class ExprContextAnalyzer { auto ParentE = Parent.getAsExpr(); return !ParentE || (!isa(ParentE) && !isa(ParentE) && - !isa(ParentE) && - !isa(ParentE)); + !isa(ParentE)); } case ExprKind::Closure: return isSingleExpressionBodyForCodeCompletion( @@ -1228,73 +1237,3 @@ ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) { singleExpressionBody); Analyzer.Analyze(); } - -//===----------------------------------------------------------------------===// -// isReferenceableByImplicitMemberExpr(ModuleD, DeclContext, Type, ValueDecl) -//===----------------------------------------------------------------------===// - -bool swift::ide::isReferenceableByImplicitMemberExpr( - ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD) { - - if (VD->isOperator()) - return false; - - if (T->getOptionalObjectType() && - VD->getModuleContext()->isStdlibModule()) { - // In optional context, ignore '.init()', 'init(nilLiteral:)', - if (isa(VD)) - return false; - // TODO: Ignore '.some()' and '.none' too *in expression - // context*. They are useful in pattern context though. - } - - // Enum element decls can always be referenced by implicit member - // expression. - if (isa(VD)) - return true; - - // Only non-failable constructors are implicitly referenceable. - if (auto CD = dyn_cast(VD)) { - return (!CD->isFailable() || CD->isImplicitlyUnwrappedOptional()); - } - - // Otherwise, check the result type matches the contextual type. - auto declTy = T->getTypeOfMember(CurrModule, VD); - if (declTy->is()) - return false; - - // Member types can also be implicitly referenceable as long as it's - // convertible to the contextual type. - if (auto CD = dyn_cast(VD)) { - declTy = declTy->getMetatypeInstanceType(); - - // Emit construction for the same type via typealias doesn't make sense - // because we are emitting all `.init()`s. - if (declTy->isEqual(T)) - return false; - - // Only non-protocol nominal type can be instantiated. - auto nominal = declTy->getAnyNominal(); - if (!nominal || isa(nominal)) - return false; - - return swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC); - } - - // Only static member can be referenced. - if (!VD->isStatic()) - return false; - - if (isa(VD)) { - // Strip '(Self.Type) ->' and parameters. - declTy = declTy->castTo()->getResult(); - declTy = declTy->castTo()->getResult(); - } else if (auto FT = declTy->getAs()) { - // The compiler accepts 'static var factory: () -> T' for implicit - // member expression. - // FIXME: This emits just 'factory'. We should emit 'factory()' instead. - declTy = FT->getResult(); - } - return declTy->isEqual(T) || - swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC); -} diff --git a/lib/IDE/ExprContextAnalysis.h b/lib/IDE/ExprContextAnalysis.h index 1e0b749ac065c..9c957353b68e0 100644 --- a/lib/IDE/ExprContextAnalysis.h +++ b/lib/IDE/ExprContextAnalysis.h @@ -114,10 +114,6 @@ class ExprContextInfo { } }; -/// Returns whether \p VD is referenceable with implicit member expression. -bool isReferenceableByImplicitMemberExpr( - ModuleDecl *CurrModule, DeclContext *DC, Type T, ValueDecl *VD); - } // namespace ide } // namespace swift diff --git a/tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp b/lib/IDE/FuzzyStringMatcher.cpp similarity index 99% rename from tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp rename to lib/IDE/FuzzyStringMatcher.cpp index 463d541d0d850..d016464691f19 100644 --- a/tools/SourceKit/lib/Support/FuzzyStringMatcher.cpp +++ b/lib/IDE/FuzzyStringMatcher.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 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 @@ -10,12 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "SourceKit/Support/FuzzyStringMatcher.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" -using namespace SourceKit; +using namespace swift; +using namespace swift::ide; using clang::toUppercase; using clang::toLowercase; using clang::isUppercase; diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index 6f6f08e9daf27..dd494e03cad25 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -715,6 +715,12 @@ passReference(ValueDecl *D, Type Ty, SourceLoc BaseNameLoc, SourceRange Range, } } + if (D == nullptr) { + // FIXME: When does this happen? + assert(false && "unhandled reference"); + return true; + } + CharSourceRange CharRange = Lexer::getCharSourceRangeFromSourceRange(D->getASTContext().SourceMgr, Range); diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index b372b1cba3e39..6f44a3078ac63 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -282,10 +282,6 @@ Stmt *NameMatcher::walkToStmtPost(Stmt *S) { } Expr *NameMatcher::getApplicableArgFor(Expr *E) { - if (auto *UME = dyn_cast(E)) { - if (auto *Arg = UME->getArgument()) - return Arg; - } if (ParentCalls.empty()) return nullptr; auto &Last = ParentCalls.back(); diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 616a0e6e0678f..7db3ed0288c7d 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -14,6 +14,7 @@ #include "swift/Basic/Edit.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangModule.h" +#include "swift/Driver/FrontendUtil.h" #include "swift/Frontend/Frontend.h" #include "swift/Parse/Parser.h" #include "swift/Subsystems.h" @@ -188,6 +189,196 @@ ide::isSourceInputComplete(StringRef Text,SourceFileKind SFKind) { SFKind); } +static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( + FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + std::string &Error) { + assert(FileSystem); + + llvm::SmallString<128> PrimaryFile; + if (auto err = FileSystem->getRealPath(UnresolvedPrimaryFile, PrimaryFile)) + PrimaryFile = UnresolvedPrimaryFile; + + unsigned primaryCount = 0; + // FIXME: The frontend should be dealing with symlinks, maybe similar to + // clang's FileManager ? + FrontendInputsAndOutputs replacementInputsAndOutputs; + for (const InputFile &input : inputsAndOutputs.getAllInputs()) { + llvm::SmallString<128> newFilename; + if (auto err = FileSystem->getRealPath(input.file(), newFilename)) + newFilename = input.file(); + llvm::sys::path::native(newFilename); + bool newIsPrimary = input.isPrimary() || + (!PrimaryFile.empty() && PrimaryFile == newFilename); + if (newIsPrimary) { + ++primaryCount; + } + assert(primaryCount < 2 && "cannot handle multiple primaries"); + replacementInputsAndOutputs.addInput( + InputFile(newFilename.str(), newIsPrimary, input.buffer())); + } + + if (PrimaryFile.empty() || primaryCount == 1) { + return replacementInputsAndOutputs; + } + + llvm::SmallString<64> Err; + llvm::raw_svector_ostream OS(Err); + OS << "'" << PrimaryFile << "' is not part of the input files"; + Error = std::string(OS.str()); + return replacementInputsAndOutputs; +} + +static void disableExpensiveSILOptions(SILOptions &Opts) { + // Disable the sanitizers. + Opts.Sanitizers = {}; + + // Disable PGO and code coverage. + Opts.GenerateProfile = false; + Opts.EmitProfileCoverageMapping = false; + Opts.UseProfile = ""; +} + +namespace { +class StreamDiagConsumer : public DiagnosticConsumer { + llvm::raw_ostream &OS; + +public: + StreamDiagConsumer(llvm::raw_ostream &OS) : OS(OS) {} + + void handleDiagnostic(SourceManager &SM, + const DiagnosticInfo &Info) override { + // FIXME: Print location info if available. + switch (Info.Kind) { + case DiagnosticKind::Error: + OS << "error: "; + break; + case DiagnosticKind::Warning: + OS << "warning: "; + break; + case DiagnosticKind::Note: + OS << "note: "; + break; + case DiagnosticKind::Remark: + OS << "remark: "; + break; + } + DiagnosticEngine::formatDiagnosticText(OS, Info.FormatString, + Info.FormatArgs); + } +}; +} // end anonymous namespace + +bool ide::initCompilerInvocation( + CompilerInvocation &Invocation, ArrayRef OrigArgs, + DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, + llvm::IntrusiveRefCntPtr FileSystem, + // SWIFT_ENABLE_TENSORFLOW + llvm::IntrusiveRefCntPtr InMemoryOutputFileSystem, + // SWIFT_ENABLE_TENSORFLOW END + const std::string &runtimeResourcePath, + const std::string &diagnosticDocumentationPath, + bool shouldOptimizeForIDE, time_t sessionTimestamp, std::string &Error) { + SmallVector Args; + // Make sure to put '-resource-dir' and '-diagnostic-documentation-path' at + // the top to allow overriding them with the passed in arguments. + Args.push_back("-resource-dir"); + Args.push_back(runtimeResourcePath.c_str()); + Args.push_back("-Xfrontend"); + Args.push_back("-diagnostic-documentation-path"); + Args.push_back("-Xfrontend"); + Args.push_back(diagnosticDocumentationPath.c_str()); + Args.append(OrigArgs.begin(), OrigArgs.end()); + + SmallString<32> ErrStr; + llvm::raw_svector_ostream ErrOS(ErrStr); + StreamDiagConsumer DiagConsumer(ErrOS); + Diags.addConsumer(DiagConsumer); + + bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( + Args, Diags, [&](ArrayRef FrontendArgs) { + return Invocation.parseArgs(FrontendArgs, Diags); + }, /*ForceNoOutputs=*/true); + + // Remove the StreamDiagConsumer as it's no longer needed. + Diags.removeConsumer(DiagConsumer); + + if (HadError) { + Error = std::string(ErrOS.str()); + return true; + } + + Invocation.getFrontendOptions().InputsAndOutputs = + resolveSymbolicLinksInInputs( + Invocation.getFrontendOptions().InputsAndOutputs, + UnresolvedPrimaryFile, FileSystem, Error); + if (!Error.empty()) + return true; + + ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions(); + ImporterOpts.DetailedPreprocessingRecord = true; + // SWIFT_ENABLE_TENSORFLOW + ImporterOpts.InMemoryOutputFileSystem = InMemoryOutputFileSystem; + // SWIFT_ENABLE_TENSORFLOW END + + assert(!Invocation.getModuleName().empty()); + + auto &LangOpts = Invocation.getLangOptions(); + LangOpts.AttachCommentsToDecls = true; + LangOpts.DiagnosticsEditorMode = true; + LangOpts.CollectParsedToken = true; + if (LangOpts.PlaygroundTransform) { + // The playground instrumenter changes the AST in ways that disrupt the + // SourceKit functionality. Since we don't need the instrumenter, and all we + // actually need is the playground semantics visible to the user, like + // silencing the "expression resolves to an unused l-value" error, disable it. + LangOpts.PlaygroundTransform = false; + } + + // Disable the index-store functionality for the sourcekitd requests. + auto &FrontendOpts = Invocation.getFrontendOptions(); + FrontendOpts.IndexStorePath.clear(); + ImporterOpts.IndexStorePath.clear(); + + // Force the action type to be -typecheck. This affects importing the + // SwiftONoneSupport module. + FrontendOpts.RequestedAction = FrontendOptions::ActionType::Typecheck; + + // We don't care about LLVMArgs + FrontendOpts.LLVMArgs.clear(); + + // SwiftSourceInfo files provide source location information for decls coming + // from loaded modules. For most IDE use cases it either has an undesirable + // impact on performance with no benefit (code completion), results in stale + // locations being used instead of more up-to-date indexer locations (cursor + // info), or has no observable effect (diagnostics, which are filtered to just + // those with a location in the primary file, and everything else). + if (shouldOptimizeForIDE) + FrontendOpts.IgnoreSwiftSourceInfo = true; + + // To save the time for module validation, consider the lifetime of ASTManager + // as a single build session. + // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* + // explicitly enabled. + auto &SearchPathOpts = Invocation.getSearchPathOptions(); + if (!SearchPathOpts.DisableModulesValidateSystemDependencies) { + // NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may + // cause unnecessary validations if they happens within one second + // from the SourceKit startup. + ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" + + std::to_string(sessionTimestamp - 1)); + ImporterOpts.ExtraArgs.push_back( + "-fmodules-validate-once-per-build-session"); + + SearchPathOpts.DisableModulesValidateSystemDependencies = true; + } + + // Disable expensive SIL options to reduce time spent in SILGen. + disableExpensiveSILOptions(Invocation.getSILOptions()); + + return false; +} + // Adjust the cc1 triple string we got from clang, to make sure it will be // accepted when it goes through the swift clang importer. static std::string adjustClangTriple(StringRef TripleStr) { diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index bc788fab6904a..8bc35dd99c134 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -132,10 +132,10 @@ namespace { /// ABI. class GenClangType : public CanTypeVisitor { IRGenModule &IGM; - ClangTypeConverter &Converter; + irgen::ClangTypeConverter &Converter; public: - GenClangType(IRGenModule &IGM, ClangTypeConverter &converter) + GenClangType(IRGenModule &IGM, irgen::ClangTypeConverter &converter) : IGM(IGM), Converter(converter) {} const clang::ASTContext &getClangASTContext() const { @@ -264,8 +264,8 @@ static clang::CanQualType getClangBuiltinTypeFromTypedef( } clang::CanQualType -ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, - CanStructType type) { +irgen::ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, + CanStructType type) { // Handle builtin types by adding entries to the cache that reverse // the mapping done by the importer. We could try to look at the // members of the struct instead, but even if that's ABI-equivalent @@ -748,7 +748,7 @@ clang::CanQualType GenClangType::visitType(CanType type) { llvm_unreachable("Unexpected type in Clang type generation."); } -clang::CanQualType ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { +clang::CanQualType irgen::ClangTypeConverter::convert(IRGenModule &IGM, CanType type) { // Look in the cache. auto it = Cache.find(type); if (it != Cache.end()) { diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 7d925563f8c2b..a47c2d5bef73d 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3941,32 +3941,14 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, return cast(addr); } - /// For concrete metadata, we want to use the initializer on the - /// "full metadata", and define the "direct" address point as an alias. - TypeMetadataAddress addrKind; - unsigned adjustmentIndex; - - auto nominal = concreteType->getAnyNominal(); - - // Native Swift class metadata has a destructor before the address point. - // Foreign class metadata candidates do not, and neither does value type - // metadata. - if (nominal && isa(nominal) && - !requiresForeignTypeMetadata(nominal)) { - addrKind = TypeMetadataAddress::FullMetadata; - adjustmentIndex = MetadataAdjustmentIndex::Class; - } else { - addrKind = TypeMetadataAddress::FullMetadata; - adjustmentIndex = MetadataAdjustmentIndex::ValueType; - } - auto entity = (isPrespecialized && !irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable( *this, concreteType)) ? LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata( concreteType) - : LinkEntity::forTypeMetadata(concreteType, addrKind); + : LinkEntity::forTypeMetadata(concreteType, + TypeMetadataAddress::FullMetadata); auto DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), entity.getDefaultDeclarationType(*this)->getPointerTo(), @@ -3984,30 +3966,35 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, if (link.isUsed()) addUsedGlobal(var); - // Keep type metadata around for all types. - if (nominal) + /// For concrete metadata, we want to use the initializer on the + /// "full metadata", and define the "direct" address point as an alias. + unsigned adjustmentIndex = MetadataAdjustmentIndex::ValueType; + + if (auto nominal = concreteType->getAnyNominal()) { + // Keep type metadata around for all types. addRuntimeResolvableType(nominal); - // Don't define the alias for foreign type metadata or prespecialized generic - // metadata, since neither is ABI. - if ((nominal && requiresForeignTypeMetadata(nominal)) || isPrespecialized) - return var; + // Don't define the alias for foreign type metadata or prespecialized + // generic metadata, since neither is ABI. + if (requiresForeignTypeMetadata(nominal) || isPrespecialized) + return var; - // For concrete metadata, declare the alias to its address point. - auto directEntity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::AddressPoint); + // Native Swift class metadata has a destructor before the address point. + if (isa(nominal)) { + adjustmentIndex = MetadataAdjustmentIndex::Class; + } + } - llvm::Constant *addr = var; - // Do an adjustment if necessary. - if (adjustmentIndex) { - llvm::Constant *indices[] = { + llvm::Constant *indices[] = { llvm::ConstantInt::get(Int32Ty, 0), - llvm::ConstantInt::get(Int32Ty, adjustmentIndex) - }; - addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, - addr, indices); - } + llvm::ConstantInt::get(Int32Ty, adjustmentIndex)}; + auto addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, var, + indices); addr = llvm::ConstantExpr::getBitCast(addr, TypeMetadataPtrTy); + + // For concrete metadata, declare the alias to its address point. + auto directEntity = LinkEntity::forTypeMetadata( + concreteType, TypeMetadataAddress::AddressPoint); return defineAlias(directEntity, addr); } @@ -4028,15 +4015,17 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, auto nominal = concreteType->getAnyNominal(); - llvm::Type *defaultVarTy; - unsigned adjustmentIndex; - bool foreign = nominal && requiresForeignTypeMetadata(nominal); + + // Foreign classes and prespecialized generic types do not use an alias into + // the full metadata and therefore require a GEP. bool fullMetadata = foreign || (concreteType->getAnyGeneric() && concreteType->getAnyGeneric()->isGenericContext()); - // Foreign classes reference the full metadata with a GEP. + llvm::Type *defaultVarTy; + unsigned adjustmentIndex; + if (fullMetadata) { defaultVarTy = FullTypeMetadataStructTy; if (concreteType->getClassOrBoundGenericClass() && !foreign) { @@ -4044,9 +4033,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, } else { adjustmentIndex = MetadataAdjustmentIndex::ValueType; } - // The symbol for other nominal type metadata is generated at the address - // point. } else if (nominal) { + // The symbol for native non-generic nominal type metadata is generated at + // the aliased address point (see defineTypeMetadata() above). assert(!nominal->hasClangNode()); defaultVarTy = TypeMetadataStructTy; @@ -4080,13 +4069,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, switch (canonicality) { case TypeMetadataCanonicality::Canonical: - if (fullMetadata) { - entity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::FullMetadata); - } else { - entity = LinkEntity::forTypeMetadata(concreteType, - TypeMetadataAddress::AddressPoint); - } + entity = LinkEntity::forTypeMetadata( + concreteType, fullMetadata ? TypeMetadataAddress::FullMetadata + : TypeMetadataAddress::AddressPoint); break; case TypeMetadataCanonicality::Noncanonical: entity = diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 6282e402545c8..2795553485a5a 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3056,7 +3056,7 @@ GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, // Construct a representative function type. auto generics = ncGenerics.getCanonicalSignature(); auto fnType = SILFunctionType::get(generics, SILFunctionType::ExtInfo(), - /*isAsync*/ false, SILCoroutineKind::None, + SILCoroutineKind::None, /*callee*/ ParameterConvention::Direct_Unowned, /*params*/ {}, /*yields*/ {}, /*results*/ {}, /*error*/ None, diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index e1cd39d903dde..65387d02719d7 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1571,6 +1571,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { case TypeKind::Unresolved: case TypeKind::LValue: case TypeKind::TypeVariable: + case TypeKind::Hole: case TypeKind::Module: case TypeKind::SILBlockStorage: case TypeKind::SILBox: diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 6d798d7ea8131..2a509cbfeeb89 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -297,7 +297,6 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env, auto newFnType = SILFunctionType::get( fnType->getInvocationGenericSignature(), fnType->getExtInfo(), - fnType->isAsync(), fnType->getCoroutineKind(), fnType->getCalleeConvention(), newParams, @@ -2362,7 +2361,6 @@ static bool rewriteFunctionReturn(StructLoweringState &pass) { auto NewTy = SILFunctionType::get( loweredTy->getSubstGenericSignature(), loweredTy->getExtInfo(), - loweredTy->isAsync(), loweredTy->getCoroutineKind(), loweredTy->getCalleeConvention(), loweredTy->getParameters(), diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d895fa4748fc7..496669855e4c6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -6449,10 +6449,9 @@ ParserResult Parser::parseDeclFunc(SourceLoc StaticLoc, return DCC.fixupParserResult(FD); } -/// Parse a function body for \p AFD and returns it without setting the body -/// to \p AFD . -ParserResult -Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { +/// Parse a function body for \p AFD, setting the body to \p AFD before +/// returning it. +BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { assert(Tok.is(tok::l_brace)); // Enter the arguments for the function into a new function-body scope. We @@ -6480,13 +6479,70 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { CodeCompletion->completeAccessorBeginning(CCE); RBraceLoc = Tok.getLoc(); consumeToken(tok::code_complete); - return makeParserCodeCompletionResult( - BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc, - /*implicit*/ true)); + auto *BS = BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc, + /*implicit*/ true); + AFD->setBodyParsed(BS); + return BS; } } - return parseBraceItemList(diag::invalid_diagnostic); + ParserResult Body = parseBraceItemList(diag::invalid_diagnostic); + if (Body.isNull()) + return nullptr; + + BraceStmt *BS = Body.get(); + AFD->setBodyParsed(BS); + + // If the body consists of a single expression, turn it into a return + // statement. + // + // But don't do this transformation during code completion, as the source + // may be incomplete and the type mismatch in return statement will just + // confuse the type checker. + if (BS->getNumElements() != 1 || Body.hasCodeCompletion()) + return BS; + + auto Element = BS->getFirstElement(); + if (auto *stmt = Element.dyn_cast()) { + if (isa(AFD)) { + if (auto *returnStmt = dyn_cast(stmt)) { + if (!returnStmt->hasResult()) { + auto returnExpr = TupleExpr::createEmpty(Context, + SourceLoc(), + SourceLoc(), + /*implicit*/true); + returnStmt->setResult(returnExpr); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(returnExpr); + } + } + } + } else if (auto *E = Element.dyn_cast()) { + if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { + if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { + // This is an assignment. We don't want to implicitly return + // it. + return BS; + } + } + if (isa(AFD)) { + auto RS = new (Context) ReturnStmt(SourceLoc(), E); + BS->setFirstElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } else if (auto *F = dyn_cast(AFD)) { + if (F->isFailable() && isa(E)) { + // If it's a nil literal, just insert return. This is the only + // legal thing to return. + auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); + BS->setFirstElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } + } + } + + return BS; } /// Parse function body into \p AFD or skip it for delayed parsing. @@ -6511,60 +6567,7 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) { } Scope S(this, ScopeKind::FunctionBody); - - ParserResult Body = parseAbstractFunctionBodyImpl(AFD); - if (!Body.isNull()) { - BraceStmt * BS = Body.get(); - AFD->setBodyParsed(BS); - - // If the body consists of a single expression, turn it into a return - // statement. - // - // But don't do this transformation during code completion, as the source - // may be incomplete and the type mismatch in return statement will just - // confuse the type checker. - if (!Body.hasCodeCompletion() && BS->getNumElements() == 1) { - auto Element = BS->getFirstElement(); - if (auto *stmt = Element.dyn_cast()) { - if (isa(AFD)) { - if (auto *returnStmt = dyn_cast(stmt)) { - if (!returnStmt->hasResult()) { - auto returnExpr = TupleExpr::createEmpty(Context, - SourceLoc(), - SourceLoc(), - /*implicit*/true); - returnStmt->setResult(returnExpr); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(returnExpr); - } - } - } - } else if (auto *E = Element.dyn_cast()) { - if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { - if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { - // This is an assignment. We don't want to implicitly return - // it. - return; - } - } - if (isa(AFD)) { - auto RS = new (Context) ReturnStmt(SourceLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } else if (auto *F = dyn_cast(AFD)) { - if (F->isFailable() && isa(E)) { - // If it's a nil literal, just insert return. This is the only - // legal thing to return. - auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } - } - } - } - } + (void)parseAbstractFunctionBodyImpl(AFD); } BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { @@ -6596,7 +6599,7 @@ BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { Scope TopLevelScope(this, ScopeKind::TopLevel); Scope S(this, ScopeKind::FunctionBody); - return parseAbstractFunctionBodyImpl(AFD).getPtrOrNull(); + return parseAbstractFunctionBodyImpl(AFD); } /// Parse a 'enum' declaration, returning true (and doing no token diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1d3a63a826d11..7c753b4c2f226 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -802,8 +802,6 @@ ParserResult Parser::parseExprSelector() { parseExpr(selectorKind == ObjCSelectorExpr::Method ? diag::expr_selector_expected_method_expr : diag::expr_selector_expected_property_expr); - if (subExpr.hasCodeCompletion()) - return makeParserCodeCompletionResult(); // Parse the closing ')'. SourceLoc rParenLoc; @@ -819,7 +817,7 @@ ParserResult Parser::parseExprSelector() { } // If the subexpression was in error, just propagate the error. - if (subExpr.isParseError()) + if (subExpr.isParseError() && !subExpr.hasCodeCompletion()) return makeParserResult( new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc))); @@ -1612,60 +1610,8 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { return makeParserErrorResult(new (Context) ErrorExpr(DotLoc)); SyntaxContext->createNodeInPlace(SyntaxKind::MemberAccessExpr); - // Check for a () suffix, which indicates a call when constructing - // this member. Note that this cannot be the start of a new line. - if (Tok.isFollowingLParen()) { - SourceLoc lParenLoc, rParenLoc; - SmallVector args; - SmallVector argLabels; - SmallVector argLabelLocs; - SmallVector trailingClosures; - - ParserStatus status = parseExprList(tok::l_paren, tok::r_paren, - /*isPostfix=*/true, isExprBasic, - lParenLoc, args, argLabels, - argLabelLocs, - rParenLoc, - trailingClosures, - SyntaxKind::TupleExprElementList); - SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); - return makeParserResult( - status, - UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - lParenLoc, args, argLabels, - argLabelLocs, rParenLoc, - trailingClosures, - /*implicit=*/false)); - } - - // Check for a trailing closure, if allowed. - if (Tok.is(tok::l_brace) && isValidTrailingClosure(isExprBasic, *this)) { - if (SyntaxContext->isEnabled()) { - // Add dummy blank argument list to the call expression syntax. - SyntaxContext->addSyntax( - ParsedSyntaxRecorder::makeBlankTupleExprElementList( - leadingTriviaLoc(), *SyntaxContext)); - } - - SmallVector trailingClosures; - auto result = parseTrailingClosures(isExprBasic, NameLoc.getSourceRange(), - trailingClosures); - if (trailingClosures.empty()) - return nullptr; - - SyntaxContext->createNodeInPlace(SyntaxKind::FunctionCallExpr); - // Handle .foo by just making an AST node. - return makeParserResult( - result, UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - SourceLoc(), {}, {}, {}, - SourceLoc(), trailingClosures, - /*implicit=*/false)); - } - - // Handle .foo by just making an AST node. - return makeParserResult( - UnresolvedMemberExpr::create(Context, DotLoc, NameLoc, Name, - /*implicit=*/false)); + return makeParserResult(new (Context) UnresolvedMemberExpr( + DotLoc, NameLoc, Name, /*implicit=*/false)); } case tok::kw_super: // 'super' diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index e26a0dd1cd238..c98ea0c6f04da 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -130,8 +130,10 @@ static ParserStatus parseDefaultArgument( defaultArgs->HasDefaultArgument = true; - if (initR.hasCodeCompletion()) + if (initR.hasCodeCompletion()) { + init = initR.get(); return makeParserCodeCompletionStatus(); + } if (initR.isNull()) return makeParserError(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index e39f0daf1846b..c4a64ca54973e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -898,9 +898,7 @@ ParserResult Parser::parseStmtThrow(SourceLoc tryLoc) { exprLoc = Tok.getLoc(); ParserResult Result = parseExpr(diag::expected_expr_throw); - - if (Result.hasCodeCompletion()) - return makeParserCodeCompletionResult(); + bool hasCodeCompletion = Result.hasCodeCompletion(); if (Result.isNull()) Result = makeParserErrorResult(new (Context) ErrorExpr(throwLoc)); @@ -916,6 +914,9 @@ ParserResult Parser::parseStmtThrow(SourceLoc tryLoc) { Result = makeParserResult(new (Context) TryExpr(exprLoc, Result.get())); } + if (hasCodeCompletion) + Result.setHasCodeCompletion(); + return makeParserResult(Result, new (Context) ThrowStmt(throwLoc, Result.get())); } @@ -2012,9 +2013,6 @@ ParserResult Parser::parseStmtCatch() { GuardedPattern PatternResult; parseGuardedPattern(*this, PatternResult, status, boundDecls, GuardedPatternContext::Catch, isFirst); - if (status.hasCodeCompletion()) { - return makeParserCodeCompletionResult(); - } caseLabelItems.emplace_back(PatternResult.ThePattern, PatternResult.WhereLoc, PatternResult.Guard); isFirst = false; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 7b56a1f629368..25161aabaa9ee 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -203,7 +203,7 @@ void Parser::performCodeCompletionSecondPassImpl( case CodeCompletionDelayedDeclKind::FunctionBody: { auto *AFD = cast(DC); - AFD->setBodyParsed(parseAbstractFunctionBodyImpl(AFD).getPtrOrNull()); + (void)parseAbstractFunctionBodyImpl(AFD); break; } } diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index 686a8421f642d..0f937e95cec77 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -632,9 +632,10 @@ class RemoteASTContextConcreteImpl final : public RemoteASTContextImpl { SubstitutionMap substitutions, unsigned ordinal) override { auto underlyingType = Reader - .readUnderlyingTypeForOpaqueTypeDescriptor(opaqueDescriptor.getAddressData(), - ordinal); - + .readUnderlyingTypeForOpaqueTypeDescriptor( + opaqueDescriptor.getAddressData(), ordinal) + .getType(); + if (!underlyingType) return getFailure(); diff --git a/lib/SIL/IR/SILBuilder.cpp b/lib/SIL/IR/SILBuilder.cpp index d6a876037c0b9..c925cc83bb737 100644 --- a/lib/SIL/IR/SILBuilder.cpp +++ b/lib/SIL/IR/SILBuilder.cpp @@ -107,7 +107,6 @@ SILType SILBuilder::getPartialApplyResultType( auto appliedFnType = SILFunctionType::get(nullptr, extInfo, - FTI->isAsync(), FTI->getCoroutineKind(), calleeConvention, newParams, diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 0e50bdd34f8e4..29a40a911d107 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -94,7 +94,6 @@ CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { : CanGenericSignature(); return SILFunctionType::get(signature, getExtInfo(), - isAsync(), getCoroutineKind(), getCalleeConvention(), params, yields, results, errorResult, @@ -288,11 +287,11 @@ SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, } auto newExtInfo = getExtInfo().intoBuilder().withDifferentiabilityKind(kind).build(); - return get(getInvocationGenericSignature(), newExtInfo, isAsync(), - getCoroutineKind(), getCalleeConvention(), newParameters, - getYields(), newResults, getOptionalErrorResult(), - getPatternSubstitutions(), getInvocationSubstitutions(), - getASTContext(), getWitnessMethodConformanceOrInvalid()); + return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationSubstitutions(), getASTContext(), + getWitnessMethodConformanceOrInvalid()); } CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { @@ -312,9 +311,9 @@ CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { newResults.push_back(result.getWithDifferentiability( SILResultDifferentiability::DifferentiableOrNotApplicable)); return SILFunctionType::get( - getInvocationGenericSignature(), nondiffExtInfo, isAsync(), - getCoroutineKind(), getCalleeConvention(), newParams, getYields(), - newResults, getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationGenericSignature(), nondiffExtInfo, getCoroutineKind(), + getCalleeConvention(), newParams, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext()); } @@ -503,9 +502,9 @@ static CanSILFunctionType getAutoDiffDifferentialType( llvm::makeArrayRef(substConformances)); } return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), /*isAsync*/ false, - SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, - differentialParams, {}, differentialResults, None, substitutions, + GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, differentialParams, {}, + differentialResults, None, substitutions, /*invocationSubstitutions*/ SubstitutionMap(), ctx); } @@ -682,9 +681,9 @@ static CanSILFunctionType getAutoDiffPullbackType( llvm::makeArrayRef(substConformances)); } return SILFunctionType::get( - GenericSignature(), SILFunctionType::ExtInfo(), /*isAsync*/ false, - SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, - pullbackParams, {}, pullbackResults, None, substitutions, + GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, pullbackParams, {}, + pullbackResults, None, substitutions, /*invocationSubstitutions*/ SubstitutionMap(), ctx); } @@ -738,7 +737,7 @@ static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( constrainedInvocationGenSig->areAllParamsConcrete() ? GenericSignature() : constrainedInvocationGenSig, - original->getExtInfo(), original->isAsync(), original->getCoroutineKind(), + original->getExtInfo(), original->getCoroutineKind(), original->getCalleeConvention(), newParameters, original->getYields(), newResults, original->getOptionalErrorResult(), /*patternSubstitutions*/ SubstitutionMap(), @@ -829,7 +828,6 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // cache and return. cachedResult = SILFunctionType::get( constrainedOriginalFnTy->getSubstGenericSignature(), extInfo, - constrainedOriginalFnTy->isAsync(), constrainedOriginalFnTy->getCoroutineKind(), constrainedOriginalFnTy->getCalleeConvention(), newParameters, constrainedOriginalFnTy->getYields(), newResults, @@ -915,9 +913,9 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( for (auto &res : getResults()) newParameters.push_back(getParameterInfoForOriginalResult(res)); return SILFunctionType::get( - getInvocationGenericSignature(), getExtInfo(), isAsync(), - getCoroutineKind(), getCalleeConvention(), newParameters, getYields(), - newResults, getOptionalErrorResult(), getPatternSubstitutions(), + getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), + getCalleeConvention(), newParameters, getYields(), newResults, + getOptionalErrorResult(), getPatternSubstitutions(), /*invocationSubstitutions*/ {}, getASTContext()); } @@ -991,8 +989,7 @@ Lowering::adjustFunctionType(CanSILFunctionType type, return type; return SILFunctionType::get(type->getInvocationGenericSignature(), - extInfo, type->isAsync(), - type->getCoroutineKind(), callee, + extInfo, type->getCoroutineKind(), callee, type->getParameters(), type->getYields(), type->getResults(), type->getOptionalErrorResult(), @@ -1019,9 +1016,9 @@ CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { : Lowering::DefaultThickCalleeConvention) : ParameterConvention::Direct_Unowned); - return get(getInvocationGenericSignature(), newExt, isAsync(), - getCoroutineKind(), calleeConvention, getParameters(), getYields(), - getResults(), getOptionalErrorResult(), getPatternSubstitutions(), + return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), + calleeConvention, getParameters(), getYields(), getResults(), + getOptionalErrorResult(), getPatternSubstitutions(), getInvocationSubstitutions(), getASTContext(), getWitnessMethodConformanceOrInvalid()); } @@ -2169,8 +2166,7 @@ static CanSILFunctionType getSILFunctionType( } } - return SILFunctionType::get(genericSig, silExtInfo, - substFnInterfaceType->isAsync(), coroutineKind, + return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, calleeConvention, inputs, yields, results, errorResult, substitutions, SubstitutionMap(), @@ -3760,7 +3756,7 @@ class SILTypeSubstituter : ? origType->getInvocationGenericSignature() : nullptr; - return SILFunctionType::get(genericSig, extInfo, origType->isAsync(), + return SILFunctionType::get(genericSig, extInfo, origType->getCoroutineKind(), origType->getCalleeConvention(), substParams, substYields, substResults, substErrorResult, @@ -3988,27 +3984,17 @@ SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, CanAnyFunctionType TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, CanAnyFunctionType t, - AnyFunctionType::ExtInfo extInfo, Bridgeability bridging) { // Pull out the generic signature. CanGenericSignature genericSig = t.getOptGenericSignature(); - switch (auto rep = t->getExtInfo().getSILRepresentation()) { - case SILFunctionTypeRepresentation::Thick: - case SILFunctionTypeRepresentation::Thin: - case SILFunctionTypeRepresentation::Method: - case SILFunctionTypeRepresentation::Closure: - case SILFunctionTypeRepresentation::WitnessMethod: { + auto rep = t->getExtInfo().getSILRepresentation(); + switch (getSILFunctionLanguage(rep)) { + case SILFunctionLanguage::Swift: { // No bridging needed for native functions. - if (t->getExtInfo().isEqualTo(extInfo, useClangTypes(t))) - return t; - return CanAnyFunctionType::get(genericSig, t.getParams(), t.getResult(), - extInfo); + return t; } - - case SILFunctionTypeRepresentation::CFunctionPointer: - case SILFunctionTypeRepresentation::Block: - case SILFunctionTypeRepresentation::ObjCMethod: { + case SILFunctionLanguage::C: { SmallVector params; getBridgedParams(rep, pattern, t->getParams(), params, bridging); @@ -4020,7 +4006,7 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, suppressOptional); return CanAnyFunctionType::get(genericSig, llvm::makeArrayRef(params), - result, extInfo); + result, t->getExtInfo()); } } llvm_unreachable("bad calling convention"); @@ -4102,7 +4088,6 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, auto bridging = Bridgeability::Full; unsigned numParameterLists = constant.getParameterListCount(); - auto extInfo = fnType->getExtInfo(); // Form an abstraction pattern for bridging purposes. AbstractionPattern bridgingFnPattern = @@ -4112,12 +4097,13 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, // Fast path: no uncurrying required. if (numParameterLists == 1) { auto bridgedFnType = - getBridgedFunctionType(bridgingFnPattern, fnType, extInfo, bridging); + getBridgedFunctionType(bridgingFnPattern, fnType, bridging); bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), bridgedFnType); return { bridgingFnPattern, bridgedFnType }; } + auto extInfo = fnType->getExtInfo(); SILFunctionTypeRepresentation rep = extInfo.getSILRepresentation(); assert(rep != SILFunctionType::Representation::Block && "objc blocks cannot be curried"); diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index 609a8318b153d..85407811bae76 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -272,7 +272,7 @@ SILFunction *swift::findInitializer(SILFunction *AddrF, if (!CallToOnce) return nullptr; SILFunction *callee = getCalleeOfOnceCall(CallToOnce); - if (!callee->getName().startswith("globalinit_")) + if (!callee->isGlobalInitOnceFunction()) return nullptr; return callee; } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 52d038ec240a9..17c3810556b77 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2606,6 +2606,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { case SILFunction::Purpose::GlobalInit: OS << "[global_init] "; break; + case SILFunction::Purpose::GlobalInitOnceFunction: + OS << "[global_init_once_fn] "; + break; case SILFunction::Purpose::LazyPropertyGetter: OS << "[lazy_getter] "; break; diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index 28f323ccf8769..48ca1e5cbc47d 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -671,10 +671,9 @@ TypeBase::replaceSubstitutedSILFunctionTypesWithUnsubstituted(SILModule &M) cons if (!didChange) return sft; - + return SILFunctionType::get(sft->getInvocationGenericSignature(), - sft->getExtInfo(), sft->isAsync(), - sft->getCoroutineKind(), + sft->getExtInfo(), sft->getCoroutineKind(), sft->getCalleeConvention(), newParams, newYields, newResults, newErrorResult, diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index e1d4417e42dd6..45a725074cb8d 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -1964,7 +1964,7 @@ TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion, // Bridge the parameters and result of the function type. auto bridgedFnType = - TC.getBridgedFunctionType(origType, substFnType, extInfo, bridging); + TC.getBridgedFunctionType(origType, substFnType, bridging); substFnType = bridgedFnType; // Also rewrite the type of the abstraction pattern. diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 27951f2813ec0..b6603a1d9cc0a 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -960,6 +960,8 @@ static bool parseDeclSILOptional(bool *isTransparent, *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") *specialPurpose = SILFunction::Purpose::LazyPropertyGetter; + else if (specialPurpose && SP.P.Tok.getText() == "global_init_once_fn") + *specialPurpose = SILFunction::Purpose::GlobalInitOnceFunction; else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") { if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF()) SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target, diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index b1fde1019a1ce..ff29fdb56eab0 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -3016,7 +3016,6 @@ class SILVerifier : public SILVerifierBase { auto fnTy = SILFunctionType::get(nullptr, methodTy->getExtInfo(), - methodTy->isAsync(), methodTy->getCoroutineKind(), methodTy->getCalleeConvention(), dynParams, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 48d3a50cd2b5a..4014b52841077 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -415,11 +415,12 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, SILFunctionType::ExtInfoBuilder(SILFunctionTypeRepresentation::Thin, /*pseudogeneric*/ false, /*non-escaping*/ false, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); - auto functionTy = SILFunctionType::get(sig, extInfo, /*isAsync*/ false, + auto functionTy = SILFunctionType::get(sig, extInfo, SILCoroutineKind::YieldOnce, ParameterConvention::Direct_Unowned, params, @@ -482,7 +483,7 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) { }; CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo, - /*isAsync*/ false, SILCoroutineKind::None, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, SILResultInfo(Int32Ty, @@ -1367,6 +1368,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, auto *f = builder.createFunction( SILLinkage::Private, funcName, initSILType, nullptr, SILLocation(binding), IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic); + f->setSpecialPurpose(SILFunction::Purpose::GlobalInitOnceFunction); f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f)); auto dc = binding->getDeclContext(); SILGenFunction(*this, *f, dc).emitLazyGlobalInitializer(binding, pbdEntry); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index bffecc2c2c187..22d3136ca776c 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -76,7 +76,6 @@ getIndirectApplyAbstractionPattern(SILGenFunction &SGF, // bridged to a foreign type. auto bridgedType = SGF.SGM.Types.getBridgedFunctionType(pattern, fnType, - fnType->getExtInfo(), Bridgeability::Full); pattern.rewriteType(CanGenericSignature(), bridgedType); return pattern; diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index a013d5b188baa..0c1bb7d417a89 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -350,8 +350,7 @@ getParameterTypes(AnyFunctionType::CanParamArrayRef params) { static CanAnyFunctionType getBridgedBlockType(SILGenModule &SGM, CanAnyFunctionType blockType) { return SGM.Types.getBridgedFunctionType(AbstractionPattern(blockType), - blockType, blockType->getExtInfo(), - Bridgeability::Full); + blockType, Bridgeability::Full); } static void buildFuncToBlockInvokeBody(SILGenFunction &SGF, @@ -578,7 +577,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, } auto invokeTy = SILFunctionType::get( - genericSig, extInfo, /*isAsync*/ false, SILCoroutineKind::None, + genericSig, extInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, blockInterfaceTy->getResults(), blockInterfaceTy->getOptionalErrorResult(), diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 0aef4de8034b3..0f4866879fb90 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -216,11 +216,9 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, .forwardInto(SGF, Loc, init.get()); ++elti; } else { -#ifndef NDEBUG - assert( - field->getType()->isEqual(field->getParentInitializer()->getType()) - && "Checked by sema"); -#endif + assert(field->getType()->getReferenceStorageReferent()->isEqual( + field->getParentInitializer()->getType()) && + "Initialization of field with mismatched type!"); // Cleanup after this initialization. FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 8ef8f36c118ee..cb8273d129e1e 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2750,7 +2750,6 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, return SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, result, None, @@ -2897,10 +2896,9 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredInterfaceType() ->getCanonicalType(), ParameterConvention::Direct_Unowned}); - + return SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, {}, {}, None, @@ -3083,7 +3081,6 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, @@ -3258,7 +3255,6 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, params, /*yields*/ {}, results, None, diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 7f6cf2516db66..d9acdc516f6ac 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -602,7 +602,6 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { SILFunctionType::ExtInfo() .withRepresentation(SILFunctionType::Representation:: CFunctionPointer), - /*isAsync*/ false, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, SILParameterInfo(anyObjectMetaTy, @@ -698,8 +697,7 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { // has an overlay to fix the type of argv. .withRepresentation(SILFunctionType::Representation::Thin) .build(), - /*isAsync*/ false, SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, argTypes, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, argTypes, /*yields*/ {}, SILResultInfo(argc->getType().getASTType(), ResultConvention::Unowned), /*error result*/ None, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 551b438f461f0..a43ce63f99508 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -178,20 +178,8 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, ->areAllParamsConcrete()); } - // Emit the lazy initialization token for the initialization expression. - auto counter = anonymousSymbolCounter++; - - // Pick one variable of the pattern. Usually it's only one variable, but it - // can also be something like: var (a, b) = ... - Pattern *pattern = pd->getPattern(pbdEntry); - VarDecl *varDecl = nullptr; - pattern->forEachVariable([&](VarDecl *D) { - varDecl = D; - }); - assert(varDecl); - Mangle::ASTMangler TokenMangler; - std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(varDecl, counter, + std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(pd, pbdEntry, false); auto onceTy = BuiltinIntegerType::getWordType(M.getASTContext()); @@ -207,7 +195,7 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, // Emit the initialization code into a function. Mangle::ASTMangler FuncMangler; - std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(varDecl, counter, + std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(pd, pbdEntry, true); SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncBuffer, pd, diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 110edd25ba171..0ee11d74f6439 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3245,9 +3245,9 @@ CanSILFunctionType SILGenFunction::buildThunkType( // The type of the thunk function. return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->isAsync(), - expectedType->getCoroutineKind(), ParameterConvention::Direct_Unowned, - interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, + genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), + ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, + interfaceResults, interfaceErrorResult, expectedType->getPatternSubstitutions(), SubstitutionMap(), getASTContext()); } diff --git a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp index 2cadf6426c013..aa54592497e51 100644 --- a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp @@ -47,7 +47,7 @@ class ARCLoopOpts : public SILFunctionTransform { return; // Skip global init functions. - if (F->getName().startswith("globalinit_")) + if (F->isGlobalInitOnceFunction()) return; auto *LA = getAnalysis(); diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index fa0602b04bd4f..f628be8b5b29c 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -183,7 +183,7 @@ processFunctionWithoutLoopSupport(SILFunction &F, bool FreezePostDomReleases, // globalinit_func. Since that is not *that* interesting from an ARC // perspective (i.e. no ref count operations in a loop), disable it on such // functions temporarily in order to unblock others. This should be removed. - if (F.getName().startswith("globalinit_")) + if (F.isGlobalInitOnceFunction()) return false; LLVM_DEBUG(llvm::dbgs() << "***** Processing " << F.getName() << " *****\n"); @@ -231,7 +231,7 @@ static bool processFunctionWithLoopSupport( // globalinit_func. Since that is not *that* interesting from an ARC // perspective (i.e. no ref count operations in a loop), disable it on such // functions temporarily in order to unblock others. This should be removed. - if (F.getName().startswith("globalinit_")) + if (F.isGlobalInitOnceFunction()) return false; LLVM_DEBUG(llvm::dbgs() << "***** Processing " << F.getName() << " *****\n"); diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 594cb81485a8c..c651cb5bf2943 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -1623,6 +1623,13 @@ void EscapeAnalysis::ConnectionGraph::verify() const { if (auto ai = dyn_cast(&i)) { if (EA->canOptimizeArrayUninitializedCall(ai).isValid()) continue; + // Ignore checking CGNode mapping for result of apply to a no return + // function that will have a null ReturnNode + if (auto *callee = ai->getReferencedFunctionOrNull()) { + if (EA->getFunctionInfo(callee)->isValid()) + if (!EA->getConnectionGraph(callee)->getReturnNodeOrNull()) + continue; + } } for (auto result : i.getResults()) { if (EA->getPointerBase(result)) diff --git a/lib/SILOptimizer/CMakeLists.txt b/lib/SILOptimizer/CMakeLists.txt index 4bf45e0ebd8db..ec1440d2b06a1 100644 --- a/lib/SILOptimizer/CMakeLists.txt +++ b/lib/SILOptimizer/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(LoopTransforms) add_subdirectory(Mandatory) add_subdirectory(PassManager) add_subdirectory(SILCombiner) +add_subdirectory(SemanticARC) add_subdirectory(Transforms) add_subdirectory(UtilityPasses) add_subdirectory(Utils) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index f2e1d04aea635..2586e5ac6ad2e 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -553,9 +553,14 @@ class JVPCloner::Implementation final if (!originalFnTy->getParameters()[paramIndex] .getSILStorageInterfaceType() .isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - ai->getArgumentsWithoutIndirectResults()[paramIndex], - invoker, diag::autodiff_nondifferentiable_argument); + auto arg = ai->getArgumentsWithoutIndirectResults()[paramIndex]; + auto startLoc = arg.getLoc().getStartSourceLoc(); + auto endLoc = arg.getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + arg, invoker, diag::autodiff_nondifferentiable_argument) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -573,9 +578,14 @@ class JVPCloner::Implementation final .getSILStorageInterfaceType(); } if (!remappedResultType.isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - origCallee, invoker, - diag::autodiff_nondifferentiable_result); + auto startLoc = ai->getLoc().getStartSourceLoc(); + auto endLoc = ai->getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + origCallee, invoker, + diag::autodiff_nondifferentiable_result) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -1587,10 +1597,10 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { auto *diffGenericEnv = diffGenericSig ? diffGenericSig->getGenericEnvironment() : nullptr; auto diffType = SILFunctionType::get( - diffGenericSig, origTy->getExtInfo(), origTy->isAsync(), - origTy->getCoroutineKind(), origTy->getCalleeConvention(), dfParams, {}, - dfResults, None, origTy->getPatternSubstitutions(), - origTy->getInvocationSubstitutions(), original->getASTContext()); + diffGenericSig, origTy->getExtInfo(), origTy->getCoroutineKind(), + origTy->getCalleeConvention(), dfParams, {}, dfResults, None, + origTy->getPatternSubstitutions(), origTy->getInvocationSubstitutions(), + original->getASTContext()); SILOptFunctionBuilder fb(context.getTransform()); auto linkage = jvp->isSerialized() ? SILLinkage::Public : SILLinkage::Hidden; diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 9de979b76d0f8..7b0c3c62fda76 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -2035,12 +2035,10 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( SILBasicBlock *bb, SILValue optionalValue, SILValue wrappedAdjoint) { auto pbLoc = getPullback().getLocation(); // Handle `switch_enum` on `Optional`. - auto *optionalEnumDecl = getASTContext().getOptionalDecl(); - auto optionalTy = optionalValue->getType(); - assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == - optionalEnumDecl); // `Optional` - optionalTy = remapType(optionalTy); + auto optionalTy = remapType(optionalValue->getType()); + assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == + getASTContext().getOptionalDecl()); // `T` auto wrappedType = optionalTy.getOptionalObjectType(); // `T.TangentVector` diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index bd1817c6f3994..820805fff06d9 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -242,9 +242,9 @@ CanSILFunctionType buildThunkType(SILFunction *fn, // The type of the thunk function. return SILFunctionType::get( - genericSig, extInfoBuilder.build(), expectedType->isAsync(), - expectedType->getCoroutineKind(), ParameterConvention::Direct_Unowned, - interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, + genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(), + ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields, + interfaceResults, interfaceErrorResult, expectedType->getPatternSubstitutions(), SubstitutionMap(), fn->getASTContext()); } diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index dc0d915148e20..f58db200debe9 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -457,9 +457,14 @@ class VJPCloner::Implementation final if (!originalFnTy->getParameters()[paramIndex] .getSILStorageInterfaceType() .isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - ai->getArgumentsWithoutIndirectResults()[paramIndex], invoker, - diag::autodiff_nondifferentiable_argument); + auto arg = ai->getArgumentsWithoutIndirectResults()[paramIndex]; + auto startLoc = arg.getLoc().getStartSourceLoc(); + auto endLoc = arg.getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + arg, invoker, diag::autodiff_nondifferentiable_argument) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -477,8 +482,14 @@ class VJPCloner::Implementation final .getSILStorageInterfaceType(); } if (!remappedResultType.isDifferentiable(getModule())) { - context.emitNondifferentiabilityError( - origCallee, invoker, diag::autodiff_nondifferentiable_result); + auto startLoc = ai->getLoc().getStartSourceLoc(); + auto endLoc = ai->getLoc().getEndSourceLoc(); + context + .emitNondifferentiabilityError( + origCallee, invoker, + diag::autodiff_nondifferentiable_result) + .fixItInsert(startLoc, "withoutDerivative(at: ") + .fixItInsertAfter(endLoc, ")"); errorOccurred = true; return true; } @@ -892,10 +903,10 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { auto *pbGenericEnv = pbGenericSig ? pbGenericSig->getGenericEnvironment() : nullptr; auto pbType = SILFunctionType::get( - pbGenericSig, origTy->getExtInfo(), origTy->isAsync(), - origTy->getCoroutineKind(), origTy->getCalleeConvention(), pbParams, {}, - adjResults, None, origTy->getPatternSubstitutions(), - origTy->getInvocationSubstitutions(), original->getASTContext()); + pbGenericSig, origTy->getExtInfo(), origTy->getCoroutineKind(), + origTy->getCalleeConvention(), pbParams, {}, adjResults, None, + origTy->getPatternSubstitutions(), origTy->getInvocationSubstitutions(), + original->getASTContext()); SILOptFunctionBuilder fb(context.getTransform()); auto linkage = vjp->isSerialized() ? SILLinkage::Public : SILLinkage::Private; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 839810a36223d..66617c63b0c24 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -403,7 +403,7 @@ ExistentialTransform::createExistentialSpecializedFunctionType() { /// Return the new signature. return SILFunctionType::get( - NewGenericSig, ExtInfo, FTy->isAsync(), FTy->getCoroutineKind(), + NewGenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), InterfaceParams, FTy->getYields(), FTy->getResults(), InterfaceErrorResult, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 328f55ab17ee9..7d1f34ea07cc4 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -408,11 +408,10 @@ FunctionSignatureTransformDescriptor::createOptimizedSILFunctionType() { UsesGenerics ? FTy->getInvocationGenericSignature() : nullptr; return SILFunctionType::get( - GenericSig, ExtInfo, FTy->isAsync(), FTy->getCoroutineKind(), - FTy->getCalleeConvention(), InterfaceParams, InterfaceYields, - InterfaceResults, InterfaceErrorResult, FTy->getPatternSubstitutions(), - SubstitutionMap(), F->getModule().getASTContext(), - witnessMethodConformance); + GenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(), + InterfaceParams, InterfaceYields, InterfaceResults, InterfaceErrorResult, + FTy->getPatternSubstitutions(), SubstitutionMap(), + F->getModule().getASTContext(), witnessMethodConformance); } /// Compute what the function interface will look like based on the diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp index ee4f6badc8505..37533fef306fc 100644 --- a/lib/SILOptimizer/IPO/CapturePromotion.cpp +++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp @@ -428,9 +428,8 @@ ClosureCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, // Create the thin function type for the cloned closure. auto ClonedTy = SILFunctionType::get( OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), - OrigFTI->isAsync(), OrigFTI->getCoroutineKind(), - OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, - OrigFTI->getYields(), OrigFTI->getResults(), + OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), + ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 137054e99ec18..05ab7bcaf6f10 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -670,7 +670,7 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, auto ClonedTy = SILFunctionType::get( ClosureUserFunTy->getInvocationGenericSignature(), ExtInfo, - ClosureUserFunTy->isAsync(), ClosureUserFunTy->getCoroutineKind(), + ClosureUserFunTy->getCoroutineKind(), ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList, ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(), ClosureUserFunTy->getOptionalErrorResult(), diff --git a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp index ea8429c854876..ce00fdd8b8e43 100644 --- a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp +++ b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp @@ -337,9 +337,6 @@ bool CrossModuleSerializationSetup::canSerialize(SILInstruction *inst, }); return canUse; } - if (auto *GAI = dyn_cast(inst)) { - return !GAI->getReferencedGlobal()->getName().startswith("globalinit_"); - } if (auto *MI = dyn_cast(inst)) { return !MI->getMember().isForeign; } diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index 113d71ccb32b8..1c34038499262 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -260,7 +260,7 @@ void SILGlobalOpt::collectOnceCall(BuiltinInst *BI) { UnhandledOnceCallee = true; return; } - if (!Callee->getName().startswith("globalinit_")) + if (!Callee->isGlobalInitOnceFunction()) return; // We currently disable optimizing the initializer if a globalinit_func diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 12be62eefbf83..6c5f962729b83 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -876,8 +876,7 @@ static void emitFatalError(ADContext &context, SILFunction *f, // Fatal error function must have type `@convention(thin) () -> Never`. auto fatalErrorFnType = SILFunctionType::get( /*genericSig*/ nullptr, SILFunctionType::ExtInfo::getThin(), - /*isAsync*/ false, SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, {}, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, {}, /*interfaceYields*/ {}, neverResultInfo, /*interfaceErrorResults*/ None, {}, {}, context.getASTContext()); auto fnBuilder = SILOptFunctionBuilder(context.getTransform()); @@ -1029,10 +1028,10 @@ static SILValue promoteCurryThunkApplicationToDifferentiableFunction( auto newThunkResult = thunkResult.getWithInterfaceType(diffResultFnTy); auto thunkType = SILFunctionType::get( thunkTy->getSubstGenericSignature(), thunkTy->getExtInfo(), - thunkTy->isAsync(), thunkTy->getCoroutineKind(), - thunkTy->getCalleeConvention(), thunkTy->getParameters(), {}, - {newThunkResult}, {}, thunkTy->getPatternSubstitutions(), - thunkTy->getInvocationSubstitutions(), thunkTy->getASTContext()); + thunkTy->getCoroutineKind(), thunkTy->getCalleeConvention(), + thunkTy->getParameters(), {}, {newThunkResult}, {}, + thunkTy->getPatternSubstitutions(), thunkTy->getInvocationSubstitutions(), + thunkTy->getASTContext()); // Construct new curry thunk, returning a `@differentiable` function. SILOptFunctionBuilder fb(dt.getTransform()); diff --git a/lib/SILOptimizer/SemanticARC/CMakeLists.txt b/lib/SILOptimizer/SemanticARC/CMakeLists.txt new file mode 100644 index 0000000000000..7ae8f36a2bbde --- /dev/null +++ b/lib/SILOptimizer/SemanticARC/CMakeLists.txt @@ -0,0 +1,2 @@ +target_sources(swiftSILOptimizer PRIVATE + SemanticARCOpts.cpp) diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp similarity index 99% rename from lib/SILOptimizer/Transforms/SemanticARCOpts.cpp rename to lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp index 743dac16eaa6b..180f3882a7807 100644 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/SemanticARCOpts.cpp @@ -1034,8 +1034,8 @@ struct SemanticARCOptVisitor } // end anonymous namespace static llvm::cl::opt -VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", - llvm::cl::init(false), llvm::cl::Hidden); + VerifyAfterTransform("sil-semantic-arc-opts-verify-after-transform", + llvm::cl::init(false), llvm::cl::Hidden); static bool canEliminatePhi( SemanticARCOptVisitor::FrozenMultiMapRange optimizableIntroducerRange, @@ -1436,7 +1436,8 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { // are within the borrow scope. // // TODO: This needs a better name. -bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst *cvi) { +bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization( + CopyValueInst *cvi) { // For now, do not run this optimization. This is just to be careful. if (onlyGuaranteedOpts) return false; @@ -1617,7 +1618,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst /// If cvi only has destroy value users, then cvi is a dead live range. Lets /// eliminate all such dead live ranges. -bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi) { +bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue( + CopyValueInst *cvi) { // This is a cheap optimization generally. // See if we are lucky and have a simple case. @@ -1857,8 +1859,7 @@ namespace { /// written to again. In both cases, we can convert load [copy] -> load_borrow /// safely. class StorageGuaranteesLoadVisitor - : public AccessUseDefChainVisitor -{ + : public AccessUseDefChainVisitor { // The outer SemanticARCOptVisitor. SemanticARCOptVisitor &ARCOpt; @@ -1867,7 +1868,7 @@ class StorageGuaranteesLoadVisitor // The current address being visited. SILValue currentAddress; - + Optional isWritten; public: @@ -1880,11 +1881,9 @@ class StorageGuaranteesLoadVisitor currentAddress = nullptr; isWritten = written; } - - void next(SILValue address) { - currentAddress = address; - } - + + void next(SILValue address) { currentAddress = address; } + void visitNestedAccess(BeginAccessInst *access) { // First see if we have read/modify. If we do not, just look through the // nested access. @@ -1901,9 +1900,7 @@ class StorageGuaranteesLoadVisitor // scope. If so, we may be able to use a load_borrow here! SmallVector endScopeUses; transform(access->getEndAccesses(), std::back_inserter(endScopeUses), - [](EndAccessInst *eai) { - return &eai->getAllOperands()[0]; - }); + [](EndAccessInst *eai) { return &eai->getAllOperands()[0]; }); SmallPtrSet visitedBlocks; LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); if (!checker.validateLifetime(access, endScopeUses, @@ -1930,7 +1927,7 @@ class StorageGuaranteesLoadVisitor return answer(true); } - + void visitArgumentAccess(SILFunctionArgument *arg) { // If this load_copy is from an indirect in_guaranteed argument, then we // know for sure that it will never be written to. @@ -2007,15 +2004,15 @@ class StorageGuaranteesLoadVisitor // able to also to promote load [copy] from such args to load_borrow. return answer(true); } - + void visitGlobalAccess(SILValue global) { return answer(!AccessedStorage(global, AccessedStorage::Global) - .isLetAccess(&ARCOpt.F)); + .isLetAccess(&ARCOpt.F)); } - + void visitClassAccess(RefElementAddrInst *field) { currentAddress = nullptr; - + // We know a let property won't be written to if the base object is // guaranteed for the duration of the access. // For non-let properties conservatively assume they may be written to. @@ -2071,15 +2068,13 @@ class StorageGuaranteesLoadVisitor baseObject, endScopeInsts, liveRange.getAllConsumingUses()); return answer(foundError); } - + // TODO: Handle other access kinds? void visitBase(SILValue base, AccessedStorage::Kind kind) { return answer(true); } - void visitNonAccess(SILValue addr) { - return answer(true); - } + void visitNonAccess(SILValue addr) { return answer(true); } void visitCast(SingleValueInstruction *cast, Operand *parentAddr) { return next(parentAddr->get()); diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 93571944f8312..6483b47a12a6f 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -699,9 +699,8 @@ SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, // the parameters promoted. auto ClonedTy = SILFunctionType::get( OrigFTI->getInvocationGenericSignature(), OrigFTI->getExtInfo(), - OrigFTI->isAsync(), OrigFTI->getCoroutineKind(), - OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys, - OrigFTI->getYields(), OrigFTI->getResults(), + OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(), + ClonedInterfaceArgTys, OrigFTI->getYields(), OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(), OrigFTI->getPatternSubstitutions(), OrigFTI->getInvocationSubstitutions(), M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrInvalid()); diff --git a/lib/SILOptimizer/Transforms/CMakeLists.txt b/lib/SILOptimizer/Transforms/CMakeLists.txt index c51043a1910c3..ac3718b6cf20f 100644 --- a/lib/SILOptimizer/Transforms/CMakeLists.txt +++ b/lib/SILOptimizer/Transforms/CMakeLists.txt @@ -31,7 +31,6 @@ target_sources(swiftSILOptimizer PRIVATE RedundantLoadElimination.cpp RedundantOverflowCheckRemoval.cpp ReleaseDevirtualizer.cpp - SemanticARCOpts.cpp SILCodeMotion.cpp SILLowerAggregateInstrs.cpp SILMem2Reg.cpp diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index 4426205c94ff0..b5a89537fbe0e 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -298,11 +298,11 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { auto ExtInfo = SILFunctionType::ExtInfoBuilder( SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); auto FunctionType = SILFunctionType::get( - nullptr, ExtInfo, /*isAsync*/ false, SILCoroutineKind::None, + nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, /*yields*/ {}, Results, None, SubstitutionMap(), SubstitutionMap(), @@ -1181,6 +1181,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { SILFunctionType::ExtInfoBuilder(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, /*noescape*/ false, + /*async*/ false, DifferentiabilityKind::NonDifferentiable, /*clangFunctionType*/ nullptr) .build(); @@ -1203,7 +1204,7 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { SILResultInfo(BridgedReturn.getReturnType(), ResultConvention::Owned)); } auto FunctionType = SILFunctionType::get( - nullptr, ExtInfo, /*isAsync*/ false, SILCoroutineKind::None, + nullptr, ExtInfo, SILCoroutineKind::None, ParameterConvention::Direct_Unowned, Parameters, {}, Results, None, SubstitutionMap(), SubstitutionMap(), diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index 3ec8f130c3496..9ef7e2d70befd 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -86,11 +86,11 @@ class BugReducerTester : public SILFunctionTransform { nullptr, SILFunctionType::ExtInfoBuilder( SILFunctionType::Representation::Thin, false /*isPseudoGeneric*/, - false /*noescape*/, DifferentiabilityKind::NonDifferentiable, + false /*noescape*/, false /*async*/, + DifferentiabilityKind::NonDifferentiable, nullptr /*clangFunctionType*/) .build(), - /*isAsync*/ false, SILCoroutineKind::None, - ParameterConvention::Direct_Unowned, + SILCoroutineKind::None, ParameterConvention::Direct_Unowned, ArrayRef(), ArrayRef(), ResultInfoArray, None, SubstitutionMap(), SubstitutionMap(), getFunction()->getModule().getASTContext()); diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 304ec2c2158b2..7740d0803b344 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -799,11 +799,10 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, // Use the new specialized generic signature. auto NewFnTy = SILFunctionType::get( - CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->isAsync(), - FnTy->getCoroutineKind(), FnTy->getCalleeConvention(), - FnTy->getParameters(), FnTy->getYields(), FnTy->getResults(), - FnTy->getOptionalErrorResult(), FnTy->getPatternSubstitutions(), - SubstitutionMap(), M.getASTContext(), + CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCoroutineKind(), + FnTy->getCalleeConvention(), FnTy->getParameters(), FnTy->getYields(), + FnTy->getResults(), FnTy->getOptionalErrorResult(), + FnTy->getPatternSubstitutions(), SubstitutionMap(), M.getASTContext(), FnTy->getWitnessMethodConformanceOrInvalid()); // This is an interface type. It should not have any archetypes. @@ -871,7 +870,7 @@ createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const { ? SubstFTy->getInvocationGenericSignature() : CanGenericSignature(); return SILFunctionType::get( - Signature, SubstFTy->getExtInfo(), SubstFTy->isAsync(), + Signature, SubstFTy->getExtInfo(), SubstFTy->getCoroutineKind(), SubstFTy->getCalleeConvention(), SpecializedParams, SpecializedYields, SpecializedResults, SubstFTy->getOptionalErrorResult(), SubstitutionMap(), SubstitutionMap(), diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index b1c81fb652151..3da17ed9989ec 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -860,12 +860,9 @@ namespace { } // Similarly, ".foo(...)" really applies two argument lists. - if (auto *unresolvedMemberExpr = dyn_cast(prev)) { - if (unresolvedMemberExpr->hasArguments() || - unresolvedMemberExpr->hasTrailingClosure()) - return 2; - return 1; - } + if (isa(prev) && + isa(cast(prev)->getFn())) + return 2; return getArgCount(maxArgCount); }(); @@ -2753,31 +2750,25 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { - // Dig out the type of the base, which will be the result type of this - // expression. If constraint solving resolved this to an UnresolvedType, - // then we're in an ambiguity tolerant mode used for diagnostic - // generation. Just leave this as an unresolved member reference. + // If constraint solving resolved this to an UnresolvedType, then we're in + // an ambiguity tolerant mode used for diagnostic generation. Just leave + // this as an unresolved member reference. Type resultTy = simplifyType(cs.getType(expr)); if (resultTy->hasUnresolvedType()) { cs.setType(expr, resultTy); return expr; } - Type baseTy = resultTy->getRValueType(); auto &ctx = cs.getASTContext(); - - // Find the selected member. + // Find the selected member and base type. auto memberLocator = cs.getConstraintLocator( expr, ConstraintLocator::UnresolvedMember); auto selected = solution.getOverloadChoice(memberLocator); - - // If the member came by optional unwrapping, then unwrap the base type. - if (selected.choice.getKind() - == OverloadChoiceKind::DeclViaUnwrappedOptional) { - baseTy = baseTy->getOptionalObjectType(); - assert(baseTy - && "got unwrapped optional decl from non-optional base?!"); - } + + // Unresolved member lookup always happens in a metatype so dig out the + // instance type. + auto baseTy = selected.choice.getBaseType()->getMetatypeInstanceType(); + baseTy = simplifyType(baseTy); // The base expression is simply the metatype of the base type. // FIXME: This location info is bogus. @@ -2792,30 +2783,6 @@ namespace { if (!result) return nullptr; - auto getType = [&](Expr *E) -> Type { return cs.getType(E); }; - - // If there was an argument, apply it. - if (auto arg = expr->getArgument()) { - // Get the callee locator. Note this may be different to the locator for - // the member being referenced for things like callAsFunction. - auto *calleeLoc = cs.getCalleeLocator(exprLoc); - - // Build and finish the apply. - ApplyExpr *apply = CallExpr::create( - ctx, result, arg, expr->getArgumentLabels(), - expr->getArgumentLabelLocs(), expr->hasTrailingClosure(), - /*implicit=*/expr->isImplicit(), Type(), getType); - result = finishApply(apply, Type(), exprLoc, calleeLoc); - - // FIXME: Application could fail, because some of the solutions - // are not expressible in AST (yet?), like certain tuple-to-tuple - // conversions. Better solution here would be not to form solutions - // which couldn't be applied by e.g. detecting situations like that - // and inserting fixes early. - if (!result) - return nullptr; - } - // Check for ambiguous member if the base is an Optional if (baseTy->getOptionalObjectType()) { diagnoseAmbiguousNominalMember(baseTy, result); @@ -3276,6 +3243,19 @@ namespace { return simplifyExprType(expr); } + Expr *visitUnresolvedMemberChainResultExpr( + UnresolvedMemberChainResultExpr *expr) { + // Since this expression only exists to give the result type of an + // unresolved member chain visibility in the AST, remove it from the AST + // now that we have a solution and coerce the subexpr to the resulting + // type. + auto *subExpr = expr->getSubExpr(); + auto type = simplifyType(cs.getType(expr)); + subExpr = coerceToType(subExpr, type, cs.getConstraintLocator(subExpr)); + cs.setType(subExpr, type); + return subExpr; + } + Expr *visitTupleExpr(TupleExpr *expr) { return simplifyExprType(expr); } @@ -4742,9 +4722,21 @@ namespace { KeyPathExpr::Component::forOptionalChain(objectTy, loc)); break; } - case KeyPathExpr::Component::Kind::OptionalForce: - buildKeyPathOptionalForceComponent(resolvedComponents); + case KeyPathExpr::Component::Kind::OptionalForce: { + // Handle force optional when it is the first component e.g. + // \String?.!.count + if (resolvedComponents.empty()) { + auto loc = origComponent.getLoc(); + auto objectTy = componentTy->getOptionalObjectType(); + assert(objectTy); + + resolvedComponents.push_back( + KeyPathExpr::Component::forOptionalForce(objectTy, loc)); + } else { + buildKeyPathOptionalForceComponent(resolvedComponents); + } break; + } case KeyPathExpr::Component::Kind::Invalid: { auto component = origComponent; component.setComponentType(leafTy); @@ -7672,6 +7664,8 @@ namespace { // "Mismatched types!"); assert(!exprType->hasTypeVariable() && "Should not write type variable into expression!"); + assert(!exprType->hasHole() && + "Should not write type holes into expression!"); expr->setType(exprType); if (auto kp = dyn_cast(expr)) { @@ -7681,6 +7675,8 @@ namespace { componentType = solution.simplifyType(cs.getType(kp, i)); assert(!componentType->hasTypeVariable() && "Should not write type variable into key-path component"); + assert(!componentType->hasHole() && + "Should not write type hole into key-path component"); kp->getMutableComponents()[i].setComponentType(componentType); } } diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 8919c9e352f4f..5f324d7579e64 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -56,8 +56,33 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings( auto &bindings = relatedBindings->getSecond(); - // Infer transitive protocol requirements. - llvm::copy(bindings.Protocols, std::back_inserter(Protocols)); + // FIXME: This is a workaround necessary because solver doesn't filter + // bindings based on protocol requirements placed on a type variable. + // + // Forward propagate (subtype -> supertype) only literal conformance + // requirements since that helps solver to infer more types at + // parameter positions. + // + // \code + // func foo(_: String, _: T) -> T { + // fatalError() + // } + // + // func bar(_: Any?) {} + // + // func test() { + // bar(foo("", "")) + // } + // \endcode + // + // If one of the literal arguments doesn't propagate its + // `ExpressibleByStringLiteral` conformance, we'd end up picking + // `T` with only one type `Any?` which is incorrect. + llvm::copy_if(bindings.Protocols, std::back_inserter(Protocols), + [](const Constraint *protocol) { + return protocol->getKind() == + ConstraintKind::LiteralConformsTo; + }); // Infer transitive defaults. llvm::copy(bindings.Defaults, std::back_inserter(Defaults)); @@ -335,7 +360,7 @@ void ConstraintSystem::PotentialBindings::finalize( if (locator->isLastElement()) PotentiallyIncomplete = true; - addPotentialBinding(PotentialBinding::forHole(cs.getASTContext(), locator)); + addPotentialBinding(PotentialBinding::forHole(TypeVar, locator)); } // Let's always consider `Any` to be a last resort binding because @@ -481,6 +506,7 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding( if (binding.Kind == AllowedBindingKind::Supertypes && !binding.BindingType->hasUnresolvedType() && !binding.BindingType->hasTypeVariable() && + !binding.BindingType->hasHole() && !binding.BindingType->hasUnboundGenericType() && !binding.hasDefaultedLiteralProtocol() && !binding.isDefaultableBinding() && allowJoinMeet) { @@ -905,15 +931,7 @@ bool ConstraintSystem::PotentialBindings::infer( case ConstraintKind::ConformsTo: case ConstraintKind::SelfObjectOfProtocol: - // Swift 3 allowed the use of default types for normal conformances - // to expressible-by-literal protocols. - if (cs.getASTContext().LangOpts.EffectiveLanguageVersion[0] >= 4) - return false; - - if (!constraint->getSecondType()->is()) - return false; - - LLVM_FALLTHROUGH; + return false; case ConstraintKind::LiteralConformsTo: { // Record constraint where protocol requirement originated diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index d6ad205c17218..1006542d8324a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -17,8 +17,10 @@ #include "CSDiagnostics.h" #include "ConstraintSystem.h" #include "MiscDiagnostics.h" +#include "TypeCheckProtocol.h" #include "TypoCorrection.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" @@ -755,6 +757,11 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + diagnostic = diag::cannot_convert_chain_result_type; + break; + } + default: break; } @@ -1071,9 +1078,6 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { return false; auto sourceRange = getSourceRange(); - - emitDiagnostic(diag::optional_base_not_unwrapped, - baseType, Member, unwrappedBaseType); auto componentPathElt = locator->getLastElementAs(); @@ -1082,12 +1086,25 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() { // let's emit a tailored note suggesting to use its unwrapped type. auto *keyPathExpr = castToExpr(getAnchor()); if (auto rootType = keyPathExpr->getRootType()) { + emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member, + unwrappedBaseType); + emitDiagnostic(diag::optional_base_remove_optional_for_keypath_root, unwrappedBaseType) .fixItReplace(rootType->getSourceRange(), unwrappedBaseType.getString()); + } else { + emitDiagnostic(diag::invalid_optional_infered_keypath_root, baseType, + Member, unwrappedBaseType); + emitDiagnostic(diag::optional_key_path_root_base_chain, Member) + .fixItInsert(sourceRange.End, "?."); + emitDiagnostic(diag::optional_key_path_root_base_unwrap, Member) + .fixItInsert(sourceRange.End, "!."); } } else { + emitDiagnostic(diag::optional_base_not_unwrapped, baseType, Member, + unwrappedBaseType); + // FIXME: It would be nice to immediately offer "base?.member ?? defaultValue" // for non-optional results where that would be appropriate. For the moment // always offering "?" means that if the user chooses chaining, we'll end up @@ -1126,6 +1143,8 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt( bool needsParensInside = exprNeedsParensBeforeAddingNilCoalescing(DC, const_cast(expr)); auto parentExpr = findParentExpr(anchor); + if (parentExpr && isa(parentExpr)) + parentExpr = findParentExpr(parentExpr); bool needsParensOutside = exprNeedsParensAfterAddingNilCoalescing( DC, const_cast(expr), parentExpr); @@ -1200,14 +1219,6 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { auto *anchor = castToExpr(getAnchor()); - // If this is an unresolved member expr e.g. `.foo` its - // base type is going to be the same as result type minus - // r-value adjustment because base could be an l-value type. - // We want to fix both cases by only diagnose one of them, - // otherwise this is just going to result in a duplcate diagnostic. - if (getLocator()->isLastElement()) - return false; - if (auto assignExpr = dyn_cast(anchor)) anchor = assignExpr->getSrc(); @@ -1237,8 +1248,10 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() { assert(!baseType->hasTypeVariable() && "Base type must not be a type variable"); + assert(!baseType->isHole() && "Base type must not be a type hole"); assert(!unwrappedType->hasTypeVariable() && "Unwrapped type must not be a type variable"); + assert(!unwrappedType->isHole() && "Unwrapped type must not be a type hole"); if (!baseType->getOptionalObjectType()) return false; @@ -1315,6 +1328,11 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { if (getContextualTypePurpose(diagExpr) == CTP_Condition) return false; + // If the failure happened at the end of an unresolved member chain, it should + // be diagnosed instead as though it happened at the last element. + if (auto chainExpr = dyn_cast(diagExpr)) + diagExpr = chainExpr->getSubExpr(); + if (auto assignExpr = dyn_cast(diagExpr)) { // Let's check whether this is an attempt to assign // variable or property to itself. @@ -1438,6 +1456,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { } } else if (isa(diagExpr)) { subElementDiagID = diag::assignment_subscript_has_immutable_base; + } else if (auto *UME = dyn_cast(diagExpr)) { + subElementDiagID = diag::assignment_lhs_is_immutable_property; } else { subElementDiagID = diag::assignment_lhs_is_immutable_variable; } @@ -1904,6 +1924,18 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { return resolveImmutableBase(MRE->getBase()); } + if (auto *UME = dyn_cast(expr)) { + auto loc = getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); + auto member = getMemberRef(loc); + + // If we can resolve a member, we can determine whether it is settable in + // this context. + if (member && member->isDecl() && isImmutable(member->getDecl())) + return {expr, member}; + else + return {expr, None}; + } + if (auto *DRE = dyn_cast(expr)) return {expr, OverloadChoice(Type(), DRE->getDecl(), FunctionRefKind::Unapplied)}; @@ -2137,10 +2169,11 @@ bool ContextualFailure::diagnoseAsError() { return false; } - case ConstraintLocator::RValueAdjustment: { + case ConstraintLocator::UnresolvedMemberChainResult: { auto &solution = getSolution(); - auto overload = getOverloadChoiceIfAvailable( - getConstraintLocator(anchor, ConstraintLocator::UnresolvedMember)); + + auto overload = + getCalleeOverloadChoiceIfAvailable(getConstraintLocator(anchor)); if (!(overload && overload->choice.isDecl())) return false; @@ -2175,13 +2208,22 @@ bool ContextualFailure::diagnoseAsError() { }); if (numMissingArgs == 0 || numMissingArgs > 1) { - auto diagnostic = emitDiagnostic( - diag::expected_parens_in_contextual_member, choice->getName()); - - // If there are no parameters we can suggest a fix-it - // to form an explicit call. - if (numMissingArgs == 0) - diagnostic.fixItInsertAfter(getSourceRange().End, "()"); + auto applyFixIt = [&](InFlightDiagnostic &diagnostic) { + // If there are no parameters we can suggest a fix-it + // to form an explicit call. + if (numMissingArgs == 0) + diagnostic.fixItInsertAfter(getSourceRange().End, "()"); + }; + if (fnType->getResult()->isEqual(toType)) { + auto diag = emitDiagnostic( + diag::expected_parens_in_contextual_member_type, + choice->getName(), fnType->getResult()); + applyFixIt(diag); + } else { + auto diag = emitDiagnostic(diag::expected_parens_in_contextual_member, + choice->getName()); + applyFixIt(diag); + } } else { emitDiagnostic(diag::expected_argument_in_contextual_member, choice->getName(), params.front().getPlainType()); @@ -2400,6 +2442,10 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const { if (getLocator()->isLastElement()) return false; + if (getLocator() + ->isLastElement()) + return false; + auto *srcFT = getFromType()->getAs(); if (!srcFT || !(srcFT->getParams().empty() || @@ -2770,9 +2816,11 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Let's build a list of protocols that the context does not conform to. SmallVector missingProtoTypeStrings; + SmallVector missingProtocols; for (auto protocol : layout.getProtocols()) { if (!TypeChecker::conformsToProtocol(fromType, protocol->getDecl(), getDC())) { missingProtoTypeStrings.push_back(protocol->getString()); + missingProtocols.push_back(protocol->getDecl()); } } @@ -2794,8 +2842,6 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Emit a diagnostic to inform the user that they need to conform to the // missing protocols. - // - // TODO: Maybe also insert the requirement stubs? auto conformanceDiag = emitDiagnostic(diag::assign_protocol_conformance_fix_it, unwrappedToType, nominal->getDescriptiveKind(), fromType); @@ -2810,6 +2856,35 @@ bool ContextualFailure::tryProtocolConformanceFixIt( conformanceDiag.fixItInsert(nameEndLoc, ": " + protoString); } + // Emit fix-its to insert requirement stubs if we're in editor mode. + if (!getASTContext().LangOpts.DiagnosticsEditorMode) { + return true; + } + + { + llvm::SmallString<128> Text; + llvm::raw_svector_ostream SS(Text); + llvm::SetVector missingWitnesses; + for (auto protocol : missingProtocols) { + auto conformance = NormalProtocolConformance( + nominal->getDeclaredType(), protocol, SourceLoc(), nominal, + ProtocolConformanceState::Incomplete); + ConformanceChecker checker(getASTContext(), &conformance, + missingWitnesses); + checker.resolveValueWitnesses(); + checker.resolveTypeWitnesses(); + } + + for (auto decl : missingWitnesses) { + swift::printRequirementStub(decl, nominal, nominal->getDeclaredType(), + nominal->getStartLoc(), SS); + } + + if (!Text.empty()) { + conformanceDiag.fixItInsertAfter(nominal->getBraces().Start, Text.str()); + } + } + return true; } @@ -3413,6 +3488,13 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const { if (!(parentExpr && isa(expr))) return false; + if (!isa(parentExpr)) + return false; + + parentExpr = findParentExpr(parentExpr); + if (!parentExpr) + return false; + auto parentType = getType(parentExpr); if (!parentType->isKnownStdlibCollectionType() && !parentType->is()) @@ -4429,9 +4511,6 @@ MissingArgumentsFailure::getCallInfo(ASTNode anchor) const { return std::make_tuple(call->getFn(), call->getArg(), call->getNumArguments(), call->getUnlabeledTrailingClosureIndex()); - } else if (auto *UME = getAsExpr(anchor)) { - return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(), - UME->getUnlabeledTrailingClosureIndex()); } else if (auto *SE = getAsExpr(anchor)) { return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), SE->getUnlabeledTrailingClosureIndex()); @@ -5059,7 +5138,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() { // holes present in the contextual type. if (FailureDiagnostic::getContextualTypePurpose(getAnchor()) == ContextualTypePurpose::CTP_ForEachStmt && - contextualType->hasHole()) { + contextualType->hasUnresolvedType()) { diagnostic.emplace(emitDiagnostic( (contextualType->is() && !eltType->is()) ? diag::cannot_match_expr_tuple_pattern_with_nontuple_value @@ -6270,6 +6349,20 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { // Member reference could be wrapped into a number of parens // e.g. `((.foo))`. auto *parentExpr = findParentExpr(anchor); + + // Look through immediate call of unresolved member (e.g., `.foo(0)`). + if (parentExpr && isa(parentExpr)) + parentExpr = findParentExpr(parentExpr); + + // FIXME: We should probably look through the entire member chain so that + // something like `let _ = .foo().bar` gets the "no contextual type" error + // rather than the "Cannot infer contextual base" error. + UnresolvedMemberChainResultExpr *resultExpr = nullptr; + if (parentExpr && isa(parentExpr)) { + resultExpr = cast(parentExpr); + parentExpr = findParentExpr(parentExpr); + } + do { // If we have found something which isn't a paren let's stop, // otherwise let's keep unwrapping until there are either no @@ -6278,7 +6371,7 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() { break; } while ((parentExpr = findParentExpr(parentExpr))); - auto diagnostic = parentExpr || getContextualType(anchor) + auto diagnostic = parentExpr || (resultExpr && getContextualType(resultExpr)) ? diag::cannot_infer_base_of_unresolved_member : diag::unresolved_member_no_inference; @@ -6317,7 +6410,7 @@ bool UnableToInferClosureParameterType::diagnoseAsError() { if (parentExpr) { // Missing or invalid member reference in call. if (auto *AE = dyn_cast(parentExpr)) { - if (getType(AE->getFn())->isHole()) + if (getType(AE->getFn())->is()) return false; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index e1c925322d495..956c91736dd0e 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -94,20 +94,26 @@ class FailureDiagnostic { /// Resolve type variables present in the raw type, if any. Type resolveType(Type rawType, bool reconstituteSugar = false, bool wantRValue = true) const { - if (!rawType->hasTypeVariable()) { - if (reconstituteSugar) - rawType = rawType->reconstituteSugar(/*recursive*/ true); - return wantRValue ? rawType->getRValueType() : rawType; + auto &cs = getConstraintSystem(); + + if (rawType->hasTypeVariable() || rawType->hasHole()) { + rawType = rawType.transform([&](Type type) { + if (auto *typeVar = type->getAs()) { + auto resolvedType = S.simplifyType(typeVar); + Type GP = typeVar->getImpl().getGenericParameter(); + return resolvedType->is() && GP + ? GP + : resolvedType; + } + + return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType) + : type; + }); } - auto &cs = getConstraintSystem(); - return cs.simplifyTypeImpl(rawType, [&](TypeVariableType *typeVar) -> Type { - auto fixed = S.simplifyType(typeVar); - auto *genericParam = typeVar->getImpl().getGenericParameter(); - if (fixed->isHole() && genericParam) - return genericParam; - return resolveType(fixed, reconstituteSugar, wantRValue); - }); + if (reconstituteSugar) + rawType = rawType->reconstituteSugar(/*recursive*/ true); + return wantRValue ? rawType->getRValueType() : rawType; } template diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index da230d48f2f51..cab9af330dbef 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -792,6 +792,10 @@ namespace { /// Keep track of acceptable DiscardAssignmentExpr's. llvm::SmallPtrSet CorrectDiscardAssignmentExprs; + /// A map from each UnresolvedMemberExpr to the respective (implicit) base + /// found during our walk. + llvm::MapVector UnresolvedBaseTypes; + /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) { @@ -1422,15 +1426,21 @@ namespace { Type visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) { llvm_unreachable("Already typechecked"); } + + void setUnresolvedBaseType(UnresolvedMemberExpr *UME, Type ty) { + UnresolvedBaseTypes.insert({UME, ty}); + } + + Type getUnresolvedBaseType(UnresolvedMemberExpr *UME) { + auto result = UnresolvedBaseTypes.find(UME); + assert(result != UnresolvedBaseTypes.end()); + return result->second; + } virtual Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { auto baseLocator = CS.getConstraintLocator( expr, ConstraintLocator::MemberRefBase); - FunctionRefKind functionRefKind = - expr->getArgument() ? FunctionRefKind::DoubleApply - : FunctionRefKind::Compound; - auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); @@ -1438,6 +1448,8 @@ namespace { // should be marked as a potential hole. auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape | TVO_CanBindToHole); + setUnresolvedBaseType(expr, baseTy); + auto memberTy = CS.createTypeVariable( memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); @@ -1450,54 +1462,38 @@ namespace { // member, i.e., an enum case or a static variable. auto baseMetaTy = MetatypeType::get(baseTy); CS.addUnresolvedValueMemberConstraint(baseMetaTy, expr->getName(), - memberTy, CurDC, functionRefKind, + memberTy, CurDC, + expr->getFunctionRefKind(), memberLocator); + return memberTy; + } - // If there is an argument, apply it. - if (auto arg = expr->getArgument()) { - // The result type of the function must be convertible to the base type. - // TODO: we definitely want this to include ImplicitlyUnwrappedOptional; - // does it need to include everything else in the world? - auto outputTy = CS.createTypeVariable( - CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); - CS.addConstraint(ConstraintKind::Conversion, outputTy, baseTy, - CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); - - // The function/enum case must be callable with the given argument. - - // FIXME: Redesign the AST so that an UnresolvedMemberExpr directly - // stores a list of arguments together with their inout-ness, instead of - // a single ParenExpr or TupleExpr argument. - SmallVector params; - AnyFunctionType::decomposeInput(CS.getType(arg), params); - - CS.addConstraint(ConstraintKind::ApplicableFunction, - FunctionType::get(params, outputTy), - memberTy, - CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); - - associateArgumentLabels( - CS.getConstraintLocator(expr), - {expr->getArgumentLabels(), - expr->getUnlabeledTrailingClosureIndex()}); - return baseTy; - } + Type visitUnresolvedMemberChainResultExpr( + UnresolvedMemberChainResultExpr *expr) { + auto *tail = expr->getSubExpr(); + auto memberTy = CS.getType(tail); + auto *base = expr->getChainBase(); + assert(base == TypeChecker::getUnresolvedMemberChainBase(tail)); + + // The result type of the chain is is represented by a new type variable. + auto locator = CS.getConstraintLocator( + expr, ConstraintLocator::UnresolvedMemberChainResult); + auto chainResultTy = CS.createTypeVariable( + locator, + TVO_CanBindToLValue | TVO_CanBindToHole | TVO_CanBindToNoEscape); + auto chainBaseTy = getUnresolvedBaseType(base); + + // The result of the last element of the chain must be convertible to the + // whole chain, and the type of the whole chain must be equal to the base. + CS.addConstraint( + ConstraintKind::Conversion, memberTy, chainBaseTy, + CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); + CS.addConstraint(ConstraintKind::Conversion, memberTy, chainResultTy, + locator); + CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, + locator); - // Otherwise, the member needs to be convertible to the base type. - CS.addConstraint(ConstraintKind::Conversion, memberTy, baseTy, - CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); - - // The member type also needs to be convertible to the context type, which - // preserves lvalue-ness. - auto resultTy = CS.createTypeVariable(memberLocator, - TVO_CanBindToLValue | - TVO_CanBindToNoEscape); - CS.addConstraint(ConstraintKind::Conversion, memberTy, resultTy, - memberLocator); - CS.addConstraint(ConstraintKind::Equal, resultTy, baseTy, - memberLocator); - return resultTy; + return chainResultTy; } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { @@ -2062,48 +2058,38 @@ namespace { // parameter or return type is omitted, a fresh type variable is used to // stand in for that parameter or return type, allowing it to be inferred // from context. - auto getExplicitResultType = [&]() -> Type { - if (!closure->hasExplicitResultType()) { - return Type(); - } + Type resultTy = [&] { + if (closure->hasExplicitResultType()) { + if (auto declaredTy = closure->getExplicitResultType()) { + return declaredTy; + } - if (auto declaredTy = closure->getExplicitResultType()) { - return declaredTy; + const auto resolvedTy = resolveTypeReferenceInExpression( + closure->getExplicitResultTypeRepr(), + TypeResolverContext::InExpression, + // Introduce type variables for unbound generics. + OpenUnboundGenericType( + CS, CS.getConstraintLocator( + closure, ConstraintLocator::ClosureResult))); + if (resolvedTy) + return resolvedTy; } - return resolveTypeReferenceInExpression( - closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, nullptr); - }; - - Type resultTy; - auto *resultLoc = - CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult); - if (auto explicityTy = getExplicitResultType()) { - resultTy = explicityTy; - } else { - auto getContextualResultType = [&]() -> Type { - if (auto contextualType = CS.getContextualType(closure)) { - if (auto fnType = contextualType->getAs()) - return fnType->getResult(); - } - return Type(); - }; - - if (auto contextualResultTy = getContextualResultType()) { - resultTy = contextualResultTy; - } else { - // If no return type was specified, create a fresh type - // variable for it and mark it as possible hole. - // - // If this is a multi-statement closure, let's mark result - // as potential hole right away. - resultTy = CS.createTypeVariable( - resultLoc, - shouldTypeCheckInEnclosingExpression(closure) - ? 0 : TVO_CanBindToHole); + if (auto contextualType = CS.getContextualType(closure)) { + if (auto fnType = contextualType->getAs()) + return fnType->getResult(); } - } + + // If no return type was specified, create a fresh type + // variable for it and mark it as possible hole. + // + // If this is a multi-statement closure, let's mark result + // as potential hole right away. + return Type(CS.createTypeVariable( + CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult), + shouldTypeCheckInEnclosingExpression(closure) ? 0 + : TVO_CanBindToHole)); + }(); return FunctionType::get(closureParams, resultTy, extInfo); } @@ -3691,6 +3677,7 @@ namespace { if (CG.getConstraintSystem().shouldReusePrecheckedType()) { if (expr->getType()) { assert(!expr->getType()->hasTypeVariable()); + assert(!expr->getType()->hasHole()); CG.getConstraintSystem().cacheType(expr); return { false, expr }; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1608f19e49155..1ea9cf08b296a 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4306,22 +4306,18 @@ bool ConstraintSystem::repairFailures( break; } - // Unresolved member type mismatches are handled when - // r-value adjustment constraint fails. - case ConstraintLocator::UnresolvedMember: + case ConstraintLocator::RValueAdjustment: return true; - case ConstraintLocator::RValueAdjustment: { - if (!isExpr(anchor)) - break; - + case ConstraintLocator::UnresolvedMemberChainResult: { if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, locator)) break; - // r-value adjustment is used to connect base type of - // unresolved member to its output type, if there is - // a type mismatch here it's contextual e.g. + if (repairByTreatingRValueAsLValue(lhs, rhs)) + break; + + // If there is a type mismatch here it's contextual e.g., // `let x: E = .foo(42)`, where `.foo` is a member of `E` // but produces an incorrect type. auto *fix = IgnoreContextualType::create(*this, lhs, rhs, @@ -4434,6 +4430,12 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::FunctionBuilderBodyResult: { + // If result type of the body couldn't be determined + // there is going to be other fix available to diagnose + // the underlying issue. + if (lhs->isHole()) + return true; + conversionsOrFixes.push_back(ContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); break; @@ -4687,6 +4689,17 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::Unresolved: return getTypeMatchFailure(locator); + case TypeKind::Hole: { + // If it's allowed to attempt fixes, let's delegate + // decision to `repairFailures`, since depending on + // locator we might either ignore such a mismatch, + // or record a specialized fix. + if (shouldAttemptFixes()) + break; + + return getTypeMatchFailure(locator); + } + case TypeKind::GenericTypeParam: llvm_unreachable("unmapped dependent type in type checker"); @@ -5366,6 +5379,7 @@ ConstraintSystem::simplifyConstructionConstraint( case TypeKind::Unresolved: case TypeKind::Error: + case TypeKind::Hole: return SolutionKind::Error; case TypeKind::GenericFunction: @@ -6759,28 +6773,39 @@ static ConstraintFix *validateInitializerRef(ConstraintSystem &cs, } else if (auto *CE = getAsExpr(anchor)) { baseExpr = CE->getFn(); baseType = getType(baseExpr); - // If this is an initializer call without explicit mention - // of `.init` on metatype value. - if (auto *AMT = baseType->getAs()) { - auto instanceType = AMT->getInstanceType()->getWithoutParens(); - if (!cs.isTypeReference(baseExpr)) { - if (baseType->is() && - instanceType->isAnyExistentialType()) { - return AllowInvalidInitRef::onProtocolMetatype( - cs, baseType, init, cs.isStaticallyDerivedMetatype(baseExpr), - baseExpr->getSourceRange(), locator); - } + // FIXME: Historically, UnresolvedMemberExprs have allowed implicit + // construction through a metatype value, but this should probably be + // illegal. + if (!isa(baseExpr)) { + // If this is an initializer call without explicit mention + // of `.init` on metatype value. + if (auto *AMT = baseType->getAs()) { + auto instanceType = AMT->getInstanceType()->getWithoutParens(); + if (!cs.isTypeReference(baseExpr)) { + if (baseType->is() && + instanceType->isAnyExistentialType()) { + return AllowInvalidInitRef::onProtocolMetatype( + cs, baseType, init, cs.isStaticallyDerivedMetatype(baseExpr), + baseExpr->getSourceRange(), locator); + } - if (!instanceType->isExistentialType() || - instanceType->isAnyExistentialType()) { - return AllowInvalidInitRef::onNonConstMetatype(cs, baseType, init, - locator); + if (!instanceType->isExistentialType() || + instanceType->isAnyExistentialType()) { + return AllowInvalidInitRef::onNonConstMetatype(cs, baseType, init, + locator); + } } } } // Initializer reference which requires contextual base type e.g. - // `.init(...)`. + // `.init(...)`. Could also be a nested type or typealias being constructed + // via implicit member syntax, e.g., `let _: Base = .Nested()` where + // `Base.Nested: Base`. } else if (auto *UME = getAsExpr(anchor)) { + // If we're accessing a nested type to perform the construction implicitly, + // then the type we're constructing may not actually be the base of the + // UnresolvedMemberExpr--instead, it will be the type of the nested type + // member. // We need to find type variable which represents contextual base. auto *baseLocator = cs.getConstraintLocator( UME, locatorEndsWith(locator, ConstraintLocator::ConstructorMember) @@ -10657,7 +10682,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { case ConstraintKind::OptionalObject: return simplifyOptionalObjectConstraint(constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::ValueMember: @@ -10669,8 +10694,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getMemberUseDC(), constraint.getFunctionRefKind(), /*outerAlternatives=*/{}, - TMF_GenerateConstraints, - constraint.getLocator()); + /*flags*/ None, constraint.getLocator()); case ConstraintKind::ValueWitness: return simplifyValueWitnessConstraint(constraint.getKind(), @@ -10679,20 +10703,20 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getSecondType(), constraint.getMemberUseDC(), constraint.getFunctionRefKind(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::Defaultable: return simplifyDefaultableConstraint(constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::DefaultClosureType: return simplifyDefaultClosureTypeConstraint(constraint.getFirstType(), constraint.getSecondType(), constraint.getTypeVariables(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::FunctionInput: @@ -10700,7 +10724,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyFunctionComponentConstraint(constraint.getKind(), constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, + /*flags*/ None, constraint.getLocator()); case ConstraintKind::Disjunction: @@ -10712,8 +10736,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyOneWayConstraint(constraint.getKind(), constraint.getFirstType(), constraint.getSecondType(), - TMF_GenerateConstraints, - constraint.getLocator()); + /*flags*/ None, constraint.getLocator()); } llvm_unreachable("Unhandled ConstraintKind in switch."); diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index c5b4a864e4e05..708d90d7dc6de 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -81,6 +81,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const { case ConstraintLocator::TernaryBranch: case ConstraintLocator::PatternMatch: case ConstraintLocator::ArgumentAttribute: + case ConstraintLocator::UnresolvedMemberChainResult: return 0; case ConstraintLocator::FunctionArgument: @@ -483,6 +484,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { break; } + + case UnresolvedMemberChainResult: + out << "unresolved chain result"; + break; } } out << ']'; diff --git a/lib/Sema/ConstraintLocatorPathElts.def b/lib/Sema/ConstraintLocatorPathElts.def index 67228bcbc5591..435d20b74ec9f 100644 --- a/lib/Sema/ConstraintLocatorPathElts.def +++ b/lib/Sema/ConstraintLocatorPathElts.def @@ -192,6 +192,9 @@ CUSTOM_LOCATOR_PATH_ELT(PatternMatch) /// of a problem. CUSTOM_LOCATOR_PATH_ELT(ArgumentAttribute) +/// The result of a chain of member accesses off an UnresolvedMemberExpr +SIMPLE_LOCATOR_PATH_ELT(UnresolvedMemberChainResult) + #undef LOCATOR_PATH_ELT #undef CUSTOM_LOCATOR_PATH_ELT #undef SIMPLE_LOCATOR_PATH_ELT diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 7106adf24404a..7fb88905141f0 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -562,21 +562,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( } if (auto *UME = getAsExpr(anchor)) { - auto *calleeLoc = - getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); - - // Handle special cases for applies of non-function types. - // FIXME: Consider re-designing the AST such that an unresolved member expr - // with arguments uses a CallExpr, which would make this logic unnecessary - // and clean up a bunch of other special cases. Doing so may require a bit - // of hacking in CSGen though. - if (UME->hasArguments()) { - if (auto overload = getOverloadFor(calleeLoc)) { - if (auto *loc = getSpecialFnCalleeLoc(overload->boundType)) - return loc; - } - } - return calleeLoc; + return getConstraintLocator(UME, ConstraintLocator::UnresolvedMember); } if (isExpr(anchor)) @@ -2620,11 +2606,13 @@ Type ConstraintSystem::simplifyTypeImpl(Type type, // there will be a missing conformance fix applied in diagnostic mode, // so the concrete dependent member type is considered a "hole" in // order to continue solving. + auto memberTy = DependentMemberType::get(lookupBaseType, assocType); if (shouldAttemptFixes() && - getPhase() == ConstraintSystemPhase::Solving) - return getASTContext().TheUnresolvedType; + getPhase() == ConstraintSystemPhase::Solving) { + return HoleType::get(getASTContext(), memberTy); + } - return DependentMemberType::get(lookupBaseType, assocType); + return memberTy; } auto subs = SubstitutionMap::getProtocolSubstitutions( @@ -2656,16 +2644,23 @@ Type ConstraintSystem::simplifyType(Type type) const { } Type Solution::simplifyType(Type type) const { - if (!type->hasTypeVariable()) + if (!(type->hasTypeVariable() || type->hasHole())) return type; // Map type variables to fixed types from bindings. - return getConstraintSystem().simplifyTypeImpl(type, - [&](TypeVariableType *tvt) -> Type { - auto known = typeBindings.find(tvt); - assert(known != typeBindings.end()); - return known->second; - }); + auto &cs = getConstraintSystem(); + auto resolvedType = cs.simplifyTypeImpl( + type, [&](TypeVariableType *tvt) -> Type { return getFixedType(tvt); }); + + // Holes shouldn't be reachable through a solution, they are only + // useful to determine what went wrong exactly. + if (resolvedType->hasHole()) { + return resolvedType.transform([&](Type type) { + return type->isHole() ? Type(cs.getASTContext().TheUnresolvedType) : type; + }); + } + + return resolvedType; } size_t Solution::getTotalMemory() const { @@ -3171,9 +3166,7 @@ static bool diagnoseAmbiguityWithContextualType( auto type = solution.simplifyType(overload.boundType); - if (isExpr(anchor) || isExpr(anchor) || - (isExpr(anchor) && - castToExpr(anchor)->hasArguments())) { + if (isExpr(anchor) || isExpr(anchor)) { auto fnType = type->castTo(); DE.diagnose( loc, diag::cannot_convert_candidate_result_to_contextual_type, @@ -3683,11 +3676,6 @@ void constraints::simplifyLocator(ASTNode &anchor, continue; } - if (auto *UME = getAsExpr(anchor)) { - anchor = UME->getArgument(); - path = path.slice(1); - continue; - } break; } @@ -3697,6 +3685,7 @@ void constraints::simplifyLocator(ASTNode &anchor, } case ConstraintLocator::ApplyFunction: + case ConstraintLocator::FunctionResult: // Extract application function. if (auto applyExpr = getAsExpr(anchor)) { anchor = applyExpr->getFn(); @@ -3711,15 +3700,6 @@ void constraints::simplifyLocator(ASTNode &anchor, continue; } - // The unresolved member itself is the function. - if (auto unresolvedMember = getAsExpr(anchor)) { - if (unresolvedMember->getArgument()) { - anchor = unresolvedMember; - path = path.slice(1); - continue; - } - } - break; case ConstraintLocator::AutoclosureResult: @@ -3876,6 +3856,13 @@ void constraints::simplifyLocator(ASTNode &anchor, break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + auto *resultExpr = castToExpr(anchor); + anchor = resultExpr->getSubExpr(); + path = path.slice(1); + continue; + } + default: // FIXME: Lots of other cases to handle. break; @@ -3908,8 +3895,6 @@ Expr *constraints::getArgumentExpr(ASTNode node, unsigned index) { Expr *argExpr = nullptr; if (auto *AE = dyn_cast(expr)) argExpr = AE->getArg(); - else if (auto *UME = dyn_cast(expr)) - argExpr = UME->getArgument(); else if (auto *SE = dyn_cast(expr)) argExpr = SE->getIndex(); else @@ -4664,7 +4649,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization( // Determine the contextual type for the initialization. TypeLoc contextualType; if (!(isa(pattern) && !pattern->isImplicit()) && - patternType && !patternType->isHole()) { + patternType && !patternType->is()) { contextualType = TypeLoc::withoutLoc(patternType); // Only provide a TypeLoc if it makes sense to allow diagnostics. diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index bc95ed45c0b55..18579bfc857a8 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -4564,9 +4564,10 @@ class ConstraintSystem { return {type, kind, BindingSource}; } - static PotentialBinding forHole(ASTContext &ctx, + static PotentialBinding forHole(TypeVariableType *typeVar, ConstraintLocator *locator) { - return {ctx.TheUnresolvedType, AllowedBindingKind::Exact, + return {HoleType::get(typeVar->getASTContext(), typeVar), + AllowedBindingKind::Exact, /*source=*/locator}; } }; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 2f8c065c49e75..aa649dec03bc5 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -320,14 +320,17 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) { llvm_unreachable("unhandled attribute kind"); } + auto DC = FD->getDeclContext(); // mutation attributes may only appear in type context. - if (auto contextTy = FD->getDeclContext()->getDeclaredInterfaceType()) { + if (auto contextTy = DC->getDeclaredInterfaceType()) { // 'mutating' and 'nonmutating' are not valid on types // with reference semantics. if (contextTy->hasReferenceSemantics()) { - if (attrModifier != SelfAccessKind::Consuming) + if (attrModifier != SelfAccessKind::Consuming) { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_classes, - attrModifier); + attrModifier, FD->getDescriptiveKind(), + DC->getSelfProtocolDecl() != nullptr); + } } } else { diagnoseAndRemoveAttr(attr, diag::mutating_invalid_global_scope, @@ -2901,18 +2904,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { auto nominal = evaluateOrDefault( Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); - // If there is no nominal type with this name, complain about this being - // an unknown attribute. if (!nominal) { - std::string typeName; - if (auto typeRepr = attr->getTypeRepr()) { - llvm::raw_string_ostream out(typeName); - typeRepr->print(out); - } else { - typeName = attr->getType().getString(); - } - - diagnose(attr->getLocation(), diag::unknown_attribute, typeName); attr->setInvalid(); return; } diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index 77a8222774652..6ba92aeb42dd4 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -416,6 +416,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, assert(exprType && !exprType->hasTypeVariable() && "free type variable with FreeTypeVariableBinding::GenericParameters?"); + assert(exprType && !exprType->hasHole() && + "type hole with FreeTypeVariableBinding::GenericParameters?"); if (exprType->hasError()) { recoverOriginalType(); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7eb6616d9a7d4..f0226a6d094e8 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -477,6 +477,46 @@ static bool findNonMembers(ArrayRef lookupResults, return AllDeclRefs; } +/// Find the next element in a chain of members. If this expression is (or +/// could be) the base of such a chain, this will return \c nullptr. +static Expr *getMemberChainSubExpr(Expr *expr) { + assert(expr && "getMemberChainSubExpr called with null expr!"); + if (auto *UDE = dyn_cast(expr)) { + return UDE->getBase(); + } else if (auto *CE = dyn_cast(expr)) { + return CE->getFn(); + } else if (auto *BOE = dyn_cast(expr)) { + return BOE->getSubExpr(); + } else if (auto *FVE = dyn_cast(expr)) { + return FVE->getSubExpr(); + } else if (auto *SE = dyn_cast(expr)) { + return SE->getBase(); + } else if (auto *CCE = dyn_cast(expr)) { + return CCE->getBase(); + } else { + return nullptr; + } +} + +UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase(Expr *expr) { + if (auto *subExpr = getMemberChainSubExpr(expr)) + return getUnresolvedMemberChainBase(subExpr); + else + return dyn_cast(expr); +} + +/// Whether this expression is a member of a member chain. +static bool isMemberChainMember(Expr *expr) { + return getMemberChainSubExpr(expr) != nullptr; +} +/// Whether this expression sits at the end of a chain of member accesses. +static bool isMemberChainTail(Expr *expr, Expr *parent) { + assert(expr && "isMemberChainTail called with null expr!"); + // If this expression's parent is not itself part of a chain (or, this expr + // has no parent expr), this must be the tail of the chain. + return parent == nullptr || !isMemberChainMember(parent); +} + /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used /// for the lookup. @@ -1085,13 +1125,6 @@ namespace { } } - // If this is an unresolved member with a call argument (e.g., - // .some(x)), record the argument expression. - if (auto unresolvedMember = dyn_cast(expr)) { - if (auto arg = unresolvedMember->getArgument()) - CallArgs.insert(arg); - } - // FIXME(diagnostics): `InOutType` could appear here as a result // of successful re-typecheck of the one of the sub-expressions e.g. // `let _: Int = { (s: inout S) in s.bar() }`. On the first @@ -1326,6 +1359,14 @@ namespace { if (auto *simplified = simplifyTypeConstructionWithLiteralArg(expr)) return simplified; + // If we find an unresolved member chain, wrap it in an + // UnresolvedMemberChainResultExpr (unless this has already been done). + auto *parent = Parent.getAsExpr(); + if (isMemberChainTail(expr, parent)) + if (auto *UME = TypeChecker::getUnresolvedMemberChainBase(expr)) + if (!parent || !isa(parent)) + return new (ctx) UnresolvedMemberChainResultExpr(expr, UME); + return expr; } diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index b02220919667d..1e5c3a571df6f 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -446,18 +446,12 @@ class ResolvePattern : public ASTVisitorgetArgument()) { - subPattern = getSubExprPattern(arg); - } - if (ume->getName().getBaseName().isSpecial()) return nullptr; return new (Context) EnumElementPattern(ume->getDotLoc(), ume->getNameLoc(), ume->getName(), - subPattern, ume); + nullptr, ume); } // Member syntax 'T.Element' forms a pattern if 'T' is an enum and the @@ -547,6 +541,18 @@ class ResolvePattern : public ASTVisitor(ce->getFn())) return nullptr; + if (isa(ce->getFn())) { + auto *P = visit(ce->getFn()); + if (!P) + return nullptr; + + auto *EEP = cast(P); + EEP->setSubPattern(getSubExprPattern(ce->getArg())); + EEP->setUnresolvedOriginalExpr(ce); + + return P; + } + SmallVector components; if (!ExprToIdentTypeRepr(components, Context).visit(ce->getFn())) return nullptr; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index cd43b00ccc3dd..2148b4104489b 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1749,7 +1749,6 @@ namespace { Type resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, - bool isAsync = false, SILCoroutineKind coroutineKind = SILCoroutineKind::None, SILFunctionType::ExtInfo extInfo @@ -2147,8 +2146,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, SILFunctionType::Representation rep; TypeRepr *witnessMethodProtocol = nullptr; - auto isAsync = attrs.has(TAK_async); - auto coroutineKind = SILCoroutineKind::None; if (attrs.has(TAK_yield_once)) { coroutineKind = SILCoroutineKind::YieldOnce; @@ -2227,10 +2224,11 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // [TODO: Store-SIL-Clang-type] auto extInfo = SILFunctionType::ExtInfoBuilder( rep, attrs.has(TAK_pseudogeneric), - attrs.has(TAK_noescape), diffKind, nullptr) + attrs.has(TAK_noescape), attrs.has(TAK_async), + diffKind, nullptr) .build(); - ty = resolveSILFunctionType(fnRepr, options, isAsync, coroutineKind, extInfo, + ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, calleeConvention, witnessMethodProtocol); if (!ty || ty->hasError()) return ty; @@ -2845,7 +2843,6 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, - bool isAsync, SILCoroutineKind coroutineKind, SILFunctionType::ExtInfo extInfo, ParameterConvention callee, @@ -3040,8 +3037,7 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, "found witness_method without matching conformance"); } - return SILFunctionType::get(genericSig, extInfo, isAsync, - coroutineKind, callee, + return SILFunctionType::get(genericSig, extInfo, coroutineKind, callee, interfaceParams, interfaceYields, interfaceResults, interfaceErrorResult, interfacePatternSubs, invocationSubs, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 5bf4b256902e7..df34417eb64ce 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1208,6 +1208,11 @@ bool requirePointerArgumentIntrinsics(ASTContext &ctx, SourceLoc loc); /// Require that the library intrinsics for creating /// array literals exist. bool requireArrayLiteralIntrinsics(ASTContext &ctx, SourceLoc loc); + +/// Gets the \c UnresolvedMemberExpr at the base of a chain of member accesses. +/// If \c expr is not part of a member chain or the base is something other than +/// an \c UnresolvedMemberExpr, \c nullptr is returned. +UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr); }; // namespace TypeChecker /// Temporary on-stack storage and unescaping for encoded diagnostic diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 0bb3cef17922d..724aef5da6b76 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1611,6 +1611,14 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { getXRefDeclNameForError()); } + if (memberName.getKind() == DeclBaseName::Kind::Destructor) { + assert(isa(nominal)); + // Force creation of an implicit destructor + auto CD = dyn_cast(nominal); + values.push_back(CD->getDestructor()); + break; + } + if (!privateDiscriminator.empty()) { ModuleDecl *searchModule = M; if (!searchModule) @@ -5405,21 +5413,18 @@ class TypeDeserializer { if (!diffKind.hasValue()) MF.fatal(); - const clang::FunctionType *clangFunctionType = nullptr; + const clang::Type *clangFunctionType = nullptr; if (clangFunctionTypeID) { auto clangType = MF.getClangType(clangFunctionTypeID); if (!clangType) return clangType.takeError(); - // FIXME: allow block pointers here. - clangFunctionType = - dyn_cast_or_null(clangType.get()); - if (!clangFunctionType) - MF.fatal(); + clangFunctionType = clangType.get(); } auto extInfo = SILFunctionType::ExtInfoBuilder(*representation, pseudogeneric, - noescape, *diffKind, clangFunctionType) + noescape, async, *diffKind, + clangFunctionType) .build(); // Process the coroutine kind. @@ -5568,8 +5573,7 @@ class TypeDeserializer { if (!patternSubsOrErr) return patternSubsOrErr.takeError(); - return SILFunctionType::get(invocationSig, extInfo, - async, coroutineKind.getValue(), + return SILFunctionType::get(invocationSig, extInfo, coroutineKind.getValue(), calleeConvention.getValue(), allParams, allYields, allResults, errorResult, diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index ab06b6189060f..fbe77f062b9b6 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -19,157 +19,81 @@ #include "swift/Basic/FileTypes.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Serialization/ModuleDependencyScanner.h" #include "swift/Subsystems.h" using namespace swift; using llvm::ErrorOr; -namespace { -/// A module "loader" that looks for .swiftinterface and .swiftmodule files -/// for the purpose of determining dependencies, but does not attempt to -/// load the module files. -class ModuleDependencyScanner : public SerializedModuleLoaderBase { - /// The module we're scanning dependencies of. - Identifier moduleName; - - /// Scan the given interface file to determine dependencies. - ErrorOr scanInterfaceFile( - Twine moduleInterfacePath, bool isFramework); - - InterfaceSubContextDelegate &astDelegate; -public: - Optional dependencies; - - /// Describes the kind of dependencies this scanner is able to identify - ModuleDependenciesKind dependencyKind; - - ModuleDependencyScanner( - ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName, - InterfaceSubContextDelegate &astDelegate, - ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift) - : SerializedModuleLoaderBase(ctx, nullptr, LoadMode, - /*IgnoreSwiftSourceInfoFile=*/true), - moduleName(moduleName), astDelegate(astDelegate), - dependencyKind(dependencyKind) {} - - virtual std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, - const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer, - bool IsFramework) override { - using namespace llvm::sys; - - auto &fs = *Ctx.SourceMgr.getFileSystem(); - - auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile); - auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile); - - if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) { - if (fs.exists(ModPath)) { - // The module file will be loaded directly. - auto dependencies = scanModuleFile(ModPath); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); - return std::error_code(); - } - return dependencies.getError(); - } else { - return std::make_error_code(std::errc::no_such_file_or_directory); +std::error_code ModuleDependencyScanner::findModuleFilesInDirectory( + AccessPathElem ModuleID, + const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + using namespace llvm::sys; + + auto &fs = *Ctx.SourceMgr.getFileSystem(); + + auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile); + auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile); + + if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) { + if (fs.exists(ModPath)) { + // The module file will be loaded directly. + auto dependencies = scanModuleFile(ModPath); + if (dependencies) { + this->dependencies = std::move(dependencies.get()); + return std::error_code(); } + return dependencies.getError(); + } else { + return std::make_error_code(std::errc::no_such_file_or_directory); } - assert(fs.exists(InPath)); - // Use the private interface file if exits. - auto PrivateInPath = - BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile); - if (fs.exists(PrivateInPath)) { - InPath = PrivateInPath; - } - auto dependencies = scanInterfaceFile(InPath, IsFramework); - if (dependencies) { - this->dependencies = std::move(dependencies.get()); - return std::error_code(); - } - - return dependencies.getError(); } - - virtual void collectVisibleTopLevelModuleNames( - SmallVectorImpl &names) const override { - llvm_unreachable("Not used"); + assert(fs.exists(InPath)); + // Use the private interface file if exits. + auto PrivateInPath = + BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile); + if (fs.exists(PrivateInPath)) { + InPath = PrivateInPath; } -}; - -/// A ModuleLoader that loads placeholder dependency module stubs specified in -/// -placeholder-dependency-module-map-file -/// This loader is used only in dependency scanning to inform the scanner that a -/// set of modules constitute placeholder dependencies that are not visible to the -/// scanner but will nevertheless be provided by the scanner's clients. -/// This "loader" will not attempt to load any module files. -class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner { - /// Scan the given placeholder module map - void parsePlaceholderModuleMap(StringRef fileName) { - ExplicitModuleMapParser parser(Allocator); - auto result = - parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap); - if (result == std::errc::invalid_argument) { - Ctx.Diags.diagnose(SourceLoc(), - diag::placeholder_dependency_module_map_corrupted, - fileName); - } - else if (result == std::errc::no_such_file_or_directory) { - Ctx.Diags.diagnose(SourceLoc(), - diag::placeholder_dependency_module_map_missing, - fileName); - } + auto dependencies = scanInterfaceFile(InPath, IsFramework); + if (dependencies) { + this->dependencies = std::move(dependencies.get()); + return std::error_code(); } - llvm::StringMap PlaceholderDependencyModuleMap; - llvm::BumpPtrAllocator Allocator; - -public: - PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode, - Identifier moduleName, - StringRef PlaceholderDependencyModuleMap, - InterfaceSubContextDelegate &astDelegate) - : ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate, - ModuleDependenciesKind::SwiftPlaceholder) { - - // FIXME: Find a better place for this map to live, to avoid - // doing the parsing on every module. - if (!PlaceholderDependencyModuleMap.empty()) { - parsePlaceholderModuleMap(PlaceholderDependencyModuleMap); - } - } + return dependencies.getError(); +} - std::error_code findModuleFilesInDirectory( - AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, - SmallVectorImpl *ModuleInterfacePath, - std::unique_ptr *ModuleBuffer, - std::unique_ptr *ModuleDocBuffer, - std::unique_ptr *ModuleSourceInfoBuffer, - bool IsFramework) override { - StringRef moduleName = ModuleID.Item.str(); - auto it = PlaceholderDependencyModuleMap.find(moduleName); - // If no placeholder module stub path is given matches the name, return with an - // error code. - if (it == PlaceholderDependencyModuleMap.end()) { - return std::make_error_code(std::errc::not_supported); - } - auto &moduleInfo = it->getValue(); - assert(!moduleInfo.moduleBuffer && - "Placeholder dependency module stubs cannot have an associated buffer"); - auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub( - moduleInfo.modulePath, moduleInfo.moduleDocPath, - moduleInfo.moduleSourceInfoPath); - this->dependencies = std::move(dependencies); - return std::error_code{}; +std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory( + AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, + SmallVectorImpl *ModuleInterfacePath, + std::unique_ptr *ModuleBuffer, + std::unique_ptr *ModuleDocBuffer, + std::unique_ptr *ModuleSourceInfoBuffer, + bool IsFramework) { + StringRef moduleName = ModuleID.Item.str(); + auto it = PlaceholderDependencyModuleMap.find(moduleName); + // If no placeholder module stub path is given matches the name, return with an + // error code. + if (it == PlaceholderDependencyModuleMap.end()) { + return std::make_error_code(std::errc::not_supported); } -}; -} // namespace + auto &moduleInfo = it->getValue(); + assert(!moduleInfo.moduleBuffer && + "Placeholder dependency module stubs cannot have an associated buffer"); + + auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub( + moduleInfo.modulePath, moduleInfo.moduleDocPath, + moduleInfo.moduleSourceInfoPath); + this->dependencies = std::move(dependencies); + return std::error_code{}; +} static std::vector getCompiledCandidates(ASTContext &ctx, StringRef moduleName, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 50a000ccb62ae..2b95150e58ff2 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 574; // reapply isUserAccessible +const uint16_t SWIFTMODULE_VERSION_MINOR = 575; // GlobalInitOnceFunction SILFunction purpose /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 79d2f87ebb7c4..2f40cc1a831f5 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3932,6 +3932,10 @@ class Serializer::TypeSerializer : public TypeVisitor { llvm_unreachable("should not serialize an invalid type"); } + void visitHoleType(const HoleType *) { + llvm_unreachable("should not serialize an invalid type"); + } + void visitModuleType(const ModuleType *) { llvm_unreachable("modules are currently not first-class values"); } diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index d469f67329008..d8b545c646460 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -2224,6 +2224,10 @@ - id: expected_parens_in_contextual_member msg: "member %0 is a function; did you mean to call it?" +- id: expected_parens_in_contextual_member_type + msg: >- + member %0 is a function that produces expected type %1; did you mean to call it? + - id: expected_result_in_contextual_member msg: "member %0 in %2 produces result of type %1, but context expects %2" @@ -2518,6 +2522,10 @@ - id: cannot_convert_parent_type msg: "cannot convert parent type %0 to expected type %1" +- id: cannot_convert_chain_result_type + msg: >- + member chain produces result of type %0 but contextual base was inferred as %1 + - id: generic_argument_mismatch msg: "arguments to generic parameter %0 (%1 and %2) are expected to be equal" @@ -3136,6 +3144,9 @@ - id: optional_base_not_unwrapped msg: "value of optional type %0 must be unwrapped to refer to member %1 of wrapped base type %2" +- id: invalid_optional_infered_keypath_root + msg: "key path root inferred as optional type %0 must be unwrapped to refer to member %1 of unwrapped type %2" + - id: optional_base_chain msg: "chain the optional using '?' to access member %0 only for non-'nil' base values" @@ -3145,6 +3156,12 @@ - id: optional_keypath_application_base msg: "use '?' to access key path subscript only for non-'nil' base values" +- id: optional_key_path_root_base_chain + msg: "chain the optional using '?.' to access unwrapped type member %0" + +- id: optional_key_path_root_base_unwrap + msg: "unwrap the optional using '!.' to access unwrapped type member %0" + - id: missing_unwrap_optional_try msg: "value of optional type %0 not unwrapped; did you mean to use 'try!' or chain with '?'?" @@ -3350,7 +3367,7 @@ msg: "%0 is only valid on methods" - id: mutating_invalid_classes - msg: "%0 isn't valid on methods in classes or class-bound protocols" + msg: "%0 is not valid on %1s in %select{classes|class-bound protocols}2" - id: functions_mutating_and_not msg: "method must not be declared both %0 and %1" diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index fab91273b97ec..d692ef67d1d70 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -21,18 +21,10 @@ option(SWIFT_RUNTIME_MACHO_NO_DYLD "Build stdlib assuming the runtime environment uses Mach-O but does not support dynamic modules." FALSE) -option(SWIFT_STDLIB_USE_NONATOMIC_RC - "Build the standard libraries and overlays with nonatomic reference count operations enabled" - FALSE) - option(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME - "Build the standard libraries assuming that they will be used in an environment with only a single thread. If set, also forces SWIFT_STDLIB_USE_NONATOMIC_RC to On." + "Build the standard libraries assuming that they will be used in an environment with only a single thread." FALSE) -if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) - set(SWIFT_STDLIB_USE_NONATOMIC_RC TRUE) -endif() - # # End of user-configurable options. # diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index a5b06685b8daa..2332ad6a224b1 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -306,10 +306,6 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_RUNTIME_MACHO_NO_DYLD") endif() - if(SWIFT_STDLIB_USE_NONATOMIC_RC) - list(APPEND result "-DSWIFT_STDLIB_USE_NONATOMIC_RC") - endif() - if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME") endif() diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index d4eab07932f37..0f2cf1e239a80 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -413,7 +413,7 @@ function(_compile_swift_files # SWIFT_ENABLE_TENSORFLOW END endif() - if(SWIFT_STDLIB_USE_NONATOMIC_RC) + if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) list(APPEND swift_flags "-Xfrontend" "-assume-single-threaded") endif() diff --git a/stdlib/public/Reflection/TypeRefBuilder.cpp b/stdlib/public/Reflection/TypeRefBuilder.cpp index 772afeb1e98f2..d811f53d89036 100644 --- a/stdlib/public/Reflection/TypeRefBuilder.cpp +++ b/stdlib/public/Reflection/TypeRefBuilder.cpp @@ -135,7 +135,8 @@ lookupTypeWitness(const std::string &MangledTypeName, auto SubstitutedTypeName = readTypeRef(AssocTy, AssocTy->SubstitutedTypeName); auto Demangled = demangleTypeRef(SubstitutedTypeName); - auto *TypeWitness = swift::Demangle::decodeMangledType(*this, Demangled); + auto *TypeWitness = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); AssociatedTypeCache.insert(std::make_pair(key, TypeWitness)); return TypeWitness; @@ -155,7 +156,8 @@ lookupSuperclass(const TypeRef *TR) { return nullptr; auto Demangled = demangleTypeRef(readTypeRef(FD, FD->Superclass)); - auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); + auto Unsubstituted = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); if (!Unsubstituted) return nullptr; @@ -226,7 +228,8 @@ bool TypeRefBuilder::getFieldTypeRefs( } auto Demangled = demangleTypeRef(readTypeRef(Field,Field->MangledTypeName)); - auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); + auto Unsubstituted = + swift::Demangle::decodeMangledType(*this, Demangled).getType(); if (!Unsubstituted) return false; @@ -304,7 +307,7 @@ TypeRefBuilder::getClosureContextInfo(RemoteRef CD) { if (CR->hasMangledTypeName()) { auto MangledName = readTypeRef(CR, CR->MangledTypeName); auto DemangleTree = demangleTypeRef(MangledName); - TR = swift::Demangle::decodeMangledType(*this, DemangleTree); + TR = swift::Demangle::decodeMangledType(*this, DemangleTree).getType(); } Info.CaptureTypes.push_back(TR); } @@ -316,7 +319,7 @@ TypeRefBuilder::getClosureContextInfo(RemoteRef CD) { if (MSR->hasMangledTypeName()) { auto MangledName = readTypeRef(MSR, MSR->MangledTypeName); auto DemangleTree = demangleTypeRef(MangledName); - TR = swift::Demangle::decodeMangledType(*this, DemangleTree); + TR = swift::Demangle::decodeMangledType(*this, DemangleTree).getType(); } const MetadataSource *MS = nullptr; @@ -344,12 +347,17 @@ TypeRefBuilder::dumpTypeRef(RemoteRef MangledName, auto DemangleTree = demangleTypeRef(MangledName); auto TypeName = nodeToString(DemangleTree); fprintf(file, "%s\n", TypeName.c_str()); - auto TR = swift::Demangle::decodeMangledType(*this, DemangleTree); - if (!TR) { + auto Result = swift::Demangle::decodeMangledType(*this, DemangleTree); + if (Result.isError()) { + auto *Error = Result.getError(); + char *ErrorStr = Error->copyErrorString(); auto str = getTypeRefString(MangledName); - fprintf(file, "!!! Invalid typeref: %s\n", std::string(str.begin(), str.end()).c_str()); + fprintf(file, "!!! Invalid typeref: %s - %s\n", + std::string(str.begin(), str.end()).c_str(), ErrorStr); + Error->freeErrorString(ErrorStr); return; } + auto TR = Result.getType(); TR->dump(file); fprintf(file, "\n"); } diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 114cf058512d0..b10f8981149be 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -298,7 +298,7 @@ swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef, const char *MangledTypeName, uint64_t Length) { auto Context = ContextRef->nativeContext; - auto TR = Context->readTypeFromMangledName(MangledTypeName, Length); + auto TR = Context->readTypeFromMangledName(MangledTypeName, Length).getType(); return reinterpret_cast(TR); } @@ -447,6 +447,12 @@ static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) { FieldInfo = &(RecordTI->getFields()[Index]); } else { assert(false && "convertChild(TI): TI must be record or enum typeinfo"); + return { + "unknown TypeInfo kind", + 0, + SWIFT_UNKNOWN, + 0, + }; } return { diff --git a/stdlib/public/core/DebuggerSupport.swift b/stdlib/public/core/DebuggerSupport.swift index 0e7095aebd783..82cfedd5eb4fb 100644 --- a/stdlib/public/core/DebuggerSupport.swift +++ b/stdlib/public/core/DebuggerSupport.swift @@ -152,7 +152,14 @@ public enum _DebuggerSupport { // yes, a type can lie and say it's a class when it's not since we only // check the displayStyle - but then the type would have a custom Mirror // anyway, so there's that... - let willExpand = mirror.displayStyle != .`class` || value is CustomReflectable? + let isNonClass = mirror.displayStyle != .`class` + let isCustomReflectable: Bool + if let value = value { + isCustomReflectable = value is CustomReflectable + } else { + isCustomReflectable = true + } + let willExpand = isNonClass || isCustomReflectable let count = mirror._children.count let bullet = isRoot && (count == 0 || !willExpand) ? "" diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index e29be3ff2033e..0b481bd2459b8 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -33,6 +33,7 @@ set(swift_runtime_sources CompatibilityOverride.cpp CygwinPort.cpp Demangle.cpp + DynamicCast.cpp Enum.cpp EnvironmentVariables.cpp ErrorObjectCommon.cpp diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 6db0739a585ed..99e08243588bb 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -339,6 +339,15 @@ _dynamicCastClassMetatype(const ClassMetadata *sourceType, return nullptr; } +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_unboxFromSwiftValueWithType(OpaqueValue *source, + OpaqueValue *result, + const Metadata *destinationType); +/// Nominal type descriptor for Swift.__SwiftValue +extern "C" const ClassDescriptor NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC); +#endif + /// Dynamically cast a class instance to a Swift class type. static const void *swift_dynamicCastClassImpl(const void *object, const ClassMetadata *targetType) { @@ -351,10 +360,28 @@ static const void *swift_dynamicCastClassImpl(const void *object, } #endif - auto isa = _swift_getClassOfAllocated(object); + auto srcType = _swift_getClassOfAllocated(object); - if (_dynamicCastClassMetatype(isa, targetType)) + if (_dynamicCastClassMetatype(srcType, targetType)) return object; + +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class on Linux + if (srcType->getKind() == MetadataKind::Class + && targetType->getKind() == MetadataKind::Class) { + auto srcClassType = cast(srcType); + auto srcDescr = srcClassType->getDescription(); + if (srcDescr == &NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC)) { + auto srcValue = reinterpret_cast(&object); + void *result; + auto destLocation = reinterpret_cast(&result); + if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, targetType)) { + swift_unknownObjectRelease(const_cast(object)); + return result; + } + } + } +#endif + return nullptr; } @@ -3262,3 +3289,30 @@ HeapObject *_swift_bridgeToObjectiveCUsingProtocolIfPossible( #define OVERRIDE_CASTING COMPATIBILITY_OVERRIDE #include "CompatibilityOverride.def" +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX + +// A way for the new implementation to call the old one, so we +// can support switching between the two until the new one is +// fully settled. + +// XXX TODO XXX Once the new implementation is stable, remove the following, +// swift_dynamicCastImpl above, and all the other code above that only exists to +// support that. (Don't forget _dynamicCastToExistential!!) This file should +// be only ~1400 lines when you're done. + +extern "C" { + bool swift_dynamicCast_OLD(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags) + { + return swift_dynamicCastImpl(destLocation, srcValue, srcType, destType, flags); + } +} + +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX +// XXX TODO XXX REMOVE XXX TRANSITION SHIM XXX diff --git a/stdlib/public/runtime/CompatibilityOverride.def b/stdlib/public/runtime/CompatibilityOverride.def index 92e32430251cd..1489ee07e1eeb 100644 --- a/stdlib/public/runtime/CompatibilityOverride.def +++ b/stdlib/public/runtime/CompatibilityOverride.def @@ -40,6 +40,7 @@ #ifdef OVERRIDE # define OVERRIDE_METADATALOOKUP OVERRIDE # define OVERRIDE_CASTING OVERRIDE +# define OVERRIDE_DYNAMICCASTING OVERRIDE # define OVERRIDE_OBJC OVERRIDE # define OVERRIDE_FOREIGN OVERRIDE # define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE @@ -52,6 +53,9 @@ # ifndef OVERRIDE_CASTING # define OVERRIDE_CASTING(...) # endif +# ifndef OVERRIDE_DYNAMICCASTING +# define OVERRIDE_DYNAMICCASTING(...) +# endif # ifndef OVERRIDE_OBJC # define OVERRIDE_OBJC(...) # endif @@ -69,12 +73,12 @@ # endif #endif -OVERRIDE_CASTING(dynamicCast, bool, , , swift::, - (OpaqueValue *dest, OpaqueValue *src, - const Metadata *srcType, - const Metadata *targetType, - DynamicCastFlags flags), - (dest, src, srcType, targetType, flags)) +OVERRIDE_DYNAMICCASTING(dynamicCast, bool, , , swift::, + (OpaqueValue *dest, OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags), + (dest, src, srcType, targetType, flags)) OVERRIDE_CASTING(dynamicCastClass, const void *, , , swift::, @@ -138,7 +142,7 @@ OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , , swift::, (const void *pattern, const void *arguments), (pattern, arguments)) -OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift::, +OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, (MetadataRequest request, Demangler &demangler, Demangle::NodePointer node, @@ -146,7 +150,7 @@ OVERRIDE_METADATALOOKUP(getTypeByMangledNode, TypeInfo, , SWIFT_CC(swift), swift SubstGenericParameterFn substGenericParam, SubstDependentWitnessTableFn substWitnessTable), (request, demangler, node, arguments, substGenericParam, substWitnessTable)) -OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeInfo, , SWIFT_CC(swift), swift::, +OVERRIDE_METADATALOOKUP(getTypeByMangledName, TypeLookupErrorOr, , SWIFT_CC(swift), swift::, (MetadataRequest request, StringRef typeName, const void * const *arguments, @@ -212,6 +216,7 @@ OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift:: #undef OVERRIDE #undef OVERRIDE_METADATALOOKUP #undef OVERRIDE_CASTING +#undef OVERRIDE_DYNAMICCASTING #undef OVERRIDE_OBJC #undef OVERRIDE_FOREIGN #undef OVERRIDE_PROTOCOLCONFORMANCE diff --git a/stdlib/public/runtime/DynamicCast.cpp b/stdlib/public/runtime/DynamicCast.cpp new file mode 100644 index 0000000000000..fa628e296fb2a --- /dev/null +++ b/stdlib/public/runtime/DynamicCast.cpp @@ -0,0 +1,2197 @@ +//===--- DynamicCast.cpp - Swift Language Dynamic Casting Support ---------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 +// +//===----------------------------------------------------------------------===// +// +// Implementations of the dynamic cast runtime functions. +// +//===----------------------------------------------------------------------===// + +#include "CompatibilityOverride.h" +#include "ErrorObject.h" +#include "Private.h" +#include "SwiftHashableSupport.h" +#include "swift/ABI/MetadataValues.h" +#include "swift/Basic/Lazy.h" +#include "swift/Runtime/Casting.h" +#include "swift/Runtime/Config.h" +#include "swift/Runtime/ExistentialContainer.h" +#include "swift/Runtime/HeapObject.h" +#if SWIFT_OBJC_INTEROP +#include "swift/Runtime/ObjCBridge.h" +#include "SwiftObject.h" +#include "SwiftValue.h" +#endif + +using namespace swift; +using namespace hashable_support; + +// +// The top-level driver code directly handles the most general cases +// (identity casts, _ObjectiveCBridgeable, _SwiftValue boxing) and +// recursively unwraps source and/or destination as appropriate. +// It calls "tryCastToXyz" functions to perform tailored operations +// for a particular destination type. +// +// For each kind of destination, there is a "tryCastToXyz" that +// accepts a source value and attempts to fit it into a destination +// storage location. This function should assume that: +// * The source and destination types are _not_ identical. +// * The destination is of the expected type. +// * The source is already fully unwrapped. If the source is an +// Existential or Optional that you cannot handle directly, do _not_ +// try to unwrap it. Just return failure and you will get called +// again with the unwrapped source. +// +// Each such function accepts the following arguments: +// * Destination location and type +// * Source value address and type +// * References to the types that will be used to report failure. +// The function can update these with specific failing types +// to improve the reported failure. +// * Bool indicating whether the compiler has asked us to "take" the +// value instead of copying. +// * Bool indicating whether it's okay to do type checks lazily on later +// access (this is permitted only for unconditional casts that will +// abort the program on failure anyway). +// +// The return value is one of the following: +// * Failure. In this case, the tryCastFunction should do nothing; your +// caller will either try another strategy or report the failure and +// do any necessary cleanup. +// * Success via "copy". You successfully copied the source value. +// * Success via "take". If "take" was requested and you can do so cheaply, +// perform the take and return SuccessViaTake. If "take" is not cheap, you +// should copy and return SuccessViaCopy. Top-level code will detect this +// and take care of destroying the source for you. +// +enum class DynamicCastResult { + Failure, /// The cast attempt "failed" (did nothing). + SuccessViaCopy, /// Cast succeeded, source is still valid. + SuccessViaTake, /// Cast succeeded, source is invalid +}; +static bool isSuccess(DynamicCastResult result) { + return result != DynamicCastResult::Failure; +} + +// All of our `tryCastXyz` functions have the following signature. +typedef DynamicCastResult (tryCastFunctionType)( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks +); + +// Forward-declare the main top-level `tryCast()` function +static tryCastFunctionType tryCast; + +/// Nominal type descriptor for Swift.AnyHashable +extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s11AnyHashable); + +/// Nominal type descriptor for Swift.__SwiftValue +//extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s12__SwiftValue); + +/// Nominal type descriptor for Swift.Array. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sa); + +/// Nominal type descriptor for Swift.Dictionary. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SD); + +/// Nominal type descriptor for Swift.Set. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sh); + +/// Nominal type descriptor for Swift.String. +extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS); + +static HeapObject * getNonNullSrcObject(OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType) { + auto object = *reinterpret_cast(srcValue); + if (LLVM_LIKELY(object != nullptr)) { + return object; + } + + std::string srcTypeName = nameForMetadata(srcType); + std::string destTypeName = nameForMetadata(destType); + swift::fatalError(/* flags = */ 0, + "Found unexpected null pointer value" + " while trying to cast value of type '%s' (%p)" + " to '%s' (%p)\n", + srcTypeName.c_str(), srcType, + destTypeName.c_str(), destType); +} + +/******************************************************************************/ +/******************************* Bridge Helpers *******************************/ +/******************************************************************************/ + +#define _bridgeAnythingToObjectiveC \ + MANGLE_SYM(s27_bridgeAnythingToObjectiveCyyXlxlF) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API +HeapObject *_bridgeAnythingToObjectiveC( + OpaqueValue *src, const Metadata *srcType); + +#if SWIFT_OBJC_INTEROP +SWIFT_RUNTIME_EXPORT +id swift_dynamicCastMetatypeToObjectConditional(const Metadata *metatype); +#endif + +// protocol _ObjectiveCBridgeable { +struct _ObjectiveCBridgeableWitnessTable : WitnessTable { + static_assert(WitnessTableFirstRequirementOffset == 1, + "Witness table layout changed"); + + // associatedtype _ObjectiveCType : class + void *_ObjectiveCType; + + // func _bridgeToObjectiveC() -> _ObjectiveCType + SWIFT_CC(swift) + HeapObject *(*bridgeToObjectiveC)( + SWIFT_CONTEXT OpaqueValue *self, const Metadata *Self, + const _ObjectiveCBridgeableWitnessTable *witnessTable); + + // class func _forceBridgeFromObjectiveC(x: _ObjectiveCType, + // inout result: Self?) + SWIFT_CC(swift) + void (*forceBridgeFromObjectiveC)( + HeapObject *sourceValue, + OpaqueValue *result, + SWIFT_CONTEXT const Metadata *self, + const Metadata *selfType, + const _ObjectiveCBridgeableWitnessTable *witnessTable); + + // class func _conditionallyBridgeFromObjectiveC(x: _ObjectiveCType, + // inout result: Self?) -> Bool + SWIFT_CC(swift) + bool (*conditionallyBridgeFromObjectiveC)( + HeapObject *sourceValue, + OpaqueValue *result, + SWIFT_CONTEXT const Metadata *self, + const Metadata *selfType, + const _ObjectiveCBridgeableWitnessTable *witnessTable); +}; +// } + +extern "C" const ProtocolDescriptor +PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable); + +static const _ObjectiveCBridgeableWitnessTable * +findBridgeWitness(const Metadata *T) { + static const auto bridgeableProtocol + = &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable); + auto w = swift_conformsToProtocol(T, bridgeableProtocol); + return reinterpret_cast(w); +} + +/// Retrieve the bridged Objective-C type for the given type that +/// conforms to \c _ObjectiveCBridgeable. +MetadataResponse +_getBridgedObjectiveCType( + MetadataRequest request, + const Metadata *conformingType, + const _ObjectiveCBridgeableWitnessTable *wtable) +{ + // FIXME: Can we directly reference the descriptor somehow? + const ProtocolConformanceDescriptor *conformance = wtable->getDescription(); + const ProtocolDescriptor *protocol = conformance->getProtocol(); + auto assocTypeRequirement = protocol->getRequirements().begin(); + assert(assocTypeRequirement->Flags.getKind() == + ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); + auto mutableWTable = (WitnessTable *)wtable; + return swift_getAssociatedTypeWitness( + request, mutableWTable, conformingType, + protocol->getRequirementBaseDescriptor(), + assocTypeRequirement); +} + +/// Dynamic cast from a class type to a value type that conforms to the +/// _ObjectiveCBridgeable, first by dynamic casting the object to the +/// class to which the value type is bridged, and then bridging +/// from that object to the value type via the witness table. +/// +/// Caveat: Despite the name, this is also used to bridge pure Swift +/// classes to Swift value types even when Obj-C is not being used. + +static DynamicCastResult +_tryCastFromClassToObjCBridgeable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, void *srcObject, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks, + const _ObjectiveCBridgeableWitnessTable *destBridgeWitness, + const Metadata *targetBridgeClass) +{ + + // 2. Allocate a T? to receive the bridge result. + + // The extra byte is for the tag. + auto targetSize = destType->getValueWitnesses()->getSize() + 1; + auto targetAlignMask = destType->getValueWitnesses()->getAlignmentMask(); + + // Object that frees a buffer when it goes out of scope. + struct FreeBuffer { + void *Buffer = nullptr; + size_t size, alignMask; + FreeBuffer(size_t size, size_t alignMask) : + size(size), alignMask(alignMask) {} + + ~FreeBuffer() { + if (Buffer) + swift_slowDealloc(Buffer, size, alignMask); + } + } freeBuffer{targetSize, targetAlignMask}; + + // The extra byte is for the tag on the T? + const std::size_t inlineValueSize = 3 * sizeof(void*); + alignas(std::max_align_t) char inlineBuffer[inlineValueSize + 1]; + void *optDestBuffer; + if (destType->getValueWitnesses()->getStride() <= inlineValueSize) { + // Use the inline buffer. + optDestBuffer = inlineBuffer; + } else { + // Allocate a buffer. + optDestBuffer = swift_slowAlloc(targetSize, targetAlignMask); + freeBuffer.Buffer = optDestBuffer; + } + + // Initialize the buffer as an empty optional. + destType->vw_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer, + 1, 1); + + // 3. Bridge into the T? (Effectively a copy operation.) + bool success; + if (mayDeferChecks) { + destBridgeWitness->forceBridgeFromObjectiveC( + (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, + destType, destType, destBridgeWitness); + success = true; + } else { + success = destBridgeWitness->conditionallyBridgeFromObjectiveC( + (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, + destType, destType, destBridgeWitness); + } + + // If we succeeded, then take the value from the temp buffer. + if (success) { + destType->vw_initializeWithTake(destLocation, (OpaqueValue *)optDestBuffer); + // Bridge above is effectively a copy, so overall we're a copy. + return DynamicCastResult::SuccessViaCopy; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastFromClassToObjCBridgeable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + // We need the _ObjectiveCBridgeable conformance for the target + auto destBridgeWitness = findBridgeWitness(destType); + if (destBridgeWitness == nullptr) { + return DynamicCastResult::Failure; + } + + // 1. Sanity check whether the source object can cast to the + // type expected by the target. + + auto targetBridgedClass = + _getBridgedObjectiveCType(MetadataState::Complete, destType, + destBridgeWitness).Value; + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (nullptr == swift_dynamicCastUnknownClass(srcObject, targetBridgedClass)) { + destFailureType = targetBridgedClass; + return DynamicCastResult::Failure; + } + + return _tryCastFromClassToObjCBridgeable( + destLocation, destType, + srcValue, srcType, srcObject, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks, + destBridgeWitness, targetBridgedClass); +} + +/// Dynamic cast from a value type that conforms to the +/// _ObjectiveCBridgeable protocol to a class type, first by bridging +/// the value to its Objective-C object representation and then by +/// dynamic casting that object to the resulting target type. +/// +/// Caveat: Despite the name, this is also used to bridge Swift value types +/// to Swift classes even when Obj-C is not being used. +static DynamicCastResult +tryCastFromObjCBridgeableToClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + auto srcBridgeWitness = findBridgeWitness(srcType); + if (srcBridgeWitness == nullptr) { + return DynamicCastResult::Failure; + } + + // Bridge the source value to an object. + auto srcBridgedObject = + srcBridgeWitness->bridgeToObjectiveC(srcValue, srcType, srcBridgeWitness); + + // Dynamic cast the object to the resulting class type. + if (auto cast = swift_dynamicCastUnknownClass(srcBridgedObject, destType)) { + *reinterpret_cast(destLocation) = cast; + return DynamicCastResult::SuccessViaCopy; + } else { + // We don't need the object anymore. + swift_unknownObjectRelease(srcBridgedObject); + return DynamicCastResult::Failure; + } +} + +/******************************************************************************/ +/****************************** SwiftValue Boxing *****************************/ +/******************************************************************************/ + +#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_unboxFromSwiftValueWithType(OpaqueValue *source, + OpaqueValue *result, + const Metadata *destinationType); + +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool swift_swiftValueConformsTo(const Metadata *, const Metadata *); +#endif + +#if SWIFT_OBJC_INTEROP +// Try unwrapping a source holding an Obj-C SwiftValue container and +// recursively casting the contents. +static DynamicCastResult +tryCastUnwrappingObjCSwiftValueSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + id srcObject; + memcpy(&srcObject, srcValue, sizeof(id)); + auto srcSwiftValue = getAsSwiftValue(srcObject); + + if (srcSwiftValue == nullptr) { + return DynamicCastResult::Failure; + } + + const Metadata *srcInnerType; + const OpaqueValue *srcInnerValue; + std::tie(srcInnerType, srcInnerValue) + = getValueFromSwiftValue(srcSwiftValue); + // Note: We never `take` the contents from a SwiftValue box as + // it might have other references. Instead, let our caller + // destroy the reference if necessary. + return tryCast( + destLocation, destType, + const_cast(srcInnerValue), srcInnerType, + destFailureType, srcFailureType, + /*takeOnSuccess=*/ false, mayDeferChecks); +} +#endif + +/******************************************************************************/ +/****************************** Class Destination *****************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToSwiftClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Class); + + auto destClassType = cast(destType); + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => Swift class + case MetadataKind::ObjCClassWrapper: { // Obj-C class => Swift class + void *object = getNonNullSrcObject(srcValue, srcType, destType); + if (auto t = swift_dynamicCastClass(object, destClassType)) { + auto castObject = const_cast(t); + *(reinterpret_cast(destLocation)) = castObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(castObject); + return DynamicCastResult::SuccessViaCopy; + } + } else { + srcFailureType = srcType; + destFailureType = destType; + return DynamicCastResult::Failure; + } + } + + case MetadataKind::ForeignClass: // CF class => Swift class + // Top-level code will "unwrap" to an Obj-C class and try again. + return DynamicCastResult::Failure; + + default: + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToObjectiveCClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ObjCClassWrapper); +#if SWIFT_OBJC_INTEROP + auto destObjCType = cast(destType); + + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => Obj-C class + case MetadataKind::ObjCClassWrapper: // Obj-C class => Obj-C class + case MetadataKind::ForeignClass: { // CF class => Obj-C class + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + auto destObjCClass = destObjCType->Class; + if (auto resultObject + = swift_dynamicCastObjCClass(srcObject, destObjCClass)) { + *reinterpret_cast(destLocation) = resultObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + objc_retain((id)const_cast(resultObject)); + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + + default: + break; + } +#endif + + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToForeignClass( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ +#if SWIFT_OBJC_INTEROP + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ForeignClass); + auto destClassType = cast(destType); + + switch (srcType->getKind()) { + case MetadataKind::Class: // Swift class => CF class + case MetadataKind::ObjCClassWrapper: // Obj-C class => CF class + case MetadataKind::ForeignClass: { // CF class => CF class + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (auto resultObject + = swift_dynamicCastForeignClass(srcObject, destClassType)) { + *reinterpret_cast(destLocation) = resultObject; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + objc_retain((id)const_cast(resultObject)); + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + default: + break; + } +#endif + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/***************************** Enum Destination *******************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToEnum( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + // Note: Optional is handled elsewhere + assert(destType->getKind() == MetadataKind::Enum); + + // Enum has no special cast support at present. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/**************************** Struct Destination ******************************/ +/******************************************************************************/ + +// internal func _arrayDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_arrayDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType); + +// internal func _arrayDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_arrayDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType); + +// internal func _setDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_setDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType, + const void *sourceValueHashable, + const void *targetValueHashable); + +// internal func _setDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_setDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceValueType, + const Metadata *targetValueType, + const void *sourceValueHashable, + const void *targetValueHashable); + +// internal func _dictionaryDownCastIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer>) +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +void _swift_dictionaryDownCastIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceKeyType, + const Metadata *sourceValueType, + const Metadata *targetKeyType, + const Metadata *targetValueType, + const void *sourceKeyHashable, + const void *targetKeyHashable); + +// internal func _dictionaryDownCastConditionalIndirect( +// _ source: UnsafePointer>, +// _ target: UnsafeMutablePointer> +// ) -> Bool +SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL +bool _swift_dictionaryDownCastConditionalIndirect(OpaqueValue *destination, + OpaqueValue *source, + const Metadata *sourceKeyType, + const Metadata *sourceValueType, + const Metadata *targetKeyType, + const Metadata *targetValueType, + const void *sourceKeyHashable, + const void *targetKeyHashable); + +#if SWIFT_OBJC_INTEROP +// Helper to memoize bridging conformance data for a particular +// Swift struct type. This is used to speed up the most common +// ObjC->Swift bridging conversions by eliminating repeeated +// protocol conformance lookups. + +// Currently used only for String, which may be the only +// type used often enough to justify the extra static memory. +struct ObjCBridgeMemo { +#if !NDEBUG + // Used in assert build to verify that we always get called with + // the same destType + const Metadata *destType; +#endif + const _ObjectiveCBridgeableWitnessTable *destBridgeWitness; + const Metadata *targetBridgedType; + Class targetBridgedObjCClass; + swift_once_t fetchWitnessOnce; + + DynamicCastResult tryBridge( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) + { + struct SetupData { + const Metadata *destType; + struct ObjCBridgeMemo *memo; + } setupData { destType, this }; + + swift_once(&fetchWitnessOnce, + [](void *data) { + struct SetupData *setupData = (struct SetupData *)data; + struct ObjCBridgeMemo *memo = setupData->memo; +#if !NDEBUG + memo->destType = setupData->destType; +#endif + memo->destBridgeWitness = findBridgeWitness(setupData->destType); + if (memo->destBridgeWitness == nullptr) { + memo->targetBridgedType = nullptr; + memo->targetBridgedObjCClass = nullptr; + } else { + memo->targetBridgedType = _getBridgedObjectiveCType( + MetadataState::Complete, setupData->destType, memo->destBridgeWitness).Value; + assert(memo->targetBridgedType->getKind() == MetadataKind::ObjCClassWrapper); + memo->targetBridgedObjCClass = memo->targetBridgedType->getObjCClassObject(); + assert(memo->targetBridgedObjCClass != nullptr); + } + }, (void *)&setupData); + + // Check that this always gets called with the same destType. + assert((destType == this->destType) && "ObjC casting memo used inconsistently"); + + // !! If bridging is not usable, stop here. + if (targetBridgedObjCClass == nullptr) { + return DynamicCastResult::Failure; + } + // Use the dynamic ISA type of the object always (Note that this + // also implicitly gives us the ObjC type for a CF object.) + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + Class srcObjCType = object_getClass((id)srcObject); + // Fail if the ObjC object is not a subclass of the bridge class. + while (srcObjCType != targetBridgedObjCClass) { + srcObjCType = class_getSuperclass(srcObjCType); + if (srcObjCType == nullptr) { + return DynamicCastResult::Failure; + } + } + // The ObjC object is an acceptable type, so call the bridge function... + return _tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, srcObject, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks, + destBridgeWitness, targetBridgedType); + } +}; +#endif + +static DynamicCastResult +tryCastToAnyHashable( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)); + + auto hashableConformance = reinterpret_cast( + swift_conformsToProtocol(srcType, &HashableProtocolDescriptor)); + if (hashableConformance) { + _swift_convertToAnyHashableIndirect(srcValue, destLocation, + srcType, hashableConformance); + return DynamicCastResult::SuccessViaCopy; + } else { + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToArray( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(Sa)); + + switch (srcType->getKind()) { + case MetadataKind::Struct: { // Struct -> Array + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(Sa)) { // Array -> Array + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_arrayDownCastIndirect( + srcValue, destLocation, sourceArgs[0], destArgs[0]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_arrayDownCastConditionalIndirect( + srcValue, destLocation, sourceArgs[0], destArgs[0]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToDictionary( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(SD)); + + switch (srcType->getKind()) { + case MetadataKind::Struct: { // Struct -> Dictionary + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(SD)) { // Dictionary -> Dictionary + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_dictionaryDownCastIndirect( + srcValue, destLocation, sourceArgs[0], sourceArgs[1], + destArgs[0], destArgs[1], sourceArgs[2], destArgs[2]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_dictionaryDownCastConditionalIndirect( + srcValue, destLocation, sourceArgs[0], sourceArgs[1], + destArgs[0], destArgs[1], sourceArgs[2], destArgs[2]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToSet( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(Sh)); + + switch (srcType->getKind()) { + + case MetadataKind::Struct: { // Struct -> Set + const auto srcStructType = cast(srcType); + if (srcStructType->Description == &NOMINAL_TYPE_DESCR_SYM(Sh)) { // Set -> Set + auto sourceArgs = srcType->getGenericArgs(); + auto destArgs = destType->getGenericArgs(); + if (mayDeferChecks) { + _swift_setDownCastIndirect(srcValue, destLocation, + sourceArgs[0], destArgs[0], sourceArgs[1], destArgs[1]); + return DynamicCastResult::SuccessViaCopy; + } else { + auto result = _swift_setDownCastConditionalIndirect( + srcValue, destLocation, + sourceArgs[0], destArgs[0], + sourceArgs[1], destArgs[1]); + if (result) { + return DynamicCastResult::SuccessViaCopy; + } + } + } + break; + } + + default: + break; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToString( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + assert(cast(destType)->Description + == &NOMINAL_TYPE_DESCR_SYM(SS)); + + switch (srcType->getKind()) { + case MetadataKind::ForeignClass: // CF -> String + case MetadataKind::ObjCClassWrapper: { // Obj-C -> String +#if SWIFT_OBJC_INTEROP + static ObjCBridgeMemo memo; + return memo.tryBridge( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks); +#endif + } + default: + return DynamicCastResult::Failure; + } + return DynamicCastResult::Failure; +} + +static DynamicCastResult +tryCastToStruct( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Struct); + + // There is no special cast handling at present for general Struct types. + + // Special logic for AnyHashable, Set, Dictionary, Array, and String + // is broken out above. See also selectCasterForDest() for the + // logic that chooses one of these functions. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/*************************** Optional Destination *****************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToOptional( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Optional); + + // Nothing to do for the basic casting operation. + // Unwrapping is handled by top-level tryCast with assistance + // from utility functions below. + + return DynamicCastResult::Failure; +} + +// The nil value `T?.none` can be cast to any optional type. +// When the unwrapper sees a source value that is nil, it calls +// tryCastFromNil() to try to set the target optional to nil. +// +// This is complicated by the desire to preserve the nesting +// as far as possible. For example, we would like: +// Int?.none => Int??.some(.none) +// Int??.none => Any????.some(.some(.none)) +// Of course, if the target is shallower than the source, +// then we have to just set the outermost optional to nil. + +// This helper sets a nested optional to nil at a requested level: +static void +initializeToNilAtDepth(OpaqueValue *destLocation, const Metadata *destType, int depth) { + assert(destType->getKind() == MetadataKind::Optional); + auto destInnerType = cast(destType)->getGenericArgs()[0]; + if (depth > 0) { + initializeToNilAtDepth(destLocation, destInnerType, depth - 1); + // Set .some at each level as we unwind + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, 0, 1); + } else { + // Set .none at the lowest level + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, 1, 1); + } +} + +static void +copyNil(OpaqueValue *destLocation, const Metadata *destType, const Metadata *srcType) +{ + assert(srcType->getKind() == MetadataKind::Optional); + assert(destType->getKind() == MetadataKind::Optional); + + // Measure how deep the source nil is: Is it Int?.none or Int??.none or ... + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + int srcDepth = 1; + while (srcInnerType->getKind() == MetadataKind::Optional) { + srcInnerType = cast(srcInnerType)->getGenericArgs()[0]; + srcDepth += 1; + } + + // Measure how deep the destination optional is + auto destInnerType = cast(destType)->getGenericArgs()[0]; + int destDepth = 1; + while (destInnerType->getKind() == MetadataKind::Optional) { + destInnerType = cast(destInnerType)->getGenericArgs()[0]; + destDepth += 1; + } + + // Recursively set the destination to .some(.some(... .some(.none))) + auto targetDepth = std::max(destDepth - srcDepth, 0); + initializeToNilAtDepth(destLocation, destType, targetDepth); +} + +// Try unwrapping both source and dest optionals together. +// If the source is nil, then cast that to the destination. +static DynamicCastResult +tryCastUnwrappingOptionalBoth( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(destType->getKind() == MetadataKind::Optional); + assert(srcType->getKind() == MetadataKind::Optional); + + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload( + srcValue, /*emptyCases=*/1); + auto sourceIsNil = (sourceEnumCase != 0); + if (sourceIsNil) { + copyNil(destLocation, destType, srcType); + return DynamicCastResult::SuccessViaCopy; // nil was essentially copied to dest + } else { + auto destEnumType = cast(destType); + const Metadata *destInnerType = destEnumType->getGenericArgs()[0]; + auto destInnerLocation = destLocation; // Single-payload enum layout + auto subcastResult = tryCast( + destInnerLocation, destInnerType, srcValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, /*case*/ 0, /*emptyCases*/ 1); + } + return subcastResult; + } + return DynamicCastResult::Failure; +} + +// Try unwrapping just the destination optional. +// Note we do this even if both src and dest are optional. +// For example, Int -> Any? requires unwrapping the destination +// in order to inject the Int into the existential. +static DynamicCastResult +tryCastUnwrappingOptionalDestination( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(destType->getKind() == MetadataKind::Optional); + + auto destEnumType = cast(destType); + const Metadata *destInnerType = destEnumType->getGenericArgs()[0]; + auto destInnerLocation = destLocation; // Single-payload enum layout + auto subcastResult = tryCast( + destInnerLocation, destInnerType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + destInnerType->vw_storeEnumTagSinglePayload( + destLocation, /*case*/ 0, /*emptyCases*/ 1); + } + return subcastResult; +} + +// Try unwrapping just the source optional. +// Note we do this even if both target and dest are optional. +// For example, this is used when extracting the contents of +// an Optional. +static DynamicCastResult +tryCastUnwrappingOptionalSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType->getKind() == MetadataKind::Optional); + + auto srcInnerType = cast(srcType)->getGenericArgs()[0]; + unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload( + srcValue, /*emptyCases=*/1); + auto nonNil = (sourceEnumCase == 0); + if (nonNil) { + // Recurse with unwrapped source + return tryCast(destLocation, destType, srcValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/***************************** Tuple Destination ******************************/ +/******************************************************************************/ + +// The only thing that can be legally cast to a tuple is another tuple. +// Most of the logic below is required to handle element-wise casts of +// tuples that are compatible but not of the same type. + +static DynamicCastResult +tryCastToTuple( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Tuple); + const auto destTupleType = cast(destType); + + srcFailureType = srcType; + destFailureType = destType; + + // We cannot cast non-tuple data to a tuple + if (srcType->getKind() != MetadataKind::Tuple) { + return DynamicCastResult::Failure; + } + const auto srcTupleType = cast(srcType); + + // Tuples must have same number of elements + if (srcTupleType->NumElements != destTupleType->NumElements) { + return DynamicCastResult::Failure; + } + + // Common labels must match + const char *srcLabels = srcTupleType->Labels; + const char *destLabels = destTupleType->Labels; + while (srcLabels != nullptr + && destLabels != nullptr + && srcLabels != destLabels) + { + const char *srcSpace = strchr(srcLabels, ' '); + const char *destSpace = strchr(destLabels, ' '); + + // If we've reached the end of either label string, we're done. + if (srcSpace == nullptr || destSpace == nullptr) { + break; + } + + // If both labels are non-empty, and the labels mismatch, we fail. + if (srcSpace != srcLabels && destSpace != destLabels) { + unsigned srcLen = srcSpace - srcLabels; + unsigned destLen = destSpace - destLabels; + if (srcLen != destLen || + strncmp(srcLabels, destLabels, srcLen) != 0) + return DynamicCastResult::Failure; + } + + srcLabels = srcSpace + 1; + destLabels = destSpace + 1; + } + + // Compare the element types to see if they all match. + bool typesMatch = true; + auto numElements = srcTupleType->NumElements; + for (unsigned i = 0; typesMatch && i != numElements; ++i) { + if (srcTupleType->getElement(i).Type != destTupleType->getElement(i).Type) { + typesMatch = false; + } + } + + if (typesMatch) { + // The actual element types are identical, so we can use the + // fast value-witness machinery for the whole tuple. + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } + } else { + // Slow path casts each item separately. + for (unsigned j = 0, n = srcTupleType->NumElements; j != n; ++j) { + const auto &srcElt = srcTupleType->getElement(j); + const auto &destElt = destTupleType->getElement(j); + auto subcastResult = tryCast(destElt.findIn(destLocation), destElt.Type, + srcElt.findIn(srcValue), srcElt.Type, + destFailureType, srcFailureType, + false, mayDeferChecks); + if (subcastResult == DynamicCastResult::Failure) { + for (unsigned k = 0; k != j; ++k) { + const auto &elt = destTupleType->getElement(k); + elt.Type->vw_destroy(elt.findIn(destLocation)); + } + return DynamicCastResult::Failure; + } + } + // We succeeded by casting each item. + return DynamicCastResult::SuccessViaCopy; + } + +} + +/******************************************************************************/ +/**************************** Function Destination ****************************/ +/******************************************************************************/ + +// The only thing that can be legally cast to a function is another function. + +static DynamicCastResult +tryCastToFunction( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Function); + const auto destFuncType = cast(destType); + + // Function casts succeed on exact matches, or if the target type is + // throwier than the source type. + // + // TODO: We could also allow ABI-compatible variance, such as casting + // a dynamic Base -> Derived to Derived -> Base. We wouldn't be able to + // perform a dynamic cast that required any ABI adjustment without a JIT + // though. + + if (srcType->getKind() != MetadataKind::Function) { + return DynamicCastResult::Failure; + } + auto srcFuncType = cast(srcType); + + // Check that argument counts and convention match (but ignore + // "throws" for now). + if (srcFuncType->Flags.withThrows(false) + != destFuncType->Flags.withThrows(false)) { + return DynamicCastResult::Failure; + } + + // If the target type can't throw, neither can the source. + if (srcFuncType->isThrowing() && !destFuncType->isThrowing()) + return DynamicCastResult::Failure; + + // The result and argument types must match. + if (srcFuncType->ResultType != destFuncType->ResultType) + return DynamicCastResult::Failure; + if (srcFuncType->getNumParameters() != destFuncType->getNumParameters()) + return DynamicCastResult::Failure; + if (srcFuncType->hasParameterFlags() != destFuncType->hasParameterFlags()) + return DynamicCastResult::Failure; + for (unsigned i = 0, e = srcFuncType->getNumParameters(); i < e; ++i) { + if (srcFuncType->getParameter(i) != destFuncType->getParameter(i) || + srcFuncType->getParameterFlags(i) != destFuncType->getParameterFlags(i)) + return DynamicCastResult::Failure; + } + + // Everything matches, so we can take/copy the function reference. + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } +} + +/******************************************************************************/ +/************************** Existential Destination ***************************/ +/******************************************************************************/ + +/// Check whether a type conforms to the given protocols, filling in a +/// list of conformances. +static bool _conformsToProtocols(const OpaqueValue *value, + const Metadata *type, + const ExistentialTypeMetadata *existentialType, + const WitnessTable **conformances) { + if (auto *superclass = existentialType->getSuperclassConstraint()) { + if (!swift_dynamicCastMetatype(type, superclass)) + return false; + } + + if (existentialType->isClassBounded()) { + if (!Metadata::isAnyKindOfClass(type->getKind())) + return false; + } + + for (auto protocol : existentialType->getProtocols()) { + if (!swift::_conformsToProtocol(value, type, protocol, conformances)) + return false; + if (conformances != nullptr && protocol.needsWitnessTable()) { + assert(*conformances != nullptr); + ++conformances; + } + } + + return true; +} + +// Cast to unconstrained `Any` +static DynamicCastResult +tryCastToUnconstrainedOpaqueExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + assert(cast(destType)->getRepresentation() + == ExistentialTypeRepresentation::Opaque); + auto destExistential + = reinterpret_cast(destLocation); + + // Fill in the type and value. + destExistential->Type = srcType; + auto *destBox = srcType->allocateBoxForExistentialIn(&destExistential->Buffer); + if (takeOnSuccess) { + srcType->vw_initializeWithTake(destBox, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + srcType->vw_initializeWithCopy(destBox, srcValue); + return DynamicCastResult::SuccessViaCopy; + } +} + +// Cast to constrained `Any` +static DynamicCastResult +tryCastToConstrainedOpaqueExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Opaque); + auto destExistential + = reinterpret_cast(destLocation); + + // Check for protocol conformances and fill in the witness tables. + // TODO (rdar://17033499) If the source is an existential, we should + // be able to compare the protocol constraints more efficiently than this. + if (_conformsToProtocols(srcValue, srcType, destExistentialType, + destExistential->getWitnessTables())) { + return tryCastToUnconstrainedOpaqueExistential( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } else { + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastToClassExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Class); + auto destExistentialLocation + = reinterpret_cast(destLocation); + + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + + case MetadataKind::Metatype: { +#if SWIFT_OBJC_INTEROP + // Get an object reference to the metatype and try fitting that into + // the existential... + auto metatypePtr = reinterpret_cast(srcValue); + auto metatype = *metatypePtr; + if (auto tmp = swift_dynamicCastMetatypeToObjectConditional(metatype)) { + auto value = reinterpret_cast(&tmp); + auto type = reinterpret_cast(tmp); + if (_conformsToProtocols(value, type, destExistentialType, + destExistentialLocation->getWitnessTables())) { + auto object = *(reinterpret_cast(value)); + destExistentialLocation->Value = object; + if (takeOnSuccess) { + // We copied the pointer without retain, so the source is no + // longer valid... + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(object); + return DynamicCastResult::SuccessViaCopy; + } + } else { + // We didn't assign to destination, so the source reference + // is still valid and the reference count is still correct. + } + } +#endif + return DynamicCastResult::Failure; + } + + case MetadataKind::ObjCClassWrapper: + case MetadataKind::Class: + case MetadataKind::ForeignClass: { + auto object = getNonNullSrcObject(srcValue, srcType, destType); + if (_conformsToProtocols(srcValue, srcType, + destExistentialType, + destExistentialLocation->getWitnessTables())) { + destExistentialLocation->Value = object; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + swift_unknownObjectRetain(object); + return DynamicCastResult::SuccessViaCopy; + } + } + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } + + return DynamicCastResult::Failure; +} + +// SwiftValue boxing is a failsafe that we only want to invoke +// after other approaches have failed. This is why it's not +// integrated into tryCastToClassExistential() above. +static DynamicCastResult +tryCastToClassExistentialViaSwiftValue( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Class); + auto destExistentialLocation + = reinterpret_cast(destLocation); + + // Fail if the target has constraints that make it unsuitable for + // a __SwiftValue box. + // FIXME: We should not have different checks here for + // Obj-C vs non-Obj-C. The _SwiftValue boxes should conform + // to the exact same protocols on both platforms. + bool destIsConstrained = destExistentialType->NumProtocols != 0; + if (destIsConstrained) { +#if SWIFT_OBJC_INTEROP // __SwiftValue is an Obj-C class + if (!findSwiftValueConformances( + destExistentialType, destExistentialLocation->getWitnessTables())) { + return DynamicCastResult::Failure; + } +#else // __SwiftValue is a native class + if (!swift_swiftValueConformsTo(destType, destType)) { + return DynamicCastResult::Failure; + } +#endif + } + +#if SWIFT_OBJC_INTEROP + auto object = bridgeAnythingToSwiftValueObject( + srcValue, srcType, takeOnSuccess); + destExistentialLocation->Value = object; + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + return DynamicCastResult::SuccessViaCopy; + } +# else + // Note: Code below works correctly on both Obj-C and non-Obj-C platforms, + // but the code above is slightly faster on Obj-C platforms. + auto object = _bridgeAnythingToObjectiveC(srcValue, srcType); + destExistentialLocation->Value = object; + return DynamicCastResult::SuccessViaCopy; +#endif +} + +static DynamicCastResult +tryCastToErrorExistential( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Existential); + auto destExistentialType = cast(destType); + assert(destExistentialType->getRepresentation() + == ExistentialTypeRepresentation::Error); + auto destBoxAddr = reinterpret_cast(destLocation); + + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::ForeignClass: // CF object => Error + case MetadataKind::ObjCClassWrapper: // Obj-C object => Error + case MetadataKind::Struct: // Struct => Error + case MetadataKind::Enum: // Enum => Error + case MetadataKind::Class: { // Class => Error + assert(destExistentialType->NumProtocols == 1); + const WitnessTable *errorWitness; + if (_conformsToProtocols( + srcValue, srcType, destExistentialType, &errorWitness)) { +#if SWIFT_OBJC_INTEROP + // If it already holds an NSError, just use that. + if (auto embedded = getErrorEmbeddedNSErrorIndirect( + srcValue, srcType, errorWitness)) { + *destBoxAddr = reinterpret_cast(embedded); + return DynamicCastResult::SuccessViaCopy; + } +#endif + + BoxPair destBox = swift_allocError( + srcType, errorWitness, srcValue, takeOnSuccess); + *destBoxAddr = reinterpret_cast(destBox.object); + if (takeOnSuccess) { + return DynamicCastResult::SuccessViaTake; + } else { + return DynamicCastResult::SuccessViaCopy; + } + } + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +static DynamicCastResult +tryCastUnwrappingExistentialSource( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + auto srcExistentialType = cast(srcType); + + // Unpack the existential content + const Metadata *srcInnerType; + OpaqueValue *srcInnerValue; + switch (srcExistentialType->getRepresentation()) { + case ExistentialTypeRepresentation::Class: { + auto classContainer + = reinterpret_cast(srcValue); + srcInnerType = swift_getObjectType((HeapObject *)classContainer->Value); + srcInnerValue = reinterpret_cast(&classContainer->Value); + break; + } + case ExistentialTypeRepresentation::Opaque: { + auto opaqueContainer + = reinterpret_cast(srcValue); + srcInnerType = opaqueContainer->Type; + srcInnerValue = srcExistentialType->projectValue(srcValue); + break; + } + case ExistentialTypeRepresentation::Error: { + const SwiftError *errorBox + = *reinterpret_cast(srcValue); + auto srcErrorValue + = errorBox->isPureNSError() ? srcValue : errorBox->getValue(); + srcInnerType = errorBox->getType(); + srcInnerValue = const_cast(srcErrorValue); + break; + } + } + + srcFailureType = srcInnerType; + return tryCast(destLocation, destType, + srcInnerValue, srcInnerType, + destFailureType, srcFailureType, + takeOnSuccess & (srcInnerValue == srcValue), + mayDeferChecks); +} + +/******************************************************************************/ +/**************************** Opaque Destination ******************************/ +/******************************************************************************/ + +static DynamicCastResult +tryCastToOpaque( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Opaque); + + // There's nothing special we can do here, but we have to have this + // empty function in order for the general casting logic to run + // for these types. + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/**************************** Metatype Destination ****************************/ +/******************************************************************************/ + +#if SWIFT_OBJC_INTEROP +/// Check whether an unknown class instance is actually a type/metatype object. +static const Metadata *_getUnknownClassAsMetatype(void *object) { + // Objective-C class metadata are objects, so an AnyObject (or + // NSObject) may refer to a class object. + + // Test whether the object's isa is a metaclass, which indicates that + // the object is a class. + + Class isa = object_getClass((id)object); + if (class_isMetaClass(isa)) { + return swift_getObjCClassMetadata((const ClassMetadata *)object); + } + + return nullptr; +} +#endif + +static DynamicCastResult +tryCastToMetatype( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::Metatype); + + const MetatypeMetadata *destMetatypeType = cast(destType); + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::Metatype: + case MetadataKind::ExistentialMetatype: { + const Metadata *srcMetatype = *(const Metadata * const *) srcValue; + if (auto result = swift_dynamicCastMetatype( + srcMetatype, destMetatypeType->InstanceType)) { + *((const Metadata **) destLocation) = result; + return DynamicCastResult::SuccessViaCopy; + } + return DynamicCastResult::Failure; + } + + case MetadataKind::Class: + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + // Some classes are actually metatypes + void *object = getNonNullSrcObject(srcValue, srcType, destType); + if (auto metatype = _getUnknownClassAsMetatype(object)) { + auto srcInnerValue = reinterpret_cast(&metatype); + auto srcInnerType = swift_getMetatypeMetadata(metatype); + return tryCast(destLocation, destType, srcInnerValue, srcInnerType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + } +#endif + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +/// Perform a dynamic cast of a metatype to an existential metatype type. +static DynamicCastResult +_dynamicCastMetatypeToExistentialMetatype( + OpaqueValue *destLocation, const ExistentialMetatypeMetadata *destType, + const Metadata *srcMetatype, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + // The instance type of an existential metatype must be either an + // existential or an existential metatype. + auto destMetatype + = reinterpret_cast(destLocation); + + // If it's an existential, we need to check for conformances. + auto targetInstanceType = destType->InstanceType; + if (auto targetInstanceTypeAsExistential = + dyn_cast(targetInstanceType)) { + // Check for conformance to all the protocols. + // TODO: collect the witness tables. + const WitnessTable **conformance + = destMetatype ? destMetatype->getWitnessTables() : nullptr; + if (!_conformsToProtocols(nullptr, srcMetatype, + targetInstanceTypeAsExistential, + conformance)) { + return DynamicCastResult::Failure; + } + + if (destMetatype) + destMetatype->Value = srcMetatype; + return DynamicCastResult::SuccessViaCopy; + } + + // Otherwise, we're casting to SomeProtocol.Type.Type. + auto targetInstanceTypeAsMetatype = + cast(targetInstanceType); + + // If the source type isn't a metatype, the cast fails. + auto srcMetatypeMetatype = dyn_cast(srcMetatype); + if (!srcMetatypeMetatype) { + return DynamicCastResult::Failure; + } + + // The representation of an existential metatype remains consistent + // arbitrarily deep: a metatype, followed by some protocols. The + // protocols are the same at every level, so we can just set the + // metatype correctly and then recurse, letting the recursive call + // fill in the conformance information correctly. + + // Proactively set the destination metatype so that we can tail-recur, + // unless we've already done so. There's no harm in doing this even if + // the cast fails. + if (destLocation) + *((const Metadata **) destLocation) = srcMetatype; + + // Recurse. + auto srcInstanceType = srcMetatypeMetatype->InstanceType; + return _dynamicCastMetatypeToExistentialMetatype( + nullptr, + targetInstanceTypeAsMetatype, + srcInstanceType, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); +} + +// "ExistentialMetatype" is the metatype for an existential type. +static DynamicCastResult +tryCastToExistentialMetatype( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + assert(srcType != destType); + assert(destType->getKind() == MetadataKind::ExistentialMetatype); + + auto destExistentialMetatypeType + = cast(destType); + MetadataKind srcKind = srcType->getKind(); + switch (srcKind) { + case MetadataKind::Metatype: // Metatype => ExistentialMetatype + case MetadataKind::ExistentialMetatype: { // ExistentialMetatype => ExistentialMetatype + const Metadata *srcMetatype = *(const Metadata * const *) srcValue; + return _dynamicCastMetatypeToExistentialMetatype( + destLocation, + destExistentialMetatypeType, + srcMetatype, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); + } + + case MetadataKind::ObjCClassWrapper: { + // Some Obj-C classes are actually metatypes +#if SWIFT_OBJC_INTEROP + void *srcObject = getNonNullSrcObject(srcValue, srcType, destType); + if (auto metatype = _getUnknownClassAsMetatype(srcObject)) { + return _dynamicCastMetatypeToExistentialMetatype( + destLocation, + destExistentialMetatypeType, + metatype, + destFailureType, + srcFailureType, + takeOnSuccess, mayDeferChecks); + } +#endif + return DynamicCastResult::Failure; + } + + default: + return DynamicCastResult::Failure; + } +} + +/******************************************************************************/ +/********************************** Dispatch **********************************/ +/******************************************************************************/ + +// A layer of functions that evaluate the source and/or destination types +// in order to invoke a tailored casting operation above. +// +// This layer also deals with general issues of unwrapping box types +// and invoking bridging conversions defined via the _ObjectiveCBridgeable +// protocol. +// +// Most of the caster functions above should be fairly simple: +// * They should deal with a single target type, +// * They should assume the source is fully unwrapped, +// * They should not try to report or cleanup failure, +// * If they can take, they should report the source was destroyed. + +// Based on the destination type alone, select a targeted casting function. +// This design avoids some redundant inspection of the destination type +// data, for example, when we unwrap source boxes. +static tryCastFunctionType *selectCasterForDest(const Metadata *destType) { + auto destKind = destType->getKind(); + switch (destKind) { + case MetadataKind::Class: + return tryCastToSwiftClass; + case MetadataKind::Struct: { + const auto targetDescriptor = cast(destType)->Description; + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(SS)) { + return tryCastToString; + } + if (targetDescriptor == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)) { + return tryCastToAnyHashable; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(Sa)) { + return tryCastToArray; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(SD)) { + return tryCastToDictionary; + } + if (targetDescriptor == &NOMINAL_TYPE_DESCR_SYM(Sh)) { + return tryCastToSet; + } + return tryCastToStruct; + } + case MetadataKind::Enum: + return tryCastToEnum; + case MetadataKind::Optional: + return tryCastToOptional; + case MetadataKind::ForeignClass: + return tryCastToForeignClass; + case MetadataKind::Opaque: + return tryCastToOpaque; + case MetadataKind::Tuple: + return tryCastToTuple; + case MetadataKind::Function: + return tryCastToFunction; + case MetadataKind::Existential: { + auto existentialType = cast(destType); + switch (existentialType->getRepresentation()) { + case ExistentialTypeRepresentation::Opaque: + if (existentialType->NumProtocols == 0) { + return tryCastToUnconstrainedOpaqueExistential; // => Unconstrained Any + } else { + return tryCastToConstrainedOpaqueExistential; // => Non-class-constrained protocol + } + case ExistentialTypeRepresentation::Class: + return tryCastToClassExistential; // => AnyObject, with or without protocol constraints + case ExistentialTypeRepresentation::Error: // => Error existential + return tryCastToErrorExistential; + } + swift_runtime_unreachable( + "Unknown existential type representation in dynamic cast dispatch"); + } + case MetadataKind::Metatype: + return tryCastToMetatype; + case MetadataKind::ObjCClassWrapper: + return tryCastToObjectiveCClass; + case MetadataKind::ExistentialMetatype: + return tryCastToExistentialMetatype; + case MetadataKind::HeapLocalVariable: + case MetadataKind::HeapGenericLocalVariable: + case MetadataKind::ErrorObject: + // These are internal details of runtime-only structures, + // so will never appear in compiler-generated types. + // As such, they don't need support here. + swift_runtime_unreachable( + "Unexpected MetadataKind in dynamic cast dispatch"); + return nullptr; + default: + // If you see this message, then there is a new MetadataKind that I didn't + // know about when I wrote this code. Please figure out what it is, how to + // handle it, and add a case for it. + swift_runtime_unreachable( + "Unknown MetadataKind in dynamic cast dispatch"); + } +} + +// This top-level driver provides the general flow for all casting +// operations. It recursively unwraps source and destination as it +// searches for a suitable conversion. +static DynamicCastResult +tryCast( + OpaqueValue *destLocation, const Metadata *destType, + OpaqueValue *srcValue, const Metadata *srcType, + const Metadata *&destFailureType, const Metadata *&srcFailureType, + bool takeOnSuccess, bool mayDeferChecks) +{ + destFailureType = destType; + srcFailureType = srcType; + + //////////////////////////////////////////////////////////////////////// + // + // 1. If types match exactly, we can just move/copy the data. + // (The tryCastToXyz functions never see this trivial case.) + // + if (srcType == destType) { + if (takeOnSuccess) { + destType->vw_initializeWithTake(destLocation, srcValue); + return DynamicCastResult::SuccessViaTake; + } else { + destType->vw_initializeWithCopy(destLocation, srcValue); + return DynamicCastResult::SuccessViaCopy; + } + } + + auto destKind = destType->getKind(); + auto srcKind = srcType->getKind(); + + //////////////////////////////////////////////////////////////////////// + // + // 2. Try directly casting the current srcValue to the target type. + // (If the dynamic type is different, try that too.) + // + auto tryCastToDestType = selectCasterForDest(destType); + if (tryCastToDestType == nullptr) { + return DynamicCastResult::Failure; + } + auto castResult = tryCastToDestType(destLocation, destType, srcValue, + srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(castResult)) { + return castResult; + } + if (srcKind == MetadataKind::Class + || srcKind == MetadataKind::ObjCClassWrapper + || srcKind == MetadataKind::ForeignClass) { + auto srcObject = getNonNullSrcObject(srcValue, srcType, destType); + auto srcDynamicType = swift_getObjectType(srcObject); + if (srcDynamicType != srcType) { + srcFailureType = srcDynamicType; + auto castResult = tryCastToDestType( + destLocation, destType, srcValue, srcDynamicType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(castResult)) { + return castResult; + } + } + } + + //////////////////////////////////////////////////////////////////////// + // + // 3. Try recursively unwrapping _source_ boxes, including + // existentials, AnyHashable, SwiftValue, and Error. + // + switch (srcKind) { + + case MetadataKind::Class: { +#if !SWIFT_OBJC_INTEROP + // Try unwrapping native __SwiftValue implementation + if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, destType)) { + return DynamicCastResult::SuccessViaCopy; + } +#endif + break; + } + + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + // Try unwrapping Obj-C __SwiftValue implementation + auto subcastResult = tryCastUnwrappingObjCSwiftValueSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } +#endif + +#if SWIFT_OBJC_INTEROP + // Try unwrapping Obj-C NSError container + auto innerFlags = DynamicCastFlags::Default; + if (tryDynamicCastNSErrorToValue( + destLocation, srcValue, srcType, destType, innerFlags)) { + return DynamicCastResult::SuccessViaCopy; + } +#endif + break; + } + + case MetadataKind::Struct: { + auto srcStructType = cast(srcType); + auto srcStructDescription = srcStructType->getDescription(); + + // Try unwrapping AnyHashable container + if (srcStructDescription == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable)) { + if (_swift_anyHashableDownCastConditionalIndirect( + srcValue, destLocation, destType)) { + return DynamicCastResult::SuccessViaCopy; + } + } + break; + } + + case MetadataKind::Existential: { + auto subcastResult = tryCastUnwrappingExistentialSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + break; + } + + default: + break; + } + + //////////////////////////////////////////////////////////////////////// + // + // 4. Try recursively unwrapping Optionals. First try jointly unwrapping + // both source and destination, then just destination, then just source. + // Note that if both are optional, we try all three of these! + // For example, consider casting an Optional to + // Optional. If T conforms, we need to + // unwrap both. But if it doesn't, we unwrap just the destination + // in order to cast Optional to the protocol directly. + // + if (destKind == MetadataKind::Optional) { + if (srcKind == MetadataKind::Optional) { + auto subcastResult = tryCastUnwrappingOptionalBoth( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + auto subcastResult = tryCastUnwrappingOptionalDestination( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + if (srcKind == MetadataKind::Optional) { + auto subcastResult = tryCastUnwrappingOptionalSource( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + //////////////////////////////////////////////////////////////////////// + // + // 5. Finally, explore bridging conversions via ObjectiveCBridgeable, + // Error, and __SwiftValue boxing. + // + switch (destKind) { + + case MetadataKind::Optional: { + // Optional supports _ObjectiveCBridgeable from an unconstrained AnyObject + if (srcType->getKind() == MetadataKind::Existential) { + auto srcExistentialType = cast(srcType); + if ((srcExistentialType->getRepresentation() == ExistentialTypeRepresentation::Class) + && (srcExistentialType->NumProtocols == 0) + && (srcExistentialType->getSuperclassConstraint() == nullptr) + && (srcExistentialType->isClassBounded())) { + auto toObjCResult = tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, false); + if (isSuccess(toObjCResult)) { + return toObjCResult; + } + } + } + + break; + } + + case MetadataKind::Existential: { + // Try general machinery for stuffing values into AnyObject: + auto destExistentialType = cast(destType); + if (destExistentialType->getRepresentation() == ExistentialTypeRepresentation::Class) { + // Some types have custom Objective-C bridging support... + auto subcastResult = tryCastFromObjCBridgeableToClass( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + + // Other types can be boxed into a __SwiftValue container... + auto swiftValueCastResult = tryCastToClassExistentialViaSwiftValue( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(swiftValueCastResult)) { + return swiftValueCastResult; + } + } + break; + } + + case MetadataKind::Class: + case MetadataKind::ObjCClassWrapper: + case MetadataKind::ForeignClass: { + // Try _ObjectiveCBridgeable to bridge _to_ a class type _from_ a + // struct/enum type. Note: Despite the name, this is used for both + // Swift-Swift and Swift-ObjC bridging + if (srcKind == MetadataKind::Struct || srcKind == MetadataKind::Enum) { + auto subcastResult = tryCastFromObjCBridgeableToClass( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + +#if SWIFT_OBJC_INTEROP + if (destKind == MetadataKind::ObjCClassWrapper) { + // If the destination type is an NSError or NSObject, and the source type + // is an Error, then the cast might succeed by NSError bridging. + if (auto srcErrorWitness = findErrorWitness(srcType)) { + if (destType == getNSErrorMetadata() + || destType == getNSObjectMetadata()) { + auto flags = DynamicCastFlags::Default; + auto error = dynamicCastValueToNSError(srcValue, srcType, + srcErrorWitness, flags); + *reinterpret_cast(destLocation) = error; + return DynamicCastResult::SuccessViaCopy; + } + } + } +#endif + + break; + } + + case MetadataKind::Struct: + case MetadataKind::Enum: { + // Use _ObjectiveCBridgeable to bridge _from_ a class type _to_ a + // struct/enum type. Note: Despite the name, this is used for both + // Swift-Swift and ObjC-Swift bridging + if (srcKind == MetadataKind::Class + || srcKind == MetadataKind::ObjCClassWrapper + || srcKind == MetadataKind::ForeignClass) { + auto subcastResult = tryCastFromClassToObjCBridgeable( + destLocation, destType, srcValue, srcType, + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + if (isSuccess(subcastResult)) { + return subcastResult; + } + } + + // Note: In theory, if src and dest are both struct/enum types, we could see + // if the ObjC bridgeable class types matched and then do a two-step + // conversion from src -> bridge class -> dest. Such ambitious conversions + // might cause more harm than good, though. In particular, it could + // undermine code that uses a series of `as?` to quickly determine how to + // handle a particular object. + break; + } + + default: + break; + } + + return DynamicCastResult::Failure; +} + +/******************************************************************************/ +/****************************** Main Entrypoint *******************************/ +/******************************************************************************/ + +// XXX REMOVE ME XXX TODO XXX +// Declare the old entrypoint +SWIFT_RUNTIME_EXPORT +bool +swift_dynamicCast_OLD(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags); +// XXX REMOVE ME XXX TODO XXX + +/// ABI: Perform a dynamic cast to an arbitrary type. +static bool +swift_dynamicCastImpl(OpaqueValue *destLocation, + OpaqueValue *srcValue, + const Metadata *srcType, + const Metadata *destType, + DynamicCastFlags flags) +{ + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // Support switching to the old implementation while the new one + // is still settling. Once the new implementation is stable, + // I'll rip the old one entirely out. + static bool useOldImplementation = false; // Default: NEW Implementation + static swift_once_t Predicate; + swift_once( + &Predicate, + [](void *) { + // Define SWIFT_OLD_DYNAMIC_CAST_RUNTIME=1 to use the old runtime + // dynamic cast logic. + auto useOld = getenv("SWIFT_OLD_DYNAMIC_CAST_RUNTIME"); + if (useOld) { + useOldImplementation = true; + } + }, nullptr); + if (useOldImplementation) { + return swift_dynamicCast_OLD(destLocation, srcValue, + srcType, destType, flags); + } + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + // XXX REMOVE ME XXX TODO XXX TRANSITION SHIM + + // If the compiler has asked for a "take", we can + // move pointers without ref-counting overhead. + bool takeOnSuccess = flags & DynamicCastFlags::TakeOnSuccess; + // Unconditional casts are allowed to crash the program on failure. + // We can exploit that for performance: return a partial conversion + // immediately and do additional checks lazily when the results are + // actually accessed. + bool mayDeferChecks = flags & DynamicCastFlags::Unconditional; + + // Attempt the cast... + const Metadata *destFailureType = destType; + const Metadata *srcFailureType = srcType; + auto result = tryCast( + destLocation, destType, + srcValue, srcType, + destFailureType, srcFailureType, + takeOnSuccess, mayDeferChecks); + + switch (result) { + case DynamicCastResult::Failure: + if (flags & DynamicCastFlags::Unconditional) { + swift_dynamicCastFailure(srcFailureType, destFailureType); + } + if (flags & DynamicCastFlags::DestroyOnFailure) { + srcType->vw_destroy(srcValue); + } + return false; + case DynamicCastResult::SuccessViaCopy: + if (takeOnSuccess) { // We copied, but compiler asked for take. + srcType->vw_destroy(srcValue); + } + return true; + case DynamicCastResult::SuccessViaTake: + return true; + } +} + +#define OVERRIDE_DYNAMICCASTING COMPATIBILITY_OVERRIDE +#include "CompatibilityOverride.def" diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index c409c23731e16..fc644c7a110c4 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -336,7 +336,11 @@ static HeapObject *_swift_retain_(HeapObject *object) { } HeapObject *swift::swift_retain(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_retain(object); +#else CALL_IMPL(swift_retain, (object)); +#endif } SWIFT_RUNTIME_EXPORT @@ -358,7 +362,11 @@ static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) { } HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_retain_n(object, n); +#else CALL_IMPL(swift_retain_n, (object, n)); +#endif } SWIFT_RUNTIME_EXPORT @@ -379,7 +387,11 @@ static void _swift_release_(HeapObject *object) { } void swift::swift_release(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_release(object); +#else CALL_IMPL(swift_release, (object)); +#endif } SWIFT_RUNTIME_EXPORT @@ -399,7 +411,11 @@ static void _swift_release_n_(HeapObject *object, uint32_t n) { } void swift::swift_release_n(HeapObject *object, uint32_t n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_release_n(object, n); +#else CALL_IMPL(swift_release_n, (object, n)); +#endif } SWIFT_RUNTIME_EXPORT @@ -427,15 +443,22 @@ size_t swift::swift_weakRetainCount(HeapObject *object) { } HeapObject *swift::swift_unownedRetain(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return static_cast(swift_nonatomic_unownedRetain(object)); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain); if (!isValidPointerForNativeRetain(object)) return object; object->refCounts.incrementUnowned(1); return object; +#endif } void swift::swift_unownedRelease(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRelease(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease); if (!isValidPointerForNativeRetain(object)) return; @@ -450,6 +473,7 @@ void swift::swift_unownedRelease(HeapObject *object) { swift_slowDealloc(object, classMetadata->getInstanceSize(), classMetadata->getInstanceAlignMask()); } +#endif } void *swift::swift_nonatomic_unownedRetain(HeapObject *object) { @@ -479,15 +503,22 @@ void swift::swift_nonatomic_unownedRelease(HeapObject *object) { } HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_unownedRetain_n(object, n); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain_n); if (!isValidPointerForNativeRetain(object)) return object; object->refCounts.incrementUnowned(n); return object; +#endif } void swift::swift_unownedRelease_n(HeapObject *object, int n) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRelease_n(object, n); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease_n); if (!isValidPointerForNativeRetain(object)) return; @@ -501,6 +532,7 @@ void swift::swift_unownedRelease_n(HeapObject *object, int n) { swift_slowDealloc(object, classMetadata->getInstanceSize(), classMetadata->getInstanceAlignMask()); } +#endif } HeapObject *swift::swift_nonatomic_unownedRetain_n(HeapObject *object, int n) { @@ -533,8 +565,13 @@ static HeapObject *_swift_tryRetain_(HeapObject *object) { if (!isValidPointerForNativeRetain(object)) return nullptr; +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + if (object->refCounts.tryIncrementNonAtomic()) return object; + else return nullptr; +#else if (object->refCounts.tryIncrement()) return object; else return nullptr; +#endif } HeapObject *swift::swift_tryRetain(HeapObject *object) { @@ -557,6 +594,9 @@ void swift::swift_setDeallocating(HeapObject *object) { } HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + return swift_nonatomic_unownedRetainStrong(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrong); if (!isValidPointerForNativeRetain(object)) return object; @@ -566,6 +606,7 @@ HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { if (! object->refCounts.tryIncrement()) swift::swift_abortRetainUnowned(object); return object; +#endif } HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { @@ -581,6 +622,9 @@ HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { } void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + swift_nonatomic_unownedRetainStrongAndRelease(object); +#else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrongAndRelease); if (!isValidPointerForNativeRetain(object)) return; @@ -594,6 +638,7 @@ void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { bool dealloc = object->refCounts.decrementUnownedShouldFree(1); assert(!dealloc && "retain-strong-and-release caused dealloc?"); (void) dealloc; +#endif } void swift::swift_nonatomic_unownedRetainStrongAndRelease(HeapObject *object) { diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 1dfe45dd8c62f..a8e9f2a1b81eb 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -2916,24 +2916,22 @@ getSuperclassMetadata(MetadataRequest request, const ClassMetadata *self) { StringRef superclassName = Demangle::makeSymbolicMangledNameStringRef(superclassNameBase); SubstGenericParametersFromMetadata substitutions(self); - MetadataResponse response = - swift_getTypeByMangledName(request, superclassName, - substitutions.getGenericArgs(), + auto result = swift_getTypeByMangledName( + request, superclassName, substitutions.getGenericArgs(), [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getResponse(); - auto superclass = response.Value; - if (!superclass) { - fatalError(0, - "failed to demangle superclass of %s from mangled name '%s'\n", - self->getDescription()->Name.get(), - superclassName.str().c_str()); + }); + if (auto *error = result.getError()) { + fatalError( + 0, "failed to demangle superclass of %s from mangled name '%s': %s\n", + self->getDescription()->Name.get(), superclassName.str().c_str(), + error->copyErrorString()); } - return response; + return result.getType().getResponse(); } else { return MetadataResponse(); } @@ -4928,12 +4926,12 @@ swift_getAssociatedTypeWitnessSlowImpl( Demangle::makeSymbolicMangledNameStringRef(mangledNameBase); // Demangle the associated type. - MetadataResponse response; + TypeLookupErrorOr result = TypeInfo(); if (inProtocolContext) { // The protocol's Self is the only generic parameter that can occur in the // type. - response = - swift_getTypeByMangledName(request, mangledName, nullptr, + result = swift_getTypeByMangledName( + request, mangledName, nullptr, [conformingType](unsigned depth, unsigned index) -> const Metadata * { if (depth == 0 && index == 0) return conformingType; @@ -4950,7 +4948,7 @@ swift_getAssociatedTypeWitnessSlowImpl( return swift_getAssociatedConformanceWitness(wtable, conformingType, type, reqBase, dependentDescriptor); - }).getResponse(); + }); } else { // The generic parameters in the associated type name are those of the // conforming type. @@ -4960,29 +4958,30 @@ swift_getAssociatedTypeWitnessSlowImpl( auto originalConformingType = findConformingSuperclass(conformingType, conformance); SubstGenericParametersFromMetadata substitutions(originalConformingType); - response = swift_getTypeByMangledName(request, mangledName, - substitutions.getGenericArgs(), - [&substitutions](unsigned depth, unsigned index) { - return substitutions.getMetadata(depth, index); - }, - [&substitutions](const Metadata *type, unsigned index) { - return substitutions.getWitnessTable(type, index); - }).getResponse(); + result = swift_getTypeByMangledName( + request, mangledName, substitutions.getGenericArgs(), + [&substitutions](unsigned depth, unsigned index) { + return substitutions.getMetadata(depth, index); + }, + [&substitutions](const Metadata *type, unsigned index) { + return substitutions.getWitnessTable(type, index); + }); } + auto *error = result.getError(); + MetadataResponse response = result.getType().getResponse(); auto assocTypeMetadata = response.Value; - - if (!assocTypeMetadata) { + if (error || !assocTypeMetadata) { + const char *errStr = error ? error->copyErrorString() + : "NULL metadata but no error was provided"; auto conformingTypeNameInfo = swift_getTypeName(conformingType, true); StringRef conformingTypeName(conformingTypeNameInfo.data, conformingTypeNameInfo.length); StringRef assocTypeName = findAssociatedTypeName(protocol, assocType); fatalError(0, "failed to demangle witness for associated type '%s' in " - "conformance '%s: %s' from mangled name '%s'\n", - assocTypeName.str().c_str(), - conformingTypeName.str().c_str(), - protocol->Name.get(), - mangledName.str().c_str()); + "conformance '%s: %s' from mangled name '%s' - %s\n", + assocTypeName.str().c_str(), conformingTypeName.str().c_str(), + protocol->Name.get(), mangledName.str().c_str(), errStr); } assert((uintptr_t(assocTypeMetadata) & @@ -5935,7 +5934,7 @@ void swift::verifyMangledNameRoundtrip(const Metadata *metadata) { nullptr, [](unsigned, unsigned){ return nullptr; }, [](const Metadata *, unsigned) { return nullptr; }) - .getMetadata(); + .getType().getMetadata(); if (metadata != result) swift::warning(RuntimeErrorFlagNone, "Metadata mangled name failed to roundtrip: %p -> %s -> %p\n", diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h index 1b12fc1000f26..ac455a8cc9938 100644 --- a/stdlib/public/runtime/MetadataImpl.h +++ b/stdlib/public/runtime/MetadataImpl.h @@ -136,7 +136,7 @@ template struct RetainableBoxBase { static constexpr size_t stride = sizeof(T); static constexpr bool isPOD = false; static constexpr bool isBitwiseTakable = true; -#ifdef SWIFT_STDLIB_USE_NONATOMIC_RC +#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME static constexpr bool isAtomic = false; #else static constexpr bool isAtomic = true; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 93ed4227928eb..c0c2f7c0c4c9d 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -961,13 +961,54 @@ getLocalGenericParams(const ContextDescriptor *context) { return genericContext->getGenericParams().slice(startParamIndex); } -static bool +static llvm::Optional _gatherGenericParameters(const ContextDescriptor *context, llvm::ArrayRef genericArgs, const Metadata *parent, llvm::SmallVectorImpl &genericParamCounts, llvm::SmallVectorImpl &allGenericArgsVec, Demangler &demangler) { + auto makeCommonErrorStringGetter = [&] { + auto metadataVector = genericArgs.vec(); + return [=] { + std::string str; + + str += "_gatherGenericParameters: context: "; + + SymbolInfo contextInfo; + if (lookupSymbol(context, &contextInfo)) { + str += contextInfo.symbolName.get(); + str += " "; + } + + char *contextStr; + swift_asprintf(&contextStr, "%p", context); + str += contextStr; + free(contextStr); + + str += " <"; + + bool first = true; + for (const Metadata *metadata : genericArgs) { + if (!first) + str += ", "; + first = false; + str += nameForMetadata(metadata); + } + + str += "> "; + + str += "parent: "; + if (parent) + str += nameForMetadata(parent); + else + str += ""; + str += " - "; + + return str; + }; + }; + // Figure out the various levels of generic parameters we have in // this type. (void)_gatherGenericParameterCounts(context, @@ -981,7 +1022,15 @@ _gatherGenericParameters(const ContextDescriptor *context, } else if (genericArgs.size() == numTotalGenericParams && !parent) { // Okay: genericArgs is the complete set of generic arguments. } else { - return false; + auto commonString = makeCommonErrorStringGetter(); + auto genericArgsSize = genericArgs.size(); + return TypeLookupError([=] { + return commonString() + "incorrect number of generic args (" + + std::to_string(genericArgsSize) + "), " + + std::to_string(getLocalGenericParams(context).size()) + + " local params, " + std::to_string(numTotalGenericParams) + + " total params"; + }); } // If there are generic parameters at any level, check the generic @@ -1008,15 +1057,30 @@ _gatherGenericParameters(const ContextDescriptor *context, auto genericParams = generics->getGenericParams(); unsigned n = genericParams.size(); if (allGenericArgs.size() != n) { - return false; + auto commonString = makeCommonErrorStringGetter(); + auto argsVecSize = allGenericArgsVec.size(); + return TypeLookupError([=] { + return commonString() + "have " + std::to_string(argsVecSize) + + "generic args, expected " + std::to_string(n); + }); } for (unsigned i = 0; i != n; ++i) { const auto ¶m = genericParams[i]; - if (param.getKind() != GenericParamKind::Type) - return false; - if (param.hasExtraArgument()) - return false; - + if (param.getKind() != GenericParamKind::Type) { + auto commonString = makeCommonErrorStringGetter(); + return TypeLookupError([=] { + return commonString() + "param " + std::to_string(i) + + " has unexpected kind " + + std::to_string(static_cast(param.getKind())); + }); + } + if (param.hasExtraArgument()) { + auto commonString = makeCommonErrorStringGetter(); + return TypeLookupError([=] { + return commonString() + "param " + std::to_string(i) + + "has extra argument"; + }); + } if (param.hasKeyArgument()) allGenericArgsVec.push_back(allGenericArgs[i]); } @@ -1028,26 +1092,33 @@ _gatherGenericParameters(const ContextDescriptor *context, // any extra arguments we need for the instantiation function. SubstGenericParametersFromWrittenArgs substitutions(allGenericArgs, genericParamCounts); - bool failed = - _checkGenericRequirements(generics->getGenericRequirements(), - allGenericArgsVec, + auto error = _checkGenericRequirements( + generics->getGenericRequirements(), allGenericArgsVec, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); }); - if (failed) - return false; + if (error) + return *error; // If we still have the wrong number of generic arguments, this is // some kind of metadata mismatch. if (generics->getGenericContextHeader().getNumArguments() != - allGenericArgsVec.size()) - return false; + allGenericArgsVec.size()) { + auto commonString = makeCommonErrorStringGetter(); + auto argsVecSize = allGenericArgsVec.size(); + return TypeLookupError([=] { + return commonString() + "generic argument count mismatch, expected " + + std::to_string( + generics->getGenericContextHeader().getNumArguments()) + + ", have " + std::to_string(argsVecSize); + }); + } } - return true; + return llvm::None; } namespace { @@ -1175,7 +1246,7 @@ class DecodedMetadataBuilder { Demangle::NodeFactory &getNodeFactory() { return demangler; } - BuiltType + TypeLookupErrorOr resolveOpaqueType(NodePointer opaqueDecl, llvm::ArrayRef> genericArgs, unsigned ordinal) { @@ -1193,12 +1264,10 @@ class DecodedMetadataBuilder { llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgsVec; - if (!_gatherGenericParameters(outerContext, - allGenericArgs, - BuiltType(), /* no parent */ - genericParamCounts, allGenericArgsVec, - demangler)) - return BuiltType(); + if (auto error = _gatherGenericParameters( + outerContext, allGenericArgs, BuiltType(), /* no parent */ + genericParamCounts, allGenericArgsVec, demangler)) + return *error; auto mangledName = descriptor->getUnderlyingTypeArgument(ordinal); SubstGenericParametersFromMetadata substitutions(descriptor, @@ -1210,7 +1279,7 @@ class DecodedMetadataBuilder { }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } BuiltTypeDecl createTypeDecl(NodePointer node, @@ -1245,8 +1314,9 @@ class DecodedMetadataBuilder { return ProtocolDescriptorRef(); #endif } - - BuiltType createObjCClassType(const std::string &mangledName) const { + + TypeLookupErrorOr + createObjCClassType(const std::string &mangledName) const { #if SWIFT_OBJC_INTEROP auto objcClass = objc_getClass(mangledName.c_str()); return swift_getObjCClassMetadata((const ClassMetadata *)objcClass); @@ -1255,7 +1325,7 @@ class DecodedMetadataBuilder { #endif } - BuiltType + TypeLookupErrorOr createBoundGenericObjCClassType(const std::string &mangledName, llvm::ArrayRef args) const { // Generic arguments of lightweight Objective-C generic classes are not @@ -1263,24 +1333,25 @@ class DecodedMetadataBuilder { return createObjCClassType(mangledName); } - BuiltType createNominalType(BuiltTypeDecl metadataOrTypeDecl, - BuiltType parent) const { + TypeLookupErrorOr + createNominalType(BuiltTypeDecl metadataOrTypeDecl, BuiltType parent) const { // Treat nominal type creation the same way as generic type creation, // but with no generic arguments at this level. return createBoundGenericType(metadataOrTypeDecl, { }, parent); } - BuiltType createTypeAliasType(BuiltTypeDecl typeAliasDecl, - BuiltType parent) const { + TypeLookupErrorOr createTypeAliasType(BuiltTypeDecl typeAliasDecl, + BuiltType parent) const { // We can't support sugared types here since we have no way to // resolve the underlying type of the type alias. However, some // CF types are mangled as type aliases. return createNominalType(typeAliasDecl, parent); } - BuiltType createBoundGenericType(BuiltTypeDecl anyTypeDecl, - llvm::ArrayRef genericArgs, - BuiltType parent) const { + TypeLookupErrorOr + createBoundGenericType(BuiltTypeDecl anyTypeDecl, + llvm::ArrayRef genericArgs, + BuiltType parent) const { auto typeDecl = dyn_cast(anyTypeDecl); if (!typeDecl) { if (auto protocol = dyn_cast(anyTypeDecl)) @@ -1294,13 +1365,11 @@ class DecodedMetadataBuilder { llvm::SmallVector genericParamCounts; llvm::SmallVector allGenericArgsVec; - if (!_gatherGenericParameters(typeDecl, - genericArgs, - parent, - genericParamCounts, allGenericArgsVec, - demangler)) - return BuiltType(); - + if (auto error = _gatherGenericParameters(typeDecl, genericArgs, parent, + genericParamCounts, + allGenericArgsVec, demangler)) + return *error; + // Call the access function. auto accessFunction = typeDecl->getAccessFunction(); if (!accessFunction) return BuiltType(); @@ -1308,8 +1377,8 @@ class DecodedMetadataBuilder { return accessFunction(MetadataState::Abstract, allGenericArgsVec).Value; } - BuiltType createBuiltinType(StringRef builtinName, - StringRef mangledName) const { + TypeLookupErrorOr createBuiltinType(StringRef builtinName, + StringRef mangledName) const { #define BUILTIN_TYPE(Symbol, _) \ if (mangledName.equals(#Symbol)) \ return &METADATA_SYM(Symbol).base; @@ -1317,19 +1386,19 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType createMetatypeType( + TypeLookupErrorOr createMetatypeType( BuiltType instance, llvm::Optional repr = None) const { return swift_getMetatypeMetadata(instance); } - BuiltType createExistentialMetatypeType( + TypeLookupErrorOr createExistentialMetatypeType( BuiltType instance, llvm::Optional repr = None) const { return swift_getExistentialMetatypeMetadata(instance); } - BuiltType + TypeLookupErrorOr createProtocolCompositionType(llvm::ArrayRef protocols, BuiltType superclass, bool isClassBound) const { // Determine whether we have a class bound. @@ -1349,13 +1418,13 @@ class DecodedMetadataBuilder { protocols.size(), protocols.data()); } - BuiltType createDynamicSelfType(BuiltType selfType) const { + TypeLookupErrorOr createDynamicSelfType(BuiltType selfType) const { // Free-standing mangled type strings should not contain DynamicSelfType. return BuiltType(); } - BuiltType createGenericTypeParameterType(unsigned depth, - unsigned index) const { + TypeLookupErrorOr + createGenericTypeParameterType(unsigned depth, unsigned index) const { // Use the callback, when provided. if (substGenericParameter) return substGenericParameter(depth, index); @@ -1363,7 +1432,7 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType + TypeLookupErrorOr createFunctionType(llvm::ArrayRef> params, BuiltType result, FunctionTypeFlags flags) const { llvm::SmallVector paramTypes; @@ -1386,7 +1455,7 @@ class DecodedMetadataBuilder { result); } - BuiltType createImplFunctionType( + TypeLookupErrorOr createImplFunctionType( Demangle::ImplParameterConvention calleeConvention, llvm::ArrayRef> params, llvm::ArrayRef> results, @@ -1396,8 +1465,9 @@ class DecodedMetadataBuilder { return BuiltType(); } - BuiltType createTupleType(llvm::ArrayRef elements, - std::string labels) const { + TypeLookupErrorOr + createTupleType(llvm::ArrayRef elements, + std::string labels) const { auto flags = TupleTypeFlags().withNumElements(elements.size()); if (!labels.empty()) flags = flags.withNonConstantLabels(true); @@ -1408,13 +1478,15 @@ class DecodedMetadataBuilder { .Value; } - BuiltType createDependentMemberType(StringRef name, BuiltType base) const { + TypeLookupErrorOr createDependentMemberType(StringRef name, + BuiltType base) const { // Should not have unresolved dependent member types here. return BuiltType(); } - BuiltType createDependentMemberType(StringRef name, BuiltType base, - BuiltProtocolDecl protocol) const { + TypeLookupErrorOr + createDependentMemberType(StringRef name, BuiltType base, + BuiltProtocolDecl protocol) const { #if SWIFT_OBJC_INTEROP if (protocol.isObjC()) return BuiltType(); @@ -1438,14 +1510,14 @@ class DecodedMetadataBuilder { *assocType).Value; } -#define REF_STORAGE(Name, ...) \ - BuiltType create##Name##StorageType(BuiltType base) { \ - ReferenceOwnership.set##Name(); \ - return base; \ +#define REF_STORAGE(Name, ...) \ + TypeLookupErrorOr create##Name##StorageType(BuiltType base) { \ + ReferenceOwnership.set##Name(); \ + return base; \ } #include "swift/AST/ReferenceStorage.def" - BuiltType createSILBoxType(BuiltType base) const { + TypeLookupErrorOr createSILBoxType(BuiltType base) const { // FIXME: Implement. return BuiltType(); } @@ -1454,22 +1526,23 @@ class DecodedMetadataBuilder { return ReferenceOwnership; } - BuiltType createOptionalType(BuiltType base) { + TypeLookupErrorOr createOptionalType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createArrayType(BuiltType base) { + TypeLookupErrorOr createArrayType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createDictionaryType(BuiltType key, BuiltType value) { + TypeLookupErrorOr createDictionaryType(BuiltType key, + BuiltType value) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } - BuiltType createParenType(BuiltType base) { + TypeLookupErrorOr createParenType(BuiltType base) { // Mangled types for building metadata don't contain sugared types return BuiltType(); } @@ -1478,13 +1551,12 @@ class DecodedMetadataBuilder { } SWIFT_CC(swift) -static TypeInfo swift_getTypeByMangledNodeImpl( - MetadataRequest request, - Demangler &demangler, - Demangle::NodePointer node, - const void * const *origArgumentVector, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +static TypeLookupErrorOr +swift_getTypeByMangledNodeImpl(MetadataRequest request, Demangler &demangler, + Demangle::NodePointer node, + const void *const *origArgumentVector, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { // Simply call an accessor function if that's all we got. if (node->getKind() == Node::Kind::AccessorFunctionReference) { // The accessor function is passed the pointer to the original argument @@ -1504,22 +1576,23 @@ static TypeInfo swift_getTypeByMangledNodeImpl( DecodedMetadataBuilder builder(demangler, substGenericParam, substWitnessTable); auto type = Demangle::decodeMangledType(builder, node); - if (!type) { - return {MetadataResponse{nullptr, MetadataState::Complete}, - TypeReferenceOwnership()}; + if (type.isError()) { + return *type.getError(); + } + if (!type.getType()) { + return TypeLookupError("NULL type but no error provided"); } - return {swift_checkMetadataState(request, type), - builder.getReferenceOwnership()}; + return TypeInfo{swift_checkMetadataState(request, type.getType()), + builder.getReferenceOwnership()}; } SWIFT_CC(swift) -static TypeInfo swift_getTypeByMangledNameImpl( - MetadataRequest request, - StringRef typeName, - const void * const *origArgumentVector, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +static TypeLookupErrorOr +swift_getTypeByMangledNameImpl(MetadataRequest request, StringRef typeName, + const void *const *origArgumentVector, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { DemanglerForRuntimeTypeResolution> demangler; NodePointer node; @@ -1587,7 +1660,7 @@ swift_getTypeByMangledNameInEnvironment( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1607,7 +1680,7 @@ swift_getTypeByMangledNameInEnvironmentInMetadataState( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1626,7 +1699,7 @@ swift_getTypeByMangledNameInContext( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1646,7 +1719,7 @@ swift_getTypeByMangledNameInContextInMetadataState( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); } /// Demangle a mangled name, but don't allow symbolic references. @@ -1661,7 +1734,7 @@ swift_stdlib_getTypeByMangledNameUntrusted(const char *typeNameStart, } return swift_getTypeByMangledName(MetadataState::Complete, typeName, nullptr, - {}, {}).getMetadata(); + {}, {}).getType().getMetadata(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1680,7 +1753,7 @@ swift_getOpaqueTypeMetadata(MetadataRequest request, }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getResponse(); + }).getType().getResponse(); } SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT @@ -1735,7 +1808,7 @@ getObjCClassByMangledName(const char * _Nonnull typeName, }, [&](const Metadata *type, unsigned index) { return nullptr; - }).getMetadata(); + }).getType().getMetadata(); } else { metadata = swift_stdlib_getTypeByMangledNameUntrusted(typeStr.data(), typeStr.size()); @@ -2068,7 +2141,7 @@ void swift::gatherWrittenGenericArgs( }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); - }).getMetadata(); + }).getType().getMetadata(); continue; } diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index c46e8ff9a9b38..2f5e7232cc55d 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -17,7 +17,10 @@ #ifndef SWIFT_RUNTIME_PRIVATE_H #define SWIFT_RUNTIME_PRIVATE_H +#include + #include "swift/Demangling/Demangler.h" +#include "swift/Demangling/TypeLookupError.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Metadata.h" @@ -77,6 +80,8 @@ class TypeInfo { const Metadata *getMetadata() const { return Response.Value; } MetadataResponse getResponse() const { return Response; } + operator bool() const { return getMetadata(); } + #define REF_STORAGE(Name, ...) \ bool is##Name() const { return ReferenceOwnership.is##Name(); } #include "swift/AST/ReferenceStorage.def" @@ -369,7 +374,7 @@ class TypeInfo { /// \p substWitnessTable Function that provides witness tables given a /// particular dependent conformance index. SWIFT_CC(swift) - TypeInfo swift_getTypeByMangledNode( + TypeLookupErrorOr swift_getTypeByMangledNode( MetadataRequest request, Demangler &demangler, Demangle::NodePointer node, @@ -384,7 +389,7 @@ class TypeInfo { /// \p substWitnessTable Function that provides witness tables given a /// particular dependent conformance index. SWIFT_CC(swift) - TypeInfo swift_getTypeByMangledName( + TypeLookupErrorOr swift_getTypeByMangledName( MetadataRequest request, StringRef typeName, const void * const *arguments, @@ -447,12 +452,12 @@ class TypeInfo { /// generic requirements (e.g., those that need to be /// passed to an instantiation function) will be added to this vector. /// - /// \returns true if an error occurred, false otherwise. - bool _checkGenericRequirements( - llvm::ArrayRef requirements, - llvm::SmallVectorImpl &extraArguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable); + /// \returns the error if an error occurred, None otherwise. + llvm::Optional _checkGenericRequirements( + llvm::ArrayRef requirements, + llvm::SmallVectorImpl &extraArguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable); /// A helper function which avoids performing a store if the destination /// address already contains the source value. This is useful when diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index e373d2a50848e..c434011faea85 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -165,15 +165,16 @@ ProtocolConformanceDescriptor::getWitnessTable(const Metadata *type) const { llvm::SmallVector conditionalArgs; if (hasConditionalRequirements()) { SubstGenericParametersFromMetadata substitutions(type); - bool failed = - _checkGenericRequirements(getConditionalRequirements(), conditionalArgs, + auto error = _checkGenericRequirements( + getConditionalRequirements(), conditionalArgs, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index); }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); }); - if (failed) return nullptr; + if (error) + return nullptr; } return swift_getWitnessTable(this, type, conditionalArgs.data()); @@ -642,31 +643,36 @@ static bool isSubclass(const Metadata *subclass, const Metadata *superclass) { }); } -bool swift::_checkGenericRequirements( - llvm::ArrayRef requirements, - llvm::SmallVectorImpl &extraArguments, - SubstGenericParameterFn substGenericParam, - SubstDependentWitnessTableFn substWitnessTable) { +llvm::Optional swift::_checkGenericRequirements( + llvm::ArrayRef requirements, + llvm::SmallVectorImpl &extraArguments, + SubstGenericParameterFn substGenericParam, + SubstDependentWitnessTableFn substWitnessTable) { for (const auto &req : requirements) { // Make sure we understand the requirement we're dealing with. - if (!req.hasKnownKind()) return true; + if (!req.hasKnownKind()) + return TypeLookupError("unknown kind"); // Resolve the subject generic parameter. - const Metadata *subjectType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getParam(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!subjectType) - return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getParam(), extraArguments.data(), + substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + const Metadata *subjectType = result.getType().getMetadata(); // Check the requirement. switch (req.getKind()) { case GenericRequirementKind::Protocol: { const WitnessTable *witnessTable = nullptr; if (!_conformsToProtocol(nullptr, subjectType, req.getProtocol(), - &witnessTable)) - return true; + &witnessTable)) { + const char *protoName = + req.getProtocol() ? req.getProtocol().getName() : ""; + return TypeLookupError( + "subject type %s does not conform to protocol %s", req.getParam(), + protoName); + } // If we need a witness table, add it. if (req.getProtocol().needsWitnessTable()) { @@ -679,17 +685,19 @@ bool swift::_checkGenericRequirements( case GenericRequirementKind::SameType: { // Demangle the second type under the given substitutions. - auto otherType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getMangledTypeName(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!otherType) return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getMangledTypeName(), + extraArguments.data(), substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + auto otherType = result.getType().getMetadata(); assert(!req.getFlags().hasExtraArgument()); // Check that the types are equivalent. - if (subjectType != otherType) return true; + if (subjectType != otherType) + return TypeLookupError("subject type %s does not match %s", + req.getParam(), req.getMangledTypeName()); continue; } @@ -698,22 +706,24 @@ bool swift::_checkGenericRequirements( switch (req.getLayout()) { case GenericRequirementLayoutKind::Class: if (!subjectType->satisfiesClassConstraint()) - return true; + return TypeLookupError( + "subject type %s does not satisfy class constraint", + req.getParam()); continue; } // Unknown layout. - return true; + return TypeLookupError("unknown layout kind %u", req.getLayout()); } case GenericRequirementKind::BaseClass: { // Demangle the base type under the given substitutions. - auto baseType = - swift_getTypeByMangledName(MetadataState::Abstract, - req.getMangledTypeName(), - extraArguments.data(), - substGenericParam, substWitnessTable).getMetadata(); - if (!baseType) return true; + auto result = swift_getTypeByMangledName( + MetadataState::Abstract, req.getMangledTypeName(), + extraArguments.data(), substGenericParam, substWitnessTable); + if (result.getError()) + return *result.getError(); + auto baseType = result.getType().getMetadata(); // If the type which is constrained to a base class is an existential // type, and if that existential type includes a superclass constraint, @@ -725,7 +735,8 @@ bool swift::_checkGenericRequirements( } if (!isSubclass(subjectType, baseType)) - return true; + return TypeLookupError("%s is not subclass of %s", req.getParam(), + req.getMangledTypeName()); continue; } @@ -737,11 +748,12 @@ bool swift::_checkGenericRequirements( } // Unknown generic requirement kind. - return true; + return TypeLookupError("unknown generic requirement kind %u", + req.getKind()); } // Success! - return false; + return llvm::None; } const Metadata *swift::findConformingSuperclass( diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm index 821fecfb7fb0b..0206237d2b44b 100644 --- a/stdlib/public/runtime/ReflectionMirror.mm +++ b/stdlib/public/runtime/ReflectionMirror.mm @@ -400,27 +400,33 @@ static bool _shouldReportMissingReflectionMetadataWarnings() { auto typeName = field.getMangledTypeName(); SubstGenericParametersFromMetadata substitutions(base); - auto typeInfo = swift_getTypeByMangledName(MetadataState::Complete, - typeName, - substitutions.getGenericArgs(), - [&substitutions](unsigned depth, unsigned index) { - return substitutions.getMetadata(depth, index); - }, - [&substitutions](const Metadata *type, unsigned index) { - return substitutions.getWitnessTable(type, index); - }); + auto result = swift_getTypeByMangledName( + MetadataState::Complete, typeName, substitutions.getGenericArgs(), + [&substitutions](unsigned depth, unsigned index) { + return substitutions.getMetadata(depth, index); + }, + [&substitutions](const Metadata *type, unsigned index) { + return substitutions.getWitnessTable(type, index); + }); // If demangling the type failed, pretend it's an empty type instead with // a log message. - if (!typeInfo.getMetadata()) { + TypeInfo typeInfo; + if (result.isError()) { typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING), MetadataState::Complete}, {}); + + auto *error = result.getError(); + char *str = error->copyErrorString(); missing_reflection_metadata_warning( - "warning: the Swift runtime was unable to demangle the type " - "of field '%*s'. the mangled type name is '%*s'. this field will " - "show up as an empty tuple in Mirrors\n", - (int)name.size(), name.data(), - (int)typeName.size(), typeName.data()); + "warning: the Swift runtime was unable to demangle the type " + "of field '%*s'. the mangled type name is '%*s': %s. this field will " + "show up as an empty tuple in Mirrors\n", + (int)name.size(), name.data(), (int)typeName.size(), typeName.data(), + str); + error->freeErrorString(str); + } else { + typeInfo = result.getType(); } auto fieldType = FieldType(typeInfo.getMetadata()); diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index f377a77d6f106..ba33dd19abd69 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -26,11 +26,13 @@ #include "llvm/ADT/StringRef.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/Casting.h" +#include "swift/Runtime/Debug.h" #include "swift/Runtime/EnvironmentVariables.h" #include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "swift/Runtime/ObjCBridge.h" +#include "swift/Runtime/Portability.h" #include "swift/Strings.h" #include "../SwiftShims/RuntimeShims.h" #include "../SwiftShims/AssertionReporting.h" @@ -39,7 +41,6 @@ #include "Private.h" #include "SwiftObject.h" #include "WeakReference.h" -#include "swift/Runtime/Debug.h" #if SWIFT_OBJC_INTEROP #include #endif diff --git a/stdlib/public/stubs/Assert.cpp b/stdlib/public/stubs/Assert.cpp index 62135b2312b1c..fa0169a5ad6b8 100644 --- a/stdlib/public/stubs/Assert.cpp +++ b/stdlib/public/stubs/Assert.cpp @@ -12,6 +12,7 @@ #include "swift/Runtime/Config.h" #include "swift/Runtime/Debug.h" +#include "swift/Runtime/Portability.h" #include "../SwiftShims/AssertionReporting.h" #include #include diff --git a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift index 331a48a425c2c..5248811b04aa0 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_control_flow_diagnostics.swift @@ -171,7 +171,7 @@ func loop_array(_ array: [Float]) -> Float { var result: Float = 1 // TODO(TF-957): Improve non-differentiability errors for for-in loops // (`Collection.makeIterator` and `IteratorProtocol.next`). - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{12-12=withoutDerivative(at: }} {{17-17=)}} for x in array { result = result * x } diff --git a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift index cbb4e0fa132f7..22d3fca6a17c3 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift @@ -301,14 +301,14 @@ struct TF_687 : Differentiable { } } // expected-error @+2 {{function is not differentiable}} -// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} +// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{78-78=withoutDerivative(at: }} {{79-79=)}} let _: @differentiable (Float) -> TF_687 = { x in TF_687(x, dummy: x) } // expected-error @+1 {{function is not differentiable}} @differentiable // expected-note @+1 {{when differentiating this function definition}} func roundingGivesError(x: Float) -> Float { - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{16-16=withoutDerivative(at: }} {{22-22=)}} return Float(Int(x)) } @@ -688,7 +688,7 @@ func differentiableProjectedValueAccess(_ s: Struct) -> Float { // expected-note @+2 {{when differentiating this function definition}} @differentiable func projectedValueAccess(_ s: Struct) -> Float { - // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?}} {{3-3=withoutDerivative(at: }} {{7-7=)}} s.$y.wrappedValue } @@ -714,7 +714,7 @@ func modify(_ s: Struct, _ x: Float) -> Float { func tupleArrayLiteralInitialization(_ x: Float, _ y: Float) -> Float { // `Array<(Float, Float)>` does not conform to `Differentiable`. let array = [(x * y, x * y)] - // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} + // expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{10-10=withoutDerivative(at: }} {{15-15=)}} return array[0].0 } diff --git a/test/AutoDiff/downstream/implicit_nonpublic_differentiable_attr_type_checking.swift b/test/AutoDiff/downstream/implicit_nonpublic_differentiable_attr_type_checking.swift index 63ca9f642166b..36532957495b9 100644 --- a/test/AutoDiff/downstream/implicit_nonpublic_differentiable_attr_type_checking.swift +++ b/test/AutoDiff/downstream/implicit_nonpublic_differentiable_attr_type_checking.swift @@ -3,24 +3,12 @@ // Test implicit `@differentiable` attributes for non-public protocol witnesses. protocol InternalProtocol: Differentiable { - // expected-note @+3 {{protocol requires function 'publicMethod' with type '(Float) -> Float'}} - @differentiable(wrt: self) - @differentiable(wrt: (self, x)) - func publicMethod(_ x: Float) -> Float - @differentiable(wrt: self) @differentiable(wrt: (self, x)) func internalMethod(_ x: Float) -> Float } -// expected-error @+1 {{type 'PublicConformingStruct' does not conform to protocol 'InternalProtocol'}} public struct PublicConformingStruct: InternalProtocol { - // Expected: error for missing `@differentiable` attribute on public protocol witness. - // expected-note @+1 {{candidate is missing attribute '@differentiable'}} - public func publicMethod(_ x: Float) -> Float { - x - } - // Expected: no error for missing `@differentiable` attribute on internal protocol witness. // Implicit `@differentiable` attributes should be created. func internalMethod(_ x: Float) -> Float { @@ -29,7 +17,6 @@ public struct PublicConformingStruct: InternalProtocol { } // CHECK-LABEL: public struct PublicConformingStruct : InternalProtocol { -// CHECK: public func publicMethod(_ x: Float) -> Float // CHECK: @differentiable(wrt: (self, x)) // CHECK: @differentiable(wrt: self) // CHECK: internal func internalMethod(_ x: Float) -> Float diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3fec4ee99da67..5fc15905342bd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -354,7 +354,7 @@ _Block_release(void) { }\n") endif() execute_process(COMMAND - $ "-c" "import psutil" + $ "-c" "import psutil" RESULT_VARIABLE python_psutil_status TIMEOUT 1 # second ERROR_QUIET) @@ -418,7 +418,7 @@ _Block_release(void) { }\n") ${command_upload_swift_reflection_test} ${command_clean_test_results_dir} COMMAND - $ "${LIT}" + $ "${LIT}" ${LIT_ARGS} "--param" "swift_test_subset=${test_subset}" "--param" "swift_test_mode=${test_mode}" @@ -437,7 +437,7 @@ _Block_release(void) { }\n") ${command_upload_swift_reflection_test} ${command_clean_test_results_dir} COMMAND - $ "${LIT}" + $ "${LIT}" ${LIT_ARGS} "--param" "swift_test_subset=${test_subset}" "--param" "swift_test_mode=${test_mode}" diff --git a/test/stdlib/CastTraps.swift.gyb b/test/Casting/CastTraps.swift.gyb similarity index 61% rename from test/stdlib/CastTraps.swift.gyb rename to test/Casting/CastTraps.swift.gyb index e5608874d028d..95c7cbbebfe31 100644 --- a/test/stdlib/CastTraps.swift.gyb +++ b/test/Casting/CastTraps.swift.gyb @@ -5,17 +5,17 @@ // FIXME: Casting.cpp has dozens of places to fail a cast. This test does not // attempt to enumerate them all. -// REQUIRES: objc_interop - import StdlibUnittest - +#if _runtime(_ObjC) import Foundation +#endif % types = [] % objectTypes = [] % protocolTypes = [] +% ObjCTypes = [] % types.append(['main.Class1', 'main.Class2']) % objectTypes.append(['main.Class1', 'main.Class2']) @@ -28,11 +28,15 @@ struct Struct2 { } % types.append(['main.ObjCClass1', 'main.ObjCClass2']) % objectTypes.append(['main.ObjCClass1', 'main.ObjCClass2']) +% ObjCTypes.extend(['main.ObjCClass1', 'main.ObjCClass2']) +#if _runtime(_ObjC) class ObjCClass1 : NSObject { } class ObjCClass2 : NSObject { } +#endif % types.append(['DateFormatter', 'NumberFormatter']) % objectTypes.append(['DateFormatter', 'NumberFormatter']) +% ObjCTypes.extend(['DateFormatter', 'NumberFormatter']) // non-Swift Objective-C class % protocolTypes.append('main.Proto1') @@ -40,6 +44,7 @@ class ObjCClass2 : NSObject { } protocol Proto1 { } protocol Proto2 { } % protocolTypes.append('URLSessionDelegate') +% ObjCTypes.append('URLSessionDelegate') // non-Swift Objective-C protocol @@ -51,6 +56,7 @@ var CastTrapsTestSuite = TestSuite("CastTraps") % for (t1, _) in types: % for (_, t2) in types: +% if t1 not in ObjCTypes and t2 not in ObjCTypes: CastTrapsTestSuite.test("${t1}__${t2}") .skip(.custom( { _isFastAssertConfiguration() }, @@ -67,6 +73,7 @@ CastTrapsTestSuite.test("${t1}__${t2}") _blackHole(r) } +% end % end % end @@ -76,6 +83,7 @@ CastTrapsTestSuite.test("${t1}__${t2}") % for (t1, _) in objectTypes: % for (t2) in protocolTypes: +% if t1 not in ObjCTypes and t2 not in ObjCTypes: CastTrapsTestSuite.test("${t1}__${t2}") .skip(.custom( { _isFastAssertConfiguration() }, @@ -92,7 +100,47 @@ CastTrapsTestSuite.test("${t1}__${t2}") _blackHole(r) } +% end % end % end +protocol P2 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastTrapsTestSuite.test("Unexpected null") + .crashOutputMatches("Found unexpected null pointer value while trying to cast value of type '") + .crashOutputMatches("Foo'") + .crashOutputMatches(" to '") + .crashOutputMatches("P2'") + .code +{ + class Foo {} + let n = UnsafeRawPointer(bitPattern: 0) + var o: Foo = unsafeBitCast(n, to: Foo.self) + let r = o as Any + expectCrashLater() + let s = r as? P2 + _blackHole(s) +} +} + + +#if _runtime(_ObjC) +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastTrapsTestSuite.test("Unexpected Obj-C null") + .crashOutputMatches("Found unexpected null pointer value while trying to cast value of type '") + .crashOutputMatches("NSObject'") + .crashOutputMatches(" to '") + .crashOutputMatches("P2'") + .code +{ + let n = UnsafeRawPointer(bitPattern: 0) + var o: NSObject = unsafeBitCast(n, to: NSObject.self) + let r = o as Any + expectCrashLater() + let s = r as? P2 + _blackHole(s) +} +} +#endif + runAllTests() diff --git a/test/Casting/Casts.swift b/test/Casting/Casts.swift new file mode 100644 index 0000000000000..54eeef85adff6 --- /dev/null +++ b/test/Casting/Casts.swift @@ -0,0 +1,763 @@ +// Casts.swift - Tests for conversion between types. +// +// 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 +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for non-trapping type conversions reported by users. +/// +// ----------------------------------------------------------------------------- +// RUN: %empty-directory(%t) +// +// RUN: %target-build-swift -swift-version 5 -g -Onone -Xfrontend -enable-experimental-concurrency -module-name a %s -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %target-run %t/a.swift5.Onone.out +// +// RUN: %target-build-swift -swift-version 5 -g -O -Xfrontend -enable-experimental-concurrency -module-name a %s -o %t/a.swift5.O.out +// RUN: %target-codesign %t/a.swift5.O.out +// RUN: %target-run %t/a.swift5.O.out +// +// REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib + +import StdlibUnittest +#if _runtime(_ObjC) +import Foundation +#endif + +func blackhole(_ t: T) { } + +private func runtimeCast(_ from: T, to: U.Type) -> U? { + return from as? U +} + +let CastsTests = TestSuite("Casts") + +// Test for SR-426: missing release for some types after failed conversion +CastsTests.test("No leak for failed tuple casts") { + let t: Any = (1, LifetimeTracked(0)) + expectFalse(t is Any.Type) +} + +protocol P {} +class ErrClass : Error { } + +CastsTests.test("No overrelease of existential boxes in failed casts") { + // Test for crash from SR-392 + // We fail casts of an existential box repeatedly + // to ensure it does not get over-released. + func bar(_ t: T) { + for _ in 0..<10 { + if case let a as P = t { + _ = a + } + } + } + + let err: Error = ErrClass() + bar(err) +} + +extension Int : P {} + +// Test for SR-7664: Inconsistent optional casting behaviour with generics +// Runtime failed to unwrap multiple levels of Optional when casting. +CastsTests.test("Multi-level optionals can be casted") { + func testSuccess(_ x: From, from: From.Type, to: To.Type) { + expectNotNil(x as? To) + } + func testFailure(_ x: From, from: From.Type, to: To.Type) { + expectNil(x as? To) + } + testSuccess(42, from: Int?.self, to: Int.self) + testSuccess(42, from: Int??.self, to: Int.self) + testSuccess(42, from: Int???.self, to: Int.self) + testSuccess(42, from: Int???.self, to: Int?.self) + testSuccess(42, from: Int???.self, to: Int??.self) + testSuccess(42, from: Int???.self, to: Int???.self) + testFailure(42, from: Int?.self, to: String.self) + testFailure(42, from: Int??.self, to: String.self) + testFailure(42, from: Int???.self, to: String.self) +} + +// Test for SR-9837: Optional.none not casting to Optional.none in generic context +CastsTests.test("Optional.none can be casted to Optional.none in generic context") { + func test(_ type: T.Type) -> T? { + return Any?.none as? T + } + + expectEqual(type(of: test(Bool.self)), Bool?.self) + expectEqual(type(of: test(Bool?.self)), Bool??.self) +} + +// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject +#if _runtime(_ObjC) +protocol P2 {} +CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") { + if #available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + struct S: P2 {} + + class ObjCWrapper { + @objc dynamic let any: Any = S() + init() {} + } + let a = ObjCWrapper().any + expectTrue(a is P2) + // In SR-3871, the following cast failed (everything else here succeeded) + expectNotNil(a as? P2) + expectNotNil(a as? S) + let b = a as AnyObject + expectTrue(a is P2) + expectNotNil(b as? P2) + expectNotNil(b as? S) + } +} +#endif + +protocol P3 {} +CastsTests.test("Cast from Swift existential to Protocol") { + struct S: P3 {} + class SwiftWrapper { + let any: Any = S() + init() {} + } + let a = SwiftWrapper().any + expectTrue(a is P3) + expectNotNil(a as? P3) + expectNotNil(a as? S) + let b = a as AnyObject + expectTrue(b is P3) + expectNotNil(b as? P3) + expectNotNil(b as? S) +} + + +#if _runtime(_ObjC) +extension CFBitVector : P { + static func makeImmutable(from values: Array) -> CFBitVector { + return CFBitVectorCreate(/*allocator:*/ nil, values, values.count * 8) + } +} + +extension CFMutableBitVector { + static func makeMutable(from values: Array) -> CFMutableBitVector { + return CFBitVectorCreateMutableCopy( + /*allocator:*/ nil, + /*capacity:*/ 0, + CFBitVector.makeImmutable(from: values)) + } +} + +func isP(_ t: T) -> Bool { + return t is P +} + +CastsTests.test("Dynamic casts of CF types to protocol existentials (SR-2289)") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "This test behaves unpredictably in optimized mode.")) +.code { + expectTrue(isP(10 as Int)) + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(isP(CFBitVector.makeImmutable(from: [10, 20]))) + expectTrue(isP(CFMutableBitVector.makeMutable(from: [10, 20]))) + } +} +#endif + +// Another test for SR-3871, SR-5590, SR-6309, SR-8651: +// user type in a _SwiftValue in an Optional can't be cast to a protocol. +// Note: This uses the (misnamed) _bridgeAnythingToObjectiveC so it can +// test these paths on Linux as well. +protocol P6309 {} +CastsTests.test("Casting struct -> Obj-C -> Protocol fails (SR-3871, SR-5590, SR-6309, SR-8651)") { + struct S: P6309 { + let value: Int + let tracker = LifetimeTracked(13) + } + + let a: P6309 = S(value: 13) + + let b = _bridgeAnythingToObjectiveC(a) + let d = b as? Any + let e = d as? P6309 + expectNotNil(e) +} + + +protocol P4552 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Casting Any(Optional(T)) -> Protocol fails (SR-4552)") { + struct S: P4552 { + let tracker = LifetimeTracked(13) + } + + let a = S() + let b: S? = a + let c = b as? Any + let d = c as? P4552 + expectNotNil(d) +} +} + +// rdar://27108240 (Optional casting bug (crash)) +protocol Key { + associatedtype Value +} +CastsTests.test("Cast to associated type") { + // Helper function to bypass compiler cast optimizations + func runtimeCast (_ x: From, to: To.Type) -> To? { + return x as? To + } + struct StringKey : Key { + typealias Value = String? + } + var string: String? + func value(forKey key: K.Type) { + let b = runtimeCast(string, to: K.Value.self) + expectNotNil(b) + let c = string as? K.Value + expectNotNil(c) + } + value(forKey: StringKey.self) +} + +#if _runtime(_ObjC) +// rdar://36288786 (Swift metatype stored in an Objective-C id property can't be typecast back to its original type) +CastsTests.test("Store Swift metatype in ObjC property and cast back to Any.Type") { + class MyObj { + var sVar: Any? = nil + @objc dynamic var objcVar: Any? = nil + } + + let a = MyObj() + + // Double values + a.sVar = 1.234 + a.objcVar = 1.234 + + let sValue1 = a.sVar as? Double + let objcValue1 = a.objcVar as? Double + expectEqual(sValue1, objcValue1) + + // Swift types + let b = Bool.self + a.sVar = b + a.objcVar = b + + let sValue2 = a.sVar as? Any.Type + let objcValue2 = a.objcVar as? Any.Type + expectTrue(sValue2 == b) + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(sValue2 == objcValue2) + expectTrue(objcValue2 == b) + } +} +#endif + +// rdar://37793004 ([dynamic casting] [SR-7049]: Enums don't cast back from AnyHashable) +CastsTests.test("Enums don't cast back from AnyHashable (SR-7049)") { + enum E { + case a + } + + // This works as expected. + let str: AnyHashable = "hello" + expectNotNil(str as? String) // Optional("hello") + expectNotNil(str as? String as Any) // Optional("hello") + + // This doesn't. + let ea: AnyHashable = E.a + expectNotNil(ea as? E) + expectNotNil(ea as? E as Any) + expectEqual((ea as? E), E.a) +} + +#if _runtime(_ObjC) +//rdar://39415812 ([dynamic casting] [SR-7432]: Can't see through boxed _SwiftValue when casting from @objc Type) +@objc(Exporter) +protocol Exporter: NSObjectProtocol { + var type: Any { get } + func export(item: Any) -> String? +} +CastsTests.test("Casts from @objc Type") { + struct User { var name: String } + + final class UserExporter: NSObject, Exporter { + var type: Any { return User.self } + func export(item: Any) -> String? { + let u = item as? User + return u?.name + } + } + + let user = User(name: "Kermit") + let exporter: Exporter = UserExporter() + + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectTrue(exporter.type is User.Type) + } + expectNotNil(exporter.export(item: user)) +} +#endif + +#if _runtime(_ObjC) +// rdar://44467533 (Swift master branch: conditional casts for _ObjectiveCBridgeable miscompile in swift-corelibs-foundation) +CastsTests.test("Conditional NSNumber -> Bool casts") { + let x = NSNumber(value: -1) as? Bool + expectNil(x) +} +#endif + +// rdar://45217461 ([dynamic casting] [SR-8964]: Type check operator (is) fails for Any! variable holding an Error (struct) value) +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Casts from Any(struct) to Error (SR-8964)") { + struct MyError: Error { } + + let a: Any! = MyError() + let b: Any = a + expectTrue(b is Error) +} +} + +#if _runtime(_ObjC) +// rdar://15494623 (Handle dynamic cast to archetype bound to ObjC existential) +CastsTests.test("Dynamic cast to ObjC protocol") { + func genericCast(x: NSObject, _: T.Type) -> T? { + return x as? T + } + + let n: NSNumber = 1 + let copying = genericCast(x: n, NSCopying.self) + expectNotNil(copying) +} +#endif + +// SR-6126 +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Nil handling for Optionals and Arrays (SR-6126)") { + func check(_ arg: Int??) -> String { + switch arg { + case .none: + return ".none" + case .some(.none): + return ".some(.none)" + case .some(.some): + return ".some(.some)" + } + } + + let x: Int? = .none + let y: [Int?] = [.none] + + let a = x as Int?? + let b = (x as? Int??)! + let b2 = runtimeCast(x, to: Int??.self)! + let c = Int?.none as Int?? + let d = (Int?.none as? Int??)! + let d2 = runtimeCast(Int?.none, to: Int??.self)! + let e = (y as [Int??]).first! + let f = (y as? [Int??])!.first! + let f2 = runtimeCast(y, to: [Int??].self)!.first! + let g = ([Int?.none] as [Int??]).first! + let h = ([Int?.none] as? [Int??])!.first! + let h2 = runtimeCast([Int?.none], to: [Int??].self)!.first! + + // Original reporter believes all of these should be .some(.none) + expectEqual(".some(.none)", check(a)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(b)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(b2)) + expectEqual(".some(.none)", check(c)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(d)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(d2)) + expectEqual(".some(.none)", check(e)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(f)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(f2)) + expectEqual(".some(.none)", check(g)) // Xcode 9.0: .some(.none) + expectEqual(".some(.none)", check(h)) // Xcode 9.0: .none + expectEqual(".some(.none)", check(h2)) +} +} + +protocol SwiftProtocol {} +CastsTests.test("Swift Protocol Metatypes don't self-conform") { + let a = SwiftProtocol.self + // `is P.Protocol` tests whether the argument is a subtype of P. + // In particular, the protocol identifier `P.self` is such a subtype. + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectNotNil(runtimeCast(a, to: SwiftProtocol.Protocol.self)) // Fixed by rdar://58991956 + } + expectNotNil(a as? SwiftProtocol.Protocol) + expectTrue(a is SwiftProtocol.Protocol) + blackhole(a as! SwiftProtocol.Protocol) // Should not trap + + // `is P.Type` tests conformance to P. Protocols cannot conform to + // protocols, so these always fail. + expectNil(runtimeCast(a, to: SwiftProtocol.Type.self)) + expectNil(a as? SwiftProtocol.Type) + expectFalse(a is SwiftProtocol.Type) +} + +CastsTests.test("Self-conformance for Any.self") { + let b = Any.self + expectNotNil(runtimeCast(b, to: Any.Protocol.self)) + blackhole(b as! Any.Protocol) // Should not trap + expectTrue(b is Any.Protocol) + expectNotNil(b as? Any.Protocol) + + // Unlike most other protocols, Any.self does conform to Any + expectNotNil(runtimeCast(b, to: Any.Type.self)) + expectNotNil(b as? Any.Type) + expectTrue(b is Any.Type) + blackhole(b as! Any.Type) +} + +// rdar://59067748 (Error Protocol should self-conform in optimized casts) +CastsTests.test("Self-conformance for Error.self") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "Cast optimizer breaks this test")) +.code { + let c = Error.self + expectNotNil(runtimeCast(c, to: Error.Protocol.self)) + expectNotNil(c as? Error.Protocol) + expectTrue(c is Error.Protocol) + blackhole(c as! Error.Protocol) + + // Unlike most other protocols, Error.self does conform to Error + expectNotNil(runtimeCast(c, to: Error.Type.self)) + expectFailure { expectNotNil(c as? Error.Type) } + expectFailure { expectTrue(c is Error.Type) } + // blackhole(c as! Error.Type) // Should not trap, but currently does +} + +// rdar://59067556 (Obj-C Protocol Metatypes should self-conform) +#if _runtime(_ObjC) +@objc protocol ObjCProtocol {} +CastsTests.test("ObjC Protocol Metatypes self-conform") { + let a = ObjCProtocol.self + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectNotNil(runtimeCast(a, to: ObjCProtocol.Protocol.self)) + } + expectNotNil(a as? ObjCProtocol.Protocol) + expectTrue(a is ObjCProtocol.Protocol) + blackhole(a as! ObjCProtocol.Protocol) + + // Unlike Swift protocols, ObjC protocols do conform to themselves + expectFailure { expectNotNil(runtimeCast(a, to: ObjCProtocol.Type.self)) } + expectFailure { expectNotNil(a as? ObjCProtocol.Type) } + expectFailure { expectTrue(a is ObjCProtocol.Type) } + // blackhole(a as! ObjCProtocol.Type) // Should not trap, but currently does +} +#endif + +#if _runtime(_ObjC) +protocol NewStringProtocol {} +extension String: NewStringProtocol { } +CastsTests.test("String/NSString extension compat") { + let x: Any = NSString() + expectFailure { expectNotNil(runtimeCast(x, to: NewStringProtocol.self)) } + expectFailure { expectNotNil(x as? NewStringProtocol) } +} +#endif + +protocol P1999 {} +if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { +CastsTests.test("Cast Any(Optional(class)) to Protocol type (SR-1999)") { + class Foo: P1999 { } + + let optionalFoo : Foo? = Foo() + let anyValue: Any = optionalFoo + + let foo1 = anyValue as? Foo + expectNotNil(foo1) + + let foo2 = anyValue as? P1999 + expectNotNil(foo2) + + let foo3 = runtimeCast(anyValue, to: Foo.self) + expectNotNil(foo3) + + let foo4 = runtimeCast(anyValue, to: P1999.self) + expectNotNil(foo4) +} +} + +#if _runtime(_ObjC) +CastsTests.test("Dict value casting (SR-2911)") { + var dict: [AnyHashable: String] = [:] + dict["Key"] = "Value" + expectNotNil(dict["Key"] as? NSString) + expectNotNil(runtimeCast(dict["Key"], to: NSString.self)) +} +#endif + +#if _runtime(_ObjC) +CastsTests.test("String coercions should work on Linux (SR-12020)") { + let a = "abc" as Substring as NSString + let b = "abc" as NSString + expectEqual(a, b) + + let c = "abc" as Substring + let d = c as? NSString + let e = "abc" as? NSString + expectEqual(d, e) + + let f = runtimeCast(d, to: NSString.self) + expectEqual(e, f) +} +#endif + +class ClassInt: Equatable, Hashable { + private var tracker = LifetimeTracked(77) + static func == (lhs: ClassInt, rhs: ClassInt) -> Bool {return true} + func hash(into hasher: inout Hasher) {} +} +CastsTests.test("AnyHashable(Class) -> Obj-C -> Class") +.skip(.custom({ + !_isDebugAssertConfiguration() + }, + reason: "Cast optimizer breaks this test")) +.code { + let a = ClassInt() + let b = runtimeCast(a, to: AnyHashable.self)! + let c = _bridgeAnythingToObjectiveC(b) + let d = /* SwiftValueBox(AnyHashable(ClassInt)) */ c as? ClassInt + expectNotNil(d) + let d2 = runtimeCast(c, to: ClassInt.self) + expectNotNil(d2) + let e = runtimeCast(/* SwiftValueBox(AnyHashable(ClassInt)) */ c, to: ClassInt.self) + expectNotNil(e) +} + +#if _runtime(_ObjC) +// rdar://58999120 +CastsTests.test("Error -> NSError -> Protocol transitivity (SR-12095)") { + enum NonConformingError: Error { + case ok + } + + let nonConformingError: Error = NonConformingError.ok + + // NSError conforms to CustomStringConvertible, so ... + let conformingError = nonConformingError as? NSError + expectTrue(conformingError is CustomStringConvertible) + expectNotNil(conformingError as? CustomStringConvertible) + + // Our error type does not conform directly, but should conform + // indirectly because of NSError... + // Note: Known broken in both runtime and compiler. + expectFailure { expectTrue(nonConformingError is CustomStringConvertible) } + expectFailure { expectNotNil(nonConformingError as? CustomStringConvertible) } +} +#endif + +#if _runtime(_ObjC) +CastsTests.test("Runtime crash casting Obj-C object to Obj-C protocol (rdar://16449805)") { + // FIXME: The reported crash was for `NSPoint(x:0, y:0) as? NSCoding`, + // but NSPoint seems to not be available on 32-bit platforms. + expectNotNil(NSString() as? NSCoding) +} +#endif + +CastsTests.test("Casting Swift Error-conforming types to Error existentials") { + enum Foo: Error { + case OK + case Broken + } + let a = Foo.Broken + let b = a as? Error + expectNotNil(b) + let c = b as? Foo + expectNotNil(c) + let d = Foo.self as? Error.Type + expectNotNil(d) +} + +#if _runtime(_ObjC) +CastsTests.test("Casting NSError <-> Error") { + @objc class Bar: NSError { + init() {super.init(domain: "Bar", code: 99)} + required init?(coder: NSCoder) {super.init(coder: coder)} + } + let e = Bar.self as? Error.Type + expectNotNil(e) + let f = Bar.self as? Bar.Type + expectNotNil(f) + let g = Bar() as? Error + expectNotNil(g) +} +#endif + +// Foundation's JSON handling makes heavy use of passing Any? inside of Any +// existentials. That inspired the following three checks: +CastsTests.test("[Any(Any?)] -> [Any?] should prefer unwrapping source") { + let a: Any? = nil + let b: [Any] = [a as Any] + let c = b as? [Any?] + let d = c! + let e = d[0] + expectNil(e) +} + +CastsTests.test("Any(Any?) -> Any? should prefer unwrapping source") { + let a: Any? = nil + let b: Any = a + let c = b as? Any? + let d = c! + expectNil(d) +} + +#if _runtime(_ObjC) +CastsTests.test("NSNull?.none -> Any? should set outer nil") { + let a: NSNull? = nil + let b = a as? Any? + let c = b! + expectNil(c) +} +#endif + +CastsTests.test("Int??.some(nil) => Int??? should inject naturally") { + let a: Int?? = .some(nil) + let b = a as? Int??? + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +CastsTests.test("Int??.some(nil) => String??? should inject naturally") { + let a: Int?? = .some(nil) + let b = runtimeCast(a, to: String???.self) + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +CastsTests.test("Int??.some(nil) => Any??? should inject naturally") { + let a: Int?? = .some(nil) + let b = a as? Any??? + let c = b! + let d = c! + let e = d! + expectNil(e) +} + +#if _runtime(_ObjC) +CastsTests.test("NSString -> String fast path") { + let a = "short" as NSString + expectNotNil(a as? String) + let b = runtimeCast(a, to: String.self) + expectNotNil(b) + + let c = "Long (adj) -- extended, large, the opposite of short" as NSString + expectNotNil(c as? String) + let d = runtimeCast(c, to: String.self) + expectNotNil(d) + + let e = NSMutableString("not read-only") + expectNotNil(e as? String) + let f = runtimeCast(e, to: String.self) + expectNotNil(f) + + let g = CFStringCreateWithCString(nil, "hello, world", CFStringBuiltInEncodings.UTF8.rawValue) + expectNotNil(g as? String) + let h = runtimeCast(g, to: String.self) + expectNotNil(h) + + let i = CFStringCreateMutable(nil, 0) + expectNotNil(i as? String) + let j = runtimeCast(i, to: String.self) + expectNotNil(j) +} +#endif + +// This fails in optimized builds because after inlining `runtimeCast`, +// the resulting SIL cast operation is left in a form that IRGen can't +// correctly handle. +//CastsTests.test("Optimized metatype -> AnyObject cast") { +// struct StructInt { } +// let a = StructInt.self +// let b = runtimeCast(a, to: AnyObject.self) +// expectNotNil(b) +//} + +CastsTests.test("Any.Protocol") { + class C {} + struct S {} + func isAnyProtocol(_ type: T.Type) -> Bool { + let result = T.self is Any.Protocol + if result { + // `as!` should succeed if `is` does + blackhole(T.self as! Any.Protocol) + } + return result + } + func isAnyType(_ type: T.Type) -> Bool { + return T.self is Any.Type + } + func isType(_ type: T.Type, to: U.Type) -> Bool { + return T.self is U.Type + } + + expectTrue(Int.self is Any.Type) + expectNotNil(Int.self as? Any.Type) + expectTrue(isAnyType(Int.self)) + expectFalse(Int.self is Any.Protocol) + expectNil(Int.self as? Any.Protocol) + expectFalse(isAnyProtocol(Int.self)) + expectFalse(isType(Int.self, to: Any.self)) + + expectTrue(C.self is Any.Type) + expectNotNil(C.self as? Any.Type) + expectTrue(isAnyType(C.self)) + expectFalse(C.self is Any.Protocol) + expectNil(C.self as? Any.Protocol) + expectFalse(isAnyProtocol(C.self)) + expectFalse(isType(C.self, to: Any.self)) + + expectTrue(S.self is Any.Type) + expectNotNil(S.self as? Any.Type) + expectTrue(isAnyType(S.self)) + expectFalse(S.self is Any.Protocol) + expectNil(S.self as? Any.Protocol) + expectFalse(isAnyProtocol(S.self)) + expectFalse(isType(S.self, to: Any.self)) + + expectTrue(Any.self is Any.Type) + expectNotNil(Any.self as? Any.Type) + expectTrue(isAnyType(Any.self)) + expectTrue(Any.self is Any.Protocol) + expectNotNil(Any.self as? Any.Protocol) + expectTrue(isAnyProtocol(Any.self)) + expectTrue(isType(Any.self, to: Any.self)) + + expectTrue(Any?.self is Any.Type) + expectNotNil(Any?.self as? Any.Type) + expectTrue(isAnyType(Any?.self)) + expectFalse(Any?.self is Any.Protocol) + expectNil(Any?.self as? Any.Protocol) + expectFalse(isAnyProtocol(Any?.self)) + expectFalse(isType(Any?.self, to: Any.self)) +} + +CastsTests.test("Async function types") { + let asyncFnType: Any.Type = (() async -> Void).self + let fnType: Any.Type = (() -> Void).self + + expectTrue(fnType is (() -> Void).Type) + expectTrue(asyncFnType is (() async -> Void).Type) + expectFalse(fnType is (() async -> Void).Type) + expectFalse(asyncFnType is (() -> Void).Type) +} + +runAllTests() diff --git a/test/ClangImporter/objc_async.swift b/test/ClangImporter/objc_async.swift new file mode 100644 index 0000000000000..15b149a89c5dd --- /dev/null +++ b/test/ClangImporter/objc_async.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify + +// REQUIRES: objc_interop +import Foundation +import ObjCConcurrency + +func testSlowServer(slowServer: SlowServer) async { + let _: Int = await slowServer.doSomethingSlow("mail") + let _: Bool = await slowServer.checkAvailability() + let _: String = await slowServer.findAnswer() ?? "nope" + let _: String = await slowServer.findAnswerFailingly() ?? "nope" + // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} + // FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}} + let _: Void = await slowServer.doSomethingFun("jump") + let _: (Int) -> Void = slowServer.completionHandler +} + +func testSlowServerOldSchool(slowServer: SlowServer) { + var i1: Int = 0 + slowServer.doSomethingSlow("mail") { i in + i1 = i + } + print(i1) +} diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index b6f99b7350729..0b77ce6ac87b2 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -1030,3 +1030,15 @@ func sr12815() { .doesntExist2() { $0 } } } + +// Make sure we can infer generic arguments in an explicit result type. +let explicitUnboundResult1 = { () -> Array in [0] } +let explicitUnboundResult2: (Array) -> Array = { + (arr: Array) -> Array in [0] +} +// FIXME: Should we prioritize the contextual result type and infer Array +// rather than using a type variable in these cases? +// expected-error@+1 {{unable to infer closure type in the current context}} +let explicitUnboundResult3: (Array) -> Array = { + (arr: Array) -> Array in [true] +} diff --git a/test/Constraints/construction.swift b/test/Constraints/construction.swift index 82f660ed6a7bb..048667c4e129b 100644 --- a/test/Constraints/construction.swift +++ b/test/Constraints/construction.swift @@ -22,7 +22,7 @@ enum Z { init(_ x: Int, _ y: Int) { self = .point(x, y) } } -enum Optional { // expected-note {{'T' declared as parameter to type 'Optional'}} +enum Optional { case none case value(T) @@ -59,8 +59,7 @@ acceptString("\(hello), \(world) #\(i)!") Optional(1) // expected-warning{{unused}} Optional(1) // expected-warning{{unused}} _ = .none as Optional -Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{9-9=}} -// expected-error@-1 {{cannot infer contextual base in reference to member 'none'}} +Optional(.none) // expected-error {{cannot infer contextual base in reference to member 'none'}} // Interpolation _ = "\(hello), \(world) #\(i)!" diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bff33fe7caa73..fac6d8b343a10 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -423,7 +423,7 @@ let _ : Color = .rainbow(42) // expected-error {{argument passed to call that t let _ : (Int, Float) = (42.0, 12) // expected-error {{cannot convert value of type '(Double, Float)' to specified type '(Int, Float)'}} -let _ : Color = .rainbow // expected-error {{member 'rainbow()' is a function; did you mean to call it?}} {{25-25=()}} +let _ : Color = .rainbow // expected-error {{member 'rainbow()' is a function that produces expected type 'Color'; did you mean to call it?}} {{25-25=()}} let _: Color = .overload(a : 1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} let _: Color = .overload(1.0) // expected-error {{no exact matches in call to static method 'overload'}} diff --git a/test/Constraints/keypath.swift b/test/Constraints/keypath.swift index 107739ee0b9a8..2512e9d9f372b 100644 --- a/test/Constraints/keypath.swift +++ b/test/Constraints/keypath.swift @@ -179,3 +179,11 @@ func key_path_root_mismatch(_ base: KeyPathBase?, subBase: KeyPathBaseSubtype let _ : T = subBase[keyPath: kpa] // expected-error {{key path with root type 'AnotherBase' cannot be applied to a base of type 'KeyPathBaseSubtype?'}} } + +// SR-13442 +func SR13442(_ x: KeyPath) -> T { "1"[keyPath: x] } + +func testSR13442() { + _ = SR13442(\.!.count) // OK + _ = SR13442(\String?.!.count) // OK +} diff --git a/test/Constraints/rdar44770297.swift b/test/Constraints/rdar44770297.swift index 8d0b128b9e136..9853dd1ca2f53 100644 --- a/test/Constraints/rdar44770297.swift +++ b/test/Constraints/rdar44770297.swift @@ -4,10 +4,8 @@ protocol P { associatedtype A } -func foo(_: () throws -> T) -> T.A? { +func foo(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Never'}} fatalError() } -let _ = foo() {fatalError()} & nil // expected-error {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}} -// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} -// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} +let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}} diff --git a/test/IDE/complete_annotation.swift b/test/IDE/complete_annotation.swift index d9dde1ac6c8e5..0e267618ca87a 100644 --- a/test/IDE/complete_annotation.swift +++ b/test/IDE/complete_annotation.swift @@ -95,9 +95,13 @@ func testPostfix(value: MyStruct) { func testImplicitMember() -> MyStruct { return .#^EXPR_IMPLICITMEMBER^# } -// EXPR_IMPLICITMEMBER: Begin completions, 3 items +// EXPR_IMPLICITMEMBER: Begin completions, 7 items // EXPR_IMPLICITMEMBER-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init(x: Int); typename=MyStruct; // EXPR_IMPLICITMEMBER-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: instance; typename=MyStruct; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: labelNameParamName(_ self: MyStruct); typename=(label: (inout Int) throws -> MyStruct) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: labelName(_ self: MyStruct); typename=(label: (@autoclosure () -> Int) -> Int) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: sameName(_ self: MyStruct); typename=(label: inout Int) -> Void; +// EXPR_IMPLICITMEMBER-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: paramName(_ self: MyStruct); typename=(Int) -> Void; // EXPR_IMPLICITMEMBER-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: create(x: Int); typename=MyStruct; // EXPR_IMPLICITMEMBER: End completions diff --git a/test/IDE/complete_assignment.swift b/test/IDE/complete_assignment.swift index 3fa5753e0b30c..871ef3db1dd2c 100644 --- a/test/IDE/complete_assignment.swift +++ b/test/IDE/complete_assignment.swift @@ -127,17 +127,19 @@ func f2() { d = .#^ASSIGN_5^# } -// ASSIGN_5: Begin completions, 2 items +// ASSIGN_5: Begin completions, 3 items // ASSIGN_5-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case2[#D1#]; name=case2 // ASSIGN_5-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case1[#D1#]; name=case1 +// ASSIGN_5-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): D1#})[#(into: inout Hasher) -> Void#]; name=hash(self: D1) func f6() { var d : D2 d = .#^ASSIGN_6^# } -// ASSIGN_6: Begin completions, 2 items +// ASSIGN_6: Begin completions, 3 items // ASSIGN_6-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case3[#D2#]; name=case3 // ASSIGN_6-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: case4[#D2#]; name=case4 +// ASSIGN_6-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): D2#})[#(into: inout Hasher) -> Void#]; name=hash(self: D2) func f7 (C : C2) { var i : Int diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index 978810776e125..bbd17ff20cd9e 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -78,11 +78,13 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_AFTERPAREN_2 | %FileCheck %s -check-prefix=STATIC_METHOD_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_SECOND | %FileCheck %s -check-prefix=STATIC_METHOD_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_SKIPPED | %FileCheck %s -check-prefix=STATIC_METHOD_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_METHOD_OVERLOADED | %FileCheck %s -check-prefix=STATIC_METHOD_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_1 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_AFTERPAREN_3 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_SKIPPED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_OVERLOADED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_1 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_1_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND @@ -91,6 +93,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_2 | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_AFTERPAREN_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_SECOND | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SECOND // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_SKIPPED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_SKIPPED +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IMPLICIT_MEMBER_ARRAY_2_OVERLOADED | %FileCheck %s -check-prefix=IMPLICIT_MEMBER_OVERLOADED // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARCHETYPE_GENERIC_1 | %FileCheck %s -check-prefix=ARCHETYPE_GENERIC_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PARAM_WITH_ERROR_AUTOCLOSURE| %FileCheck %s -check-prefix=PARAM_WITH_ERROR_AUTOCLOSURE @@ -579,10 +582,12 @@ func testTupleShuffle() { // SHUFFLE_2-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s1[#String#]; name=s1 // SHUFFLE_2-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s2[#String#]; name=s2 -// SHUFFLE_3: Begin completions, 3 items +// SHUFFLE_3: Begin completions, 4 items // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// SHUFFLE_3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) + class HasSubscript { subscript(idx: Int) -> String {} @@ -665,6 +670,8 @@ class TestStaticMemberCall { static func create2(_ arg1: Int, arg2: Int = 0, arg3: Int = 1, arg4: Int = 2) -> TestStaticMemberCall { return TestStaticMemberCall() } + static func createOverloaded(arg1: Int) -> TestStaticMemberCall { TestStaticMemberCall() } + static func createOverloaded(arg1: String) -> String { arg1 } } func testStaticMemberCall() { let _ = TestStaticMemberCall.create1(#^STATIC_METHOD_AFTERPAREN_1^#) @@ -693,24 +700,30 @@ func testStaticMemberCall() { // STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // STATIC_METHOD_SKIPPED: End completions + + let _ = TestStaticMemberCall.createOverloaded(#^STATIC_METHOD_OVERLOADED^#) +// STATIC_METHOD_OVERLOADED: Begin completions, 2 items +// STATIC_METHOD_OVERLOADED-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// STATIC_METHOD_OVERLOADED-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: String#}[')'][#String#]; name=arg1: String +// STATIC_METHOD_OVERLOADED: End completions } func testImplicitMember() { let _: TestStaticMemberCall = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_1^#) // IMPLICIT_MEMBER_AFTERPAREN_1: Begin completions, 1 items -// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int // IMPLICIT_MEMBER_AFTERPAREN_1: End completions let _: TestStaticMemberCall = .create2(#^IMPLICIT_MEMBER_AFTERPAREN_2^#) // IMPLICIT_MEMBER_AFTERPAREN_2: Begin completions -// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#]; -// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#]; +// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#]; +// IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#]; // IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Decl[Struct]/OtherModule[Swift]/IsSystem/TypeRelation[Identical]: Int[#Int#]; // IMPLICIT_MEMBER_AFTERPAREN_2-DAG: Literal[Integer]/None/TypeRelation[Identical]: 0[#Int#]; // IMPLICIT_MEMBER_AFTERPAREN_2: End completions let _: TestStaticMemberCall? = .create1(#^IMPLICIT_MEMBER_AFTERPAREN_3^#) // IMPLICIT_MEMBER_AFTERPAREN_3: Begin completions, 1 items -// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_AFTERPAREN_3: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int // IMPLICIT_MEMBER_AFTERPAREN_3: End completions let _: TestStaticMemberCall = .create2(1, #^IMPLICIT_MEMBER_SECOND^#) @@ -726,6 +739,12 @@ func testImplicitMember() { // IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg3: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: Pattern/ExprSpecific: {#arg4: Int#}[#Int#]; // IMPLICIT_MEMBER_SKIPPED: End completions + + let _: TestStaticMemberCall = .createOverloaded(#^IMPLICIT_MEMBER_OVERLOADED^#) +// IMPLICIT_MEMBER_OVERLOADED: Begin completions, 2 items +// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1: Int +// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal: ['(']{#arg1: String#}[')'][#String#]; name=arg1: String +// IMPLICIT_MEMBER_OVERLOADED: End completions } func testImplicitMemberInArrayLiteral() { struct Receiver { @@ -739,8 +758,12 @@ func testImplicitMemberInArrayLiteral() { // Same as IMPLICIT_MEMBER_AFTERPAREN_1. ]) Receiver([ + .create1(x: 1), .create2(#^IMPLICIT_MEMBER_ARRAY_1_AFTERPAREN_2^#), // Same as IMPLICIT_MEMBER_AFTERPAREN_2. + ]) + Receiver([ + .create1(x: 1), .create2(1, #^IMPLICIT_MEMBER_ARRAY_1_SECOND^# // Same as IMPLICIT_MEMBER_SECOND. ]) @@ -749,15 +772,22 @@ func testImplicitMemberInArrayLiteral() { // Same as IMPLICIT_MEMBER_SKIPPED. .create1(x: 12) ]) + Receiver(arg1: 12, arg2: [ + .create1(x: 12), + .createOverloaded(#^IMPLICIT_MEMBER_ARRAY_1_OVERLOADED^#) + // Same as IMPLICIT_MEMBER_OVERLOADED. + ]) let _: [TestStaticMemberCall] = [ .create1(#^IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_1^#), - // Same as STATIC_METHOD_AFTERPAREN_1. + // Same as IMPLICIT_MEMBER_AFTERPAREN_1. .create2(#^IMPLICIT_MEMBER_ARRAY_2_AFTERPAREN_2^#), - // Same as STATIC_METHOD_AFTERPAREN_2. + // Same as IMPLICIT_MEMBER_AFTERPAREN_2. .create2(1, #^IMPLICIT_MEMBER_ARRAY_2_SECOND^#), - // Same as STATIC_METHOD_SECOND. + // Same as IMPLICIT_MEMBER_SECOND. .create2(1, arg3: 2, #^IMPLICIT_MEMBER_ARRAY_2_SKIPPED^#), - // Same as STATIC_METHOD_SKIPPED. + // Same as IMPLICIT_MEMBER_SKIPPED. + .createOverloaded(#^IMPLICIT_MEMBER_ARRAY_2_OVERLOADED^#), + // Same as IMPLICIT_MEMBER_OVERLOADED ] } @@ -833,10 +863,11 @@ func testPamrameterFlags(_: Int, inoutArg: inout Int, autoclosureArg: @autoclosu func testTupleElement(arg: (SimpleEnum, SimpleEnum)) { testTupleElement(arg: (.foo, .#^TUPLEELEM_1^#)) -// TUPLEELEM_1: Begin completions, 3 items +// TUPLEELEM_1: Begin completions, 4 items // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // TUPLEELEM_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// TUPLEELEM_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) // TUPLEELEM_1: End completions testTupleElement(arg: (.foo, .bar, .#^TUPLEELEM_2^#)) // TUPLEELEM_2-NOT: Begin completions @@ -852,10 +883,11 @@ func testKeyPathThunkInBase() { func foo(_ fn: (TestKP) -> Int) -> TestKPResult { TestKPResult() } foo(\.value).testFunc(.#^KEYPATH_THUNK_BASE^#) -// KEYPATH_THUNK_BASE: Begin completions, 3 items +// KEYPATH_THUNK_BASE: Begin completions, 4 items // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: foo[#SimpleEnum#]; name=foo // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: bar[#SimpleEnum#]; name=bar // KEYPATH_THUNK_BASE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: baz[#SimpleEnum#]; name=baz +// KEYPATH_THUNK_BASE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SimpleEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: SimpleEnum) // KEYPATH_THUNK_BASE: End completions } diff --git a/test/IDE/complete_call_as_function.swift b/test/IDE/complete_call_as_function.swift index 836b3a9a7d84e..ebd371b95312c 100644 --- a/test/IDE/complete_call_as_function.swift +++ b/test/IDE/complete_call_as_function.swift @@ -111,10 +111,12 @@ func testCallAsFunctionOverloaded(fn: Functor) { fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#) // FIXME: Should only suggest 'up' and 'down' (rdar://problem/60346573). -//OVERLOADED_ARG2_VALUE: Begin completions, 4 items +//OVERLOADED_ARG2_VALUE: Begin completions, 6 items //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: up[#Functor.Vertical#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: down[#Functor.Vertical#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Functor.Vertical#})[#(into: inout Hasher) -> Void#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: left[#Functor.Horizontal#]; //OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: right[#Functor.Horizontal#]; +//OVERLOADED_ARG2_VALUE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Functor.Horizontal#})[#(into: inout Hasher) -> Void#]; //OVERLOADED_ARG2_VALUE: End completions } diff --git a/test/IDE/complete_constrained.swift b/test/IDE/complete_constrained.swift index bb85a6c711c02..cc655f4af2ea2 100644 --- a/test/IDE/complete_constrained.swift +++ b/test/IDE/complete_constrained.swift @@ -117,9 +117,11 @@ struct Vegetarian: EatsFruit, EatsVegetables { } func testVegetarian(chef: Chef) { chef.cook(.#^CONDITIONAL_OVERLOAD_ARG^#) -// CONDITIONAL_OVERLOAD_ARG: Begin completions, 2 items +// CONDITIONAL_OVERLOAD_ARG: Begin completions, 4 items // CONDITIONAL_OVERLOAD_ARG-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: apple[#Fruit#]; name=apple +// CONDITIONAL_OVERLOAD_ARG-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Fruit#})[#(into: inout Hasher) -> Void#]; name=hash(self: Fruit) // CONDITIONAL_OVERLOAD_ARG-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: broccoli[#Vegetable#]; name=broccoli +// CONDITIONAL_OVERLOAD_ARG-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Vegetable#})[#(into: inout Hasher) -> Void#]; name=hash(self: Vegetable) // CONDITIONAL_OVERLOAD_ARG: End completions var chefMeta: Chef.Type = Chef.self diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index 7f4097efb0a9c..48d8b01d8b23a 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -138,10 +138,20 @@ enum FooEnum: CaseIterable { // FOO_ENUM_DOT_INVALID-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}} // FOO_ENUM_DOT_INVALID-NEXT: End completions -// FOO_ENUM_DOT_ELEMENTS: Begin completions, 3 items +// FOO_ENUM_DOT_ELEMENTS: Begin completions, 13 items // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo1[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Foo2[#FooEnum#]{{; name=.+$}} // FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: alias1[#FooEnum#]; name=alias1 +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): FooEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: FooEnum) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#arrayLiteral: FooEnum...#})[#Array#]; name=AllCases(arrayLiteral: FooEnum...) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases()[#Array#]; name=AllCases() +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#(s): Sequence#})[#Array#]; name=AllCases(s: Sequence) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#Array#]; name=AllCases(repeating: FooEnum, count: Int) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#unsafeUninitializedCapacity: Int#}, {#initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void##(inout UnsafeMutableBufferPointer, inout Int) throws -> Void#})[' rethrows'][#Array#]; name=AllCases(unsafeUninitializedCapacity: Int, initializingWith: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#from: Decoder#})[' throws'][#Array#]; name=AllCases(from: Decoder) throws +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#repeating: FooEnum#}, {#count: Int#})[#FooEnum.AllCases#]; name=AllCases(repeating: FooEnum, count: Int) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[Constructor]/CurrNominal/IsSystem: AllCases({#(elements): Sequence#})[#FooEnum.AllCases#]; name=AllCases(elements: Sequence) +// FOO_ENUM_DOT_ELEMENTS-NEXT: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]; name=allCases // FOO_ENUM_DOT_ELEMENTS-NEXT: End completions enum BarEnum { @@ -454,9 +464,12 @@ func testWithInvalid1() { func testUnqualified1(x: QuxEnum) { _ = x == .Qux1 || x == .#^UNRESOLVED_2^#Qux2 - // UNRESOLVED_2: Begin completions, 2 items + // UNRESOLVED_2: Begin completions // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux1[#QuxEnum#]; name=Qux1 // UNRESOLVED_2-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: Qux2[#QuxEnum#]; name=Qux2 + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal/IsSystem: RawValue({#bitPattern: UInt#})[#Int#]; name=RawValue(bitPattern: UInt) + // UNRESOLVED_2-DAG: Decl[Constructor]/CurrNominal: init({#rawValue: Int#})[#QuxEnum?#]; name=init(rawValue: Int) + // UNRESOLVED_2-DAG: Decl[InstanceMethod]/Super/IsSystem/TypeRelation[Invalid]: hash({#(self): QuxEnum#})[#(into: inout Hasher) -> Void#]; name=hash(self: QuxEnum) // UNRESOLVED_2: End completions _ = (x == .Qux1#^UNRESOLVED_3^#) diff --git a/test/IDE/complete_exception.swift b/test/IDE/complete_exception.swift index 48d222ced7565..a5cef6bb5175b 100644 --- a/test/IDE/complete_exception.swift +++ b/test/IDE/complete_exception.swift @@ -5,11 +5,13 @@ // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH2 | %FileCheck %s -check-prefix=CATCH2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW2 | %FileCheck %s -check-prefix=THROW2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH3 | %FileCheck %s -check-prefix=CATCH3 +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW3 | %FileCheck %s -check-prefix=THROW3 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH1 | %FileCheck %s -check-prefix=CATCH1 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW1 | %FileCheck %s -check-prefix=THROW1 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH2 | %FileCheck %s -check-prefix=CATCH2 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW2 | %FileCheck %s -check-prefix=THROW2 +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW3 | %FileCheck %s -check-prefix=THROW3 // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH1 > %t.inside_catch1 // RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch1 @@ -70,10 +72,10 @@ func test001() { do {} catch #^CATCH1^# // CATCH1: Begin completions -// CATCH1-DAG: Decl[Enum]/CurrModule: Error4[#Error4#]; name=Error4{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error3[#Error3#]; name=Error3{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error2[#Error2#]; name=Error2{{$}} -// CATCH1-DAG: Decl[Class]/CurrModule: Error1[#Error1#]; name=Error1{{$}} +// CATCH1-DAG: Decl[Enum]/CurrModule/TypeRelation[Convertible]: Error4[#Error4#]; name=Error4{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error3[#Error3#]; name=Error3{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error2[#Error2#]; name=Error2{{$}} +// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error1[#Error1#]; name=Error1{{$}} // CATCH1-DAG: Keyword[let]/None: let{{; name=.+$}} // CATCH1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}} // CATCH1-DAG: Decl[Class]/OtherModule[Foundation]/IsSystem: NSError[#NSError#]{{; name=.+$}} @@ -126,11 +128,20 @@ func test005() { // CATCH3: End completions } +func testInvalid() { + try throw Error4.#^THROW3^# +// THROW3: Begin completions +// THROW3: Decl[EnumElement]/CurrNominal: E1[#Error4#]{{; name=.+$}} +// THROW3: Decl[EnumElement]/CurrNominal: E2({#Int32#})[#Error4#]{{; name=.+$}} +// THROW3: End completions +} + //===--- Top-level throw/catch do {} catch #^TOP_LEVEL_CATCH1^# {} throw #^TOP_LEVEL_THROW1^# do {} catch Error4.#^TOP_LEVEL_CATCH2^# {} throw Error4.#^TOP_LEVEL_THROW2^# +try throw Error4.#^TOP_LEVEL_THROW3^# //===--- Inside catch body diff --git a/test/IDE/complete_property_delegate_attribute.swift b/test/IDE/complete_property_delegate_attribute.swift index 5cf00f41e1b1b..ba1de7930993d 100644 --- a/test/IDE/complete_property_delegate_attribute.swift +++ b/test/IDE/complete_property_delegate_attribute.swift @@ -34,9 +34,10 @@ struct TestStruct { @MyStruct(arg1: .#^ARG_MyEnum_DOT^# var test3 -// ARG_MyEnum_DOT: Begin completions, 2 items +// ARG_MyEnum_DOT: Begin completions, 3 items // ARG_MyEnum_DOT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: east[#MyEnum#]; name=east // ARG_MyEnum_DOT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: west[#MyEnum#]; name=west +// ARG_MyEnum_DOT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; // ARG_MyEnum_DOT: End completions @MyStruct(arg1: MyEnum.#^ARG_MyEnum_NOBINDING^#) diff --git a/test/IDE/complete_stmt_controlling_expr.swift b/test/IDE/complete_stmt_controlling_expr.swift index b76a9bfad2f14..ccbabf4c8395f 100644 --- a/test/IDE/complete_stmt_controlling_expr.swift +++ b/test/IDE/complete_stmt_controlling_expr.swift @@ -644,11 +644,17 @@ func testGuardCase(x:FooStruct?) { // FOOSTRUCT_LOCALVAL-DAG: Decl[LocalVar]/Local{{(/TypeRelation\[Convertible\])?}}: boundVal[#FooStruct#]; // FOOSTRUCT_LOCALVAL: End completions -// OPTIONAL_FOOSTRUCT: Begin completions, 5 items +// OPTIONAL_FOOSTRUCT: Begin completions, 9 items // OPTIONAL_FOOSTRUCT-DAG: Keyword[nil]/None/Erase[1]: nil[#FooStruct?#]; name=nil // OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // OPTIONAL_FOOSTRUCT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#FooStruct#})[#Optional#]; name=some(FooStruct) // FIXME: 'FooStruct' members should not be shown. // OPTIONAL_FOOSTRUCT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#FooStruct#]; name=init() // OPTIONAL_FOOSTRUCT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#Int#})[#FooStruct#]; name=init(Int) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal: boolGen({#(self): FooStruct#})[#() -> Bool#]; name=boolGen(self: FooStruct) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal: intGen({#(self): FooStruct#})[#() -> Int#]; name=intGen(self: FooStruct) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((FooStruct) throws -> U) -> U?#]; name=map(self: Optional) +// OPTIONAL_FOOSTRUCT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((FooStruct) throws -> U?) -> U?#]; name=flatMap(self: Optional) +// OPTIONAL_FOOSTRUCT-NOT: init({#(some): +// OPTIONAL_FOOSTRUCT-NOT: init({#nilLiteral: // OPTIONAL_FOOSTRUCT: End completions diff --git a/test/IDE/complete_string_interpolation.swift b/test/IDE/complete_string_interpolation.swift index 4187ca51cf480..1089516beb5f1 100644 --- a/test/IDE/complete_string_interpolation.swift +++ b/test/IDE/complete_string_interpolation.swift @@ -31,17 +31,19 @@ struct MsgInterpolation: StringInterpolationProtocol { var messenger = Messenger() func testMessenger(intVal: Int, fltVal: Float) { messenger.send(" \(intVal, format: .#^OVERLOAD_INT^#) ") -// OVERLOAD_INT: Begin completions, 4 items +// OVERLOAD_INT: Begin completions, 5 items // OVERLOAD_INT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: decimal[#MsgInterpolation.IntFormat#]; // OVERLOAD_INT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: hex[#MsgInterpolation.IntFormat#]; +// OVERLOAD_INT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MsgInterpolation.IntFormat#})[#(into: inout Hasher) -> Void#]; // OVERLOAD_INT-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: precision({#Int#})[#MsgInterpolation.FloatFormat#]; // OVERLOAD_INT-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: hex[#MsgInterpolation.FloatFormat#]; // OVERLOAD_INT: End completions messenger.send(" \(fltVal, format: .#^OVERLOAD_FLT^#) ") -// OVERLOAD_FLT: Begin completions, 4 items +// OVERLOAD_FLT: Begin completions, 5 items // OVERLOAD_FLT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: decimal[#MsgInterpolation.IntFormat#]; // OVERLOAD_FLT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: hex[#MsgInterpolation.IntFormat#]; +// OVERLOAD_FLT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MsgInterpolation.IntFormat#})[#(into: inout Hasher) -> Void#]; // OVERLOAD_FLT-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: precision({#Int#})[#MsgInterpolation.FloatFormat#]; // OVERLOAD_FLT-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: hex[#MsgInterpolation.FloatFormat#]; // OVERLOAD_FLT: End completions diff --git a/test/IDE/complete_type.swift b/test/IDE/complete_type.swift index 04b9158fda578..4178ff2840b04 100644 --- a/test/IDE/complete_type.swift +++ b/test/IDE/complete_type.swift @@ -765,3 +765,17 @@ func testUnbound2(x: OuterStruct.Inner.#^UNBOUND_DOT_3^#) {} // UNBOUND_DOT_3: Begin completions // UNBOUND_DOT_3-DAG: Keyword/None: Type[#OuterStruct.Inner.Type#]; name=Type // UNBOUND_DOT_3: End completions + +// rdar://problem/67102794 +struct HasProtoAlias { + typealias ProtoAlias = FooProtocol +} +extension FooStruct: HasProtoAlias.#^EXTENSION_INHERITANCE_1?check=EXTENSION_INHERITANCE^# {} + +struct ContainExtension { + extension FooStruct: HasProtoAlias.#^EXTENSION_INHERITANCE_2?check=EXTENSION_INHERITANCE^# {} +} +// EXTENSION_INHERITANCE: Begin completions, 2 items +// EXTENSION_INHERITANCE-DAG: Decl[TypeAlias]/CurrNominal: ProtoAlias[#FooProtocol#]; +// EXTENSION_INHERITANCE-DAG: Keyword/None: Type[#HasProtoAlias.Type#]; +// EXTENSION_INHERITANCE: End completions diff --git a/test/IDE/complete_unresolved_chains.swift b/test/IDE/complete_unresolved_chains.swift new file mode 100644 index 0000000000000..f1d2930ce7e17 --- /dev/null +++ b/test/IDE/complete_unresolved_chains.swift @@ -0,0 +1,85 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_1 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_2 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_3 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_4 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_5 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_2 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_6 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_CHAIN_7 | %FileCheck %s -check-prefix=UNRESOLVED_CHAIN_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DOUBLY_NESTED| %FileCheck %s -check-prefix=DOUBLY_NESTED + +struct ChainStruct1 { + static var chain2 = ChainStruct2() + static func chain2Func() -> ChainStruct2 { ChainStruct2() } +} + +struct ChainStruct2 { + var chainStruct1 = ChainStruct1() + var chainEnum = ChainEnum.case1 + var chainStruct2: ChainStruct2 { ChainStruct2() } + func chainStruct1Func() -> ChainStruct1 { ChainStruct1() } +} + +enum ChainEnum { + case case1 + var chainStruct2: ChainStruct2 { ChainStruct2() } + func chainStruct2Func() -> ChainStruct2 { ChainStruct2() } +} + +func testChains() { + let _: ChainStruct1 = .chain2.#^UNRESOLVED_CHAIN_1^# + let _: ChainStruct1 = .chain2.chainStruct2.#^UNRESOLVED_CHAIN_2^# + let _: ChainStruct1 = .chain2Func().#^UNRESOLVED_CHAIN_3^# + let _: ChainStruct1 = .chain2Func().#^UNRESOLVED_CHAIN_4^# + let _: ChainEnum = .case1.#^UNRESOLVED_CHAIN_5^# + let _: ChainEnum = .case1.chainStruct2.#^UNRESOLVED_CHAIN_6^# + let _: ChainEnum = .case1.chainStruct2.#^UNRESOLVED_CHAIN_7^# +} + +// UNRESOLVED_CHAIN_1: Begin completions, 5 items +// UNRESOLVED_CHAIN_1-DAG: Keyword[self]/CurrNominal: self[#ChainStruct2#]; name=self +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainStruct1[#ChainStruct1#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainEnum[#ChainEnum#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; +// UNRESOLVED_CHAIN_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: chainStruct1Func()[#ChainStruct1#]; +// UNRESOLVED_CHAIN_1: End completions + +// UNRESOLVED_CHAIN_2: Begin completions, 5 items +// UNRESOLVED_CHAIN_2-DAG: Keyword[self]/CurrNominal: self[#ChainEnum#]; name=self +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; name=chainStruct2 +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceMethod]/CurrNominal: chainStruct2Func()[#ChainStruct2#]; name=chainStruct2Func() +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceVar]/CurrNominal: hashValue[#Int#]; name=hashValue +// UNRESOLVED_CHAIN_2-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#into: &Hasher#})[#Void#]; name=hash(into: &Hasher) +// UNRESOLVED_CHAIN_2: End completions + +// UNRESOLVED_CHAIN_3: Begin completions, 5 items +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal: chainStruct1[#ChainStruct1#]; name=chainStruct1 +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Identical]: chainEnum[#ChainEnum#]; name=chainEnum +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceVar]/CurrNominal: chainStruct2[#ChainStruct2#]; name=chainStruct2 +// UNRESOLVED_CHAIN_3-DAG: Decl[InstanceMethod]/CurrNominal: chainStruct1Func()[#ChainStruct1#]; name=chainStruct1Func() +// UNRESOLVED_CHAIN_3: End completions + +class Outer { + class Inner: Outer { + class InnerInner: Inner {} + static var outer = Outer() + static var inner = Inner() + static func makeOuter() -> Outer { Outer() } + static func makeInner() -> Inner { Inner() } + } +} + +func testDoublyNestedType() { + let _: Outer = .Inner.#^DOUBLY_NESTED^# +} + +// DOUBLY_NESTED: Begin completions, 8 items +// DOUBLY_NESTED-DAG: Keyword[self]/CurrNominal: self[#Outer.Inner.Type#]; name=self +// DOUBLY_NESTED-DAG: Decl[Class]/CurrNominal/TypeRelation[Convertible]: InnerInner[#Outer.Inner.InnerInner#]; +// DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: outer[#Outer#]; +// DOUBLY_NESTED-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: inner[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Identical]: makeOuter()[#Outer#]; +// DOUBLY_NESTED-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: makeInner()[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#Outer.Inner#]; +// DOUBLY_NESTED-DAG: Decl[Class]/Super/TypeRelation[Convertible]: Inner[#Outer.Inner#]; +// DOUBLY_NESTED: End completions + diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index 7a895c550c665..53d20a8a07d36 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -109,9 +109,9 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERICPARAM_21 | %FileCheck %s -check-prefix=GENERICPARAM_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DECL_MEMBER_INIT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_NOTIDEAL +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_1 | %FileCheck %s -check-prefix=UNRESOLVED_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_2 | %FileCheck %s -check-prefix=UNRESOLVED_3 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=DEFAULT_ARG_3 | %FileCheck %s -check-prefix=UNRESOLVED_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEPARAM_IN_CONTEXTTYPE_1 | %FileCheck %s -check-prefix=TYPEPARAM_IN_CONTEXTTYPE_1 @@ -226,7 +226,8 @@ class C2 { // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option1[#SomeOptions1#]; name=Option1 // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option2[#SomeOptions1#]; name=Option2 // UNRESOLVED_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: Option3[#SomeOptions1#]; name=Option3 -// UNRESOLVED_1-NOT: Not +// UNRESOLVED_1-DAG: Decl[StaticVar]/CurrNominal: NotOption[#Int#]; name=NotOption +// UNRESOLVED_1-NOT: NotStaticOption // UNRESOLVED_1_NOTIDEAL: Begin completions // UNRESOLVED_1_NOTIDEAL-NOT: SomeEnum1 @@ -234,7 +235,8 @@ class C2 { // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option1[#SomeOptions1#]; name=Option1 // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option2[#SomeOptions1#]; name=Option2 // UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: Option3[#SomeOptions1#]; name=Option3 -// UNRESOLVED_1_NOTIDEAL-NOT: Not +// UNRESOLVED_1_NOTIDEAL-DAG: Decl[StaticVar]/CurrNominal: NotOption[#Int#]; name=NotOption +// UNRESOLVED_1_NOTIDEAL-NOT: NotStaticOption } class C3 { @@ -274,39 +276,49 @@ class C4 { var _: SomeEnum1??? = .#^UNRESOLVED_OPT_3^# } } -// UNRESOLVED_3: Begin completions, 2 items +// UNRESOLVED_3: Begin completions, 3 items // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: North[#SomeEnum1#]; name=North // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: South[#SomeEnum1#]; name=South +// UNRESOLVED_3-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; name=hash(self: SomeEnum1) // UNRESOLVED_3-NOT: SomeOptions1 // UNRESOLVED_3-NOT: SomeOptions2 // UNRESOLVED_3-NOT: none // UNRESOLVED_3-NOT: some( -// UNRESOLVED_3_NOTIDEAL: Begin completions, 2 items +// UNRESOLVED_3_NOTIDEAL: Begin completions, 3 items // UNRESOLVED_3_NOTIDEAL-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; name=North // UNRESOLVED_3_NOTIDEAL-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; name=South +// UNRESOLVED_3_NOTIDEAL-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; name=hash(self: SomeEnum1) // UNRESOLVED_3_NOTIDEAL-NOT: SomeOptions1 // UNRESOLVED_3_NOTIDEAL-NOT: SomeOptions2 // UNRESOLVED_3_NOTIDEAL-NOT: none // UNRESOLVED_3_NOTIDEAL-NOT: some( -// UNRESOLVED_3_OPT: Begin completions, 5 items +// UNRESOLVED_3_OPT: Begin completions, 9 items // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: North[#SomeEnum1#]; // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: South[#SomeEnum1#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_3_OPT-DAG: Keyword[nil]/None/Erase[1]: nil[#SomeEnum1?#]; name=nil // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#SomeEnum1#})[#Optional#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((SomeEnum1) throws -> U) -> U?#]; +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((SomeEnum1) throws -> U?) -> U?#]; // UNRESOLVED_3_OPT-NOT: init({#(some): // UNRESOLVED_3_OPT-NOT: init({#nilLiteral: +// UNRESOLVED_3_OPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; -// UNRESOLVED_3_OPTOPTOPT: Begin completions, 5 items +// UNRESOLVED_3_OPTOPTOPT: Begin completions, 9 items // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: North[#SomeEnum1#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: South[#SomeEnum1#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/None/Erase[1]: nil[#SomeEnum1???#]; name=nil // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#SomeEnum1??#})[#Optional#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((SomeEnum1??) throws -> U) -> U?#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((SomeEnum1??) throws -> U?) -> U?#]; // UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some): // UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral: +// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; enum Somewhere { case earth, mars @@ -317,14 +329,18 @@ extension Optional where Wrapped == Somewhere { } func testOptionalWithCustomExtension() { var _: Somewhere? = .#^UNRESOLVED_OPT_4^# -// UNRESOLVED_OPT_4: Begin completions, 7 items +// UNRESOLVED_OPT_4: Begin completions, 11 items // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: earth[#Somewhere#]; // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Convertible]: mars[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Somewhere#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_OPT_4-DAG: Keyword[nil]/None/Erase[1]: nil[#Somewhere?#]; name=nil // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/CurrNominal/IsSystem: none[#Optional#]; name=none // UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/CurrNominal/IsSystem: some({#Somewhere#})[#Optional#]; // UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional#]; name=init(str: String) // UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional#]; name=nowhere +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional#})[#((Somewhere) throws -> U) -> U?#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional#})[#((Somewhere) throws -> U?) -> U?#]; +// UNRESOLVED_OPT_4-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional#})[#(into: inout Hasher) -> Void#]; // UNRESOLVED_OPT_4-NOT: init({#(some): // UNRESOLVED_OPT_4-NOT: init({#nilLiteral: // UNRESOLVED_OPT_4: End completions @@ -433,10 +449,11 @@ let _: [SomeEnum3:SomeEnum1] = [.Payload(.South):.South, .Payload(.#^UNRESOLVED_ func testAvail1(_ x: EnumAvail1) { testAvail1(.#^ENUM_AVAIL_1^#) } -// ENUM_AVAIL_1: Begin completions, 2 items +// ENUM_AVAIL_1: Begin completions, 3 items // ENUM_AVAIL_1-NOT: AAA // ENUM_AVAIL_1-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: aaa[#EnumAvail1#]; // ENUM_AVAIL_1-DAG: Decl[EnumElement]/ExprSpecific/NotRecommended/TypeRelation[Identical]: BBB[#EnumAvail1#]; +// ENUM_AVAIL_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): EnumAvail1#})[#(into: inout Hasher) -> Void#]; // ENUM_AVAIL_1-NOT: AAA // ENUM_AVAIL_1: End completions @@ -444,11 +461,11 @@ func testAvail2(_ x: OptionsAvail1) { testAvail2(.#^OPTIONS_AVAIL_1^#) } // OPTIONS_AVAIL_1: Begin completions -// ENUM_AVAIL_1-NOT: AAA +// OPTIONS_AVAIL_1-NOT: AAA // OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: aaa[#OptionsAvail1#]; // OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/ExprSpecific/NotRecommended/TypeRelation[Identical]: BBB[#OptionsAvail1#]; // OPTIONS_AVAIL_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#rawValue: Int#})[#OptionsAvail1#] -// ENUM_AVAIL_1-NOT: AAA +// OPTIONS_AVAIL_1-NOT: AAA // OPTIONS_AVAIL_1: End completions func testWithLiteral1() { @@ -460,8 +477,9 @@ func testWithLiteral1() { } let s: S _ = s.takeEnum(thing: .#^WITH_LITERAL_1^#, other: 1.0) -// WITH_LITERAL_1: Begin completions, 1 items +// WITH_LITERAL_1: Begin completions, 2 items // WITH_LITERAL_1-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: myCase[#S.MyEnum#]; +// WITH_LITERAL_1-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): S.MyEnum#})[#(into: inout Hasher) -> Void#]; // WITH_LITERAL_1-NEXT: End completions } func testWithLiteral2() { @@ -484,8 +502,9 @@ func testWithLiteral3() { func takeEnum(thing: MyEnum, other: Double) {} func test(s: S) { _ = s.takeEnum(thing: .#^WITH_LITERAL_3^#, other: 1.0) -// WITH_LITERAL_3: Begin completions, 1 items +// WITH_LITERAL_3: Begin completions, 2 items // WITH_LITERAL_3-NEXT: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: myCase[#MyEnum#]; +// WITH_LITERAL_3-NEXT: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; // WITH_LITERAL_3-NEXT: End completions } } @@ -521,11 +540,13 @@ func testNonOptSet() { let x: NonOptSet x = .#^NON_OPT_SET_1^# } -// NON_OPT_SET_1: Begin completions, 4 items +// NON_OPT_SET_1: Begin completions, 6 items // NON_OPT_SET_1-DAG: Decl[StaticVar]/ExprSpecific/TypeRelation[Identical]: a[#NonOptSet#] +// NON_OPT_SET_1-DAG: Decl[StaticVar]/CurrNominal: wrongType[#Int#]; // NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#x: Int#}, {#y: Int#})[#NonOptSet#] // NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#NonOptSet#] // NON_OPT_SET_1-DAG: Decl[StaticMethod]/ExprSpecific/TypeRelation[Identical]: b()[#NonOptSet#] +// NON_OPT_SET_1-DAG: Decl[InstanceMethod]/ExprSpecific/TypeRelation[Identical]: notStatic({#(self): NonOptSet#})[#() -> NonOptSet#]; // NON_OPT_SET_1: End completions func testNonOptSet() { @@ -562,12 +583,12 @@ struct AnotherTy: MyProtocol {} func testSubType() { var _: BaseClass = .#^SUBTYPE_1^# } -// SUBTYPE_1: Begin completions, 3 items -// SUBTYPE_1-NOT: init(failable: +// SUBTYPE_1: Begin completions, 4 items // SUBTYPE_1-NOT: Concrete1( // SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#BaseClass#]; // SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: SubClass()[#BaseClass.SubClass#]; // SUBTYPE_1-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: subInstance[#BaseClass.SubClass#]; +// SUBTYPE_1-DAG: Decl[Constructor]/CurrNominal: init({#failable: Void#})[#BaseClass?#]; // SUBTYPE_1: End completions func testMemberTypealias() { @@ -618,11 +639,11 @@ struct HasCreator { func testHasStaticClosure() { let _: HasCreator = .#^STATIC_CLOSURE_1^# } -// STATIC_CLOSURE_1: Begin completions, 2 items +// STATIC_CLOSURE_1: Begin completions, 3 items // STATIC_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#HasCreator#]; // FIXME: Suggest 'create()[#HasCreateor#]', not 'create'. // STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create[#() -> HasCreator#]; -// STATIC_CLOSURE_1-NOT: create_curried +// STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create_curried[#() -> () -> HasCreator#]; // STATIC_CLOSURE_1: End completions struct HasOverloaded { @@ -633,11 +654,13 @@ struct HasOverloaded { } func testOverload(val: HasOverloaded) { let _ = val.takeEnum(.#^OVERLOADED_METHOD_1^#) -// OVERLOADED_METHOD_1: Begin completions, 4 items +// OVERLOADED_METHOD_1: Begin completions, 6 items // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; name=South // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; name=North +// OVERLOADED_METHOD_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#]; name=East // OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#]; name=West +// OVERLOADED_METHOD_1-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum2#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_METHOD_1: End completions let _ = HasOverloaded.init(e: .#^OVERLOADED_INIT_1^#) @@ -761,10 +784,10 @@ extension MyStruct where T: OtherProtocol { func receiveMyStructOfMyProtocol(value: MyStruct) {} func testTypeParamInContextType() { receiveMyStructOfMyProtocol(value: .#^TYPEPARAM_IN_CONTEXTTYPE_1^#) -// TYPEPARAM_IN_CONTEXTTYPE_1: Begin completions, 2 items -// TYPEPARAM_IN_CONTEXTTYPE_1-NOT: otherProtocolOption +// TYPEPARAM_IN_CONTEXTTYPE_1: Begin completions, 3 items // TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[Constructor]/CurrNominal: init()[#MyStruct#]; // TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Convertible]: myProtocolOption[#MyStruct#]; +// TYPEPARAM_IN_CONTEXTTYPE_1-DAG: Decl[StaticVar]/CurrNominal: otherProtocolOption[#MyStruct#]; // TYPEPARAM_IN_CONTEXTTYPE_1: End completions } @@ -795,11 +818,13 @@ func testClosureReturnTypeForOverloaded() { overloadedClosureRcv { .#^OVERLOADED_CLOSURE_RETURN^# } -// OVERLOADED_CLOSURE_RETURN: Begin completions, 4 items +// OVERLOADED_CLOSURE_RETURN: Begin completions, 6 items // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#]; +// OVERLOADED_CLOSURE_RETURN-DAG: Decl[InstanceMethod]/CurrNominal: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: East[#SomeEnum2#]; // OVERLOADED_CLOSURE_RETURN-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: West[#SomeEnum2#]; +// OVERLOADED_CLOSURE_RETURN-DAG: Decl[InstanceMethod]/CurrNominal: hash({#(self): SomeEnum2#})[#(into: inout Hasher) -> Void#]; // OVERLOADED_CLOSURE_RETURN: End completions } diff --git a/test/IDE/print_clang_objc_async.swift b/test/IDE/print_clang_objc_async.swift new file mode 100644 index 0000000000000..7d3029fff8be6 --- /dev/null +++ b/test/IDE/print_clang_objc_async.swift @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-module -source-filename %s -module-to-print=ObjCConcurrency -function-definitions=false -enable-experimental-concurrency > %t/ObjCConcurrency.printed.txt +// RUN: %FileCheck -input-file %t/ObjCConcurrency.printed.txt %s + +// REQUIRES: objc_interop + +// CHECK-LABEL: class SlowServer : NSObject { +// CHECK-DAG: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void) +// CHECK-DAG: func doSomethingSlow(_ operation: String) async -> Int +// CHECK-DAG: func doSomethingDangerous(_ operation: String, completionHandler handler: ((String?, Error?) -> Void)? = nil) +// CHECK-DAG: func doSomethingDangerous(_ operation: String) async throws -> String? +// CHECK-DAG: func checkAvailability(completionHandler: @escaping (Bool) -> Void) +// CHECK-DAG: func checkAvailability() async -> Bool +// CHECK-DAG: func findAnswer(completionHandler handler: @escaping (String?, Error?) -> Void) +// CHECK-DAG: func findAnswer() async throws -> String? +// CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws +// CHECK-DAG: func findAnswerFailingly() async throws -> String? +// CHECK-DAG: func doSomethingFun(_ operation: String) async +// CHECK: {{^[}]$}} diff --git a/test/IRGen/big_types_corner_cases_tiny.swift b/test/IRGen/big_types_corner_cases_tiny.swift index 8a9a88b28f9b1..a4fb5a9a6929a 100644 --- a/test/IRGen/big_types_corner_cases_tiny.swift +++ b/test/IRGen/big_types_corner_cases_tiny.swift @@ -4,7 +4,7 @@ // DO NOT ADD ANY MORE CODE TO THIS FILE! -// CHECK-LABEL: define internal void @globalinit +// CHECK-LABEL: define internal void @{{.*}}WZ // CHECK: [[ALLOC:%.*]] = alloca %T27big_types_corner_cases_tiny30LoadableStructWithBiggerStringV // CHECK: call swiftcc void {{.*}}(%T27big_types_corner_cases_tiny30LoadableStructWithBiggerStringV* noalias nocapture sret [[ALLOC]] let model = ClassWithLoadableStructWithBiggerString().f() diff --git a/test/IRGen/globals.swift b/test/IRGen/globals.swift index 509922e9483ed..b423befb38b6d 100644 --- a/test/IRGen/globals.swift +++ b/test/IRGen/globals.swift @@ -53,6 +53,5 @@ extension A { // CHECK: define{{( dllexport)?}}{{( protected)?}} i32 @main(i32 %0, i8** %1) {{.*}} { // CHECK: store i64 {{.*}}, i64* getelementptr inbounds ([[INT]], [[INT]]* @"$s7globals2g0Sivp", i32 0, i32 0), align 8 -// FIXME: give these initializers a real mangled name -// CHECK: define internal void @globalinit_{{.*}}func0() {{.*}} { +// CHECK: define internal void @"{{.*}}WZ"() {{.*}} { // CHECK: store i64 5, i64* getelementptr inbounds (%TSi, %TSi* @"$s7globals1AV3fooSivpZ", i32 0, i32 0), align 8 diff --git a/test/IRGen/lazy_globals.swift b/test/IRGen/lazy_globals.swift index ce0f387d9e485..8b1d761c70e40 100644 --- a/test/IRGen/lazy_globals.swift +++ b/test/IRGen/lazy_globals.swift @@ -2,12 +2,12 @@ // REQUIRES: CPU=x86_64 -// CHECK: @globalinit_[[T:.*]]_token0 = internal global i64 0, align 8 +// CHECK: @"[[T:.*]]Wz" = internal global i64 0, align 8 // CHECK: @"$s12lazy_globals1xSivp" = hidden global %TSi zeroinitializer, align 8 // CHECK: @"$s12lazy_globals1ySivp" = hidden global %TSi zeroinitializer, align 8 // CHECK: @"$s12lazy_globals1zSivp" = hidden global %TSi zeroinitializer, align 8 -// CHECK: define internal void @globalinit_[[T]]_func0() {{.*}} { +// CHECK: define internal void @"[[T]]WZ"() {{.*}} { // CHECK: entry: // CHECK: store i64 1, i64* getelementptr inbounds (%TSi, %TSi* @"$s12lazy_globals1xSivp", i32 0, i32 0), align 8 // CHECK: store i64 2, i64* getelementptr inbounds (%TSi, %TSi* @"$s12lazy_globals1ySivp", i32 0, i32 0), align 8 @@ -17,17 +17,17 @@ // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1xSivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1ySivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } // CHECK: define hidden swiftcc i8* @"$s12lazy_globals1zSivau"() {{.*}} { // CHECK: entry: -// CHECK: call void @swift_once(i64* @globalinit_[[T]]_token0, i8* bitcast (void ()* @globalinit_[[T]]_func0 to i8*), i8* undef) +// CHECK: call void @swift_once(i64* @"[[T]]Wz", i8* bitcast (void ()* @"[[T]]WZ" to i8*), i8* undef) // CHECK: } var (x, y, z) = (1, 2, 3) diff --git a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h new file mode 100644 index 0000000000000..b03e3530a4968 --- /dev/null +++ b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h @@ -0,0 +1,16 @@ +@import Foundation; +@import ctypes; + +#pragma clang assume_nonnull begin + +@interface SlowServer : NSObject +-(void)doSomethingSlow:(NSString *)operation completionHandler:(void (^)(NSInteger))handler; +-(void)doSomethingDangerous:(NSString *)operation completionHandler:(void (^ _Nullable)(NSString *_Nullable, NSError * _Nullable))handler; +-(void)checkAvailabilityWithCompletionHandler:(void (^)(BOOL isAvailable))completionHandler; +-(void)findAnswerAsynchronously:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswer(completionHandler:)"))); +-(BOOL)findAnswerFailinglyWithError:(NSError * _Nullable * _Nullable)error completion:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswerFailingly(completionHandler:)"))); +-(void)doSomethingFun:(NSString *)operation then:(void (^)(void))completionHandler; +@property(readwrite) void (^completionHandler)(NSInteger); +@end + +#pragma clang assume_nonnull end diff --git a/test/Inputs/clang-importer-sdk/usr/include/module.map b/test/Inputs/clang-importer-sdk/usr/include/module.map index 61b062ab524eb..366101cbbb723 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/module.map +++ b/test/Inputs/clang-importer-sdk/usr/include/module.map @@ -136,3 +136,8 @@ module WinBOOL { header "winbool.h" export * } + +module ObjCConcurrency { + header "ObjCConcurrency.h" + export * +} \ No newline at end of file diff --git a/test/Interpreter/SDK/protocol_lookup_foreign.swift b/test/Interpreter/SDK/protocol_lookup_foreign.swift index e0836c4cfa31d..f0565dc042a65 100644 --- a/test/Interpreter/SDK/protocol_lookup_foreign.swift +++ b/test/Interpreter/SDK/protocol_lookup_foreign.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift | %FileCheck %s +// RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: objc_interop @@ -10,38 +10,62 @@ // XFAIL: swift_test_mode_optimize_unchecked import Foundation +import StdlibUnittest protocol Fooable { - func foo() + func foo() -> String } -func fooify(_ x: T) { +func fooify(_ x: T) -> String { if let foo = x as? Fooable { - foo.foo() + return foo.foo() } else { - print("not fooable") + return "not fooable" } } extension NSRect: Fooable { - func foo() { print("NSRect") } + func foo() -> String { return "NSRect" } } extension CFSet: Fooable { - func foo() { print("CFSet") } + func foo() -> String { return "CFSet" } } extension NSString: Fooable { - func foo() { print("NSString") } + func foo() -> String { return "NSString" } } -fooify(NSRect()) // CHECK: NSRect -fooify(NSPoint()) // CHECK-NEXT: not fooable -// FIXME: CF types get their ObjC class dynamically looked up during dynamic -// casting. -fooify(CFSetCreate(kCFAllocatorDefault, nil, 0, nil)!) // TODO-NEXT: CFSet CHECK-NEXT: not fooable -fooify(CFArrayCreate(kCFAllocatorDefault, nil, 0, nil)!) // CHECK-NEXT: not fooable -fooify(NSString()) // CHECK-NEXT: NSString -fooify(NSMutableString()) // CHECK-NEXT: NSString -fooify(NSSet()) // CHECK-NEXT: not fooable +var ProtocolLookupForeign = TestSuite("ProtocolLookupForeign") +ProtocolLookupForeign.test("NSRect") { + expectEqual("NSRect", fooify(NSRect())) +} + +ProtocolLookupForeign.test("NSPoint") { + expectEqual("not fooable", fooify(NSPoint())) +} + +ProtocolLookupForeign.test("CFSet") { + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + expectEqual("CFSet", fooify(CFSetCreate(kCFAllocatorDefault, nil, 0, nil)!)) + } +} + +ProtocolLookupForeign.test("CFArray") { + expectEqual("not fooable", fooify(CFArrayCreate(kCFAllocatorDefault, nil, 0, nil)!)) +} + +ProtocolLookupForeign.test("NSString") { + expectEqual("NSString", fooify(NSString())) +} + +ProtocolLookupForeign.test("NSMutableString") { + expectEqual("NSString", fooify(NSMutableString())) +} + +ProtocolLookupForeign.test("NSSet") { + expectEqual("not fooable", fooify(NSSet())) +} + +runAllTests() diff --git a/test/Interpreter/tuple_casts.swift b/test/Interpreter/tuple_casts.swift index 4c0dacafa57f9..0f662932ed6e7 100644 --- a/test/Interpreter/tuple_casts.swift +++ b/test/Interpreter/tuple_casts.swift @@ -1,7 +1,13 @@ // RUN: %target-run-simple-swift -// RUN: %target-build-swift -O %s -o %t/a.out.optimized -// RUN: %target-codesign %t/a.out.optimized -// RUN: %target-run %t/a.out.optimized +// +// RUN: %target-build-swift -swift-version 5 -O %s -o %t/a.swift5.O.out +// RUN: %target-codesign %t/a.swift5.O.out +// RUN: %target-run %t/a.swift5.O.out +// +// RUN: %target-build-swift -swift-version 5 -Onone %s -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %target-run %t/a.swift5.Onone.out +// // REQUIRES: executable_test import StdlibUnittest @@ -31,15 +37,31 @@ tupleCastTests.test("Adding/removing labels") { String(describing: anyToIntPoint((3, 4)))) expectEqual("(x: 5, y: 6)", String(describing: anyToIntPoint((x: 5, 6)))) + expectEqual("(x: 5, y: 6)", + String(describing: anyToIntPoint((5, y: 6)))) expectEqual("(1, 2)", String(describing: anyToInt2((1, 2)))) expectEqual("(3, 4)", String(describing: anyToInt2((x: 3, y: 4)))) expectEqual("(5, 6)", String(describing: anyToInt2((x: 5, 6)))) + expectEqual("(7, 8)", String(describing: anyToInt2((7, y: 8)))) expectEqual("(first: 1, 2, third: 3)", String(describing: anyToPartlyLabeled((1, 2, 3)))) } +tupleCastTests.test("Label checks on casting") { + expectTrue((x: 1, y: 2) is (Int, Int)) + expectTrue((x: 1, y: 2) is (x: Int, Int)) + expectTrue((x: 1, y: 2) is (Int, y: Int)) + expectTrue((x: 1, y: 2) is (x: Int, y: Int)) + + expectFalse((x: 1, y: 2) is (x: Int, z: Int)) + expectFalse((x: 1, y: 2) is (a: Int, y: Int)) + expectFalse((x: 1, y: 2) is (a: Int, z: Int)) + expectFalse((x: 1, y: 2) is (Int, z: Int)) + expectFalse((x: 1, y: 2) is (a: Int, Int)) +} + tupleCastTests.test("Incorrect labels conditional cast") { expectNil(anyToIntPointOpt((x: 1, z: 2))) expectEqual("Optional((x: 1, y: 2))", diff --git a/test/NameLookup/Inputs/custom_attrs_A.swift b/test/NameLookup/Inputs/custom_attrs_A.swift new file mode 100644 index 0000000000000..c8035b4fa167e --- /dev/null +++ b/test/NameLookup/Inputs/custom_attrs_A.swift @@ -0,0 +1,13 @@ +@propertyWrapper +public struct Wrapper { + public var wrappedValue: Value + + public init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +@_functionBuilder +public struct Builder { + static func buildBlock(_ component: T) -> T { component } +} diff --git a/test/NameLookup/Inputs/custom_attrs_B.swift b/test/NameLookup/Inputs/custom_attrs_B.swift new file mode 100644 index 0000000000000..c8035b4fa167e --- /dev/null +++ b/test/NameLookup/Inputs/custom_attrs_B.swift @@ -0,0 +1,13 @@ +@propertyWrapper +public struct Wrapper { + public var wrappedValue: Value + + public init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +@_functionBuilder +public struct Builder { + static func buildBlock(_ component: T) -> T { component } +} diff --git a/test/NameLookup/custom_attrs_ambiguous.swift b/test/NameLookup/custom_attrs_ambiguous.swift new file mode 100644 index 0000000000000..b549e34e273ba --- /dev/null +++ b/test/NameLookup/custom_attrs_ambiguous.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/custom_attrs_A.swift +// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/custom_attrs_B.swift +// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unknown -I %t %s +import custom_attrs_A +import custom_attrs_B + +// SR-13470 + +struct Test { + @Wrapper var x: Int = 17 + // expected-error@-1 {{ambiguous use of attribute 'Wrapper'}} + // expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Wrapper' in module 'custom_attrs_A'}} {{4-4=custom_attrs_A.}} + // expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Wrapper' in module 'custom_attrs_B'}} {{4-4=custom_attrs_B.}} + + init(@Builder closure: () -> Int) {} + // expected-error@-1 {{ambiguous use of attribute 'Builder'}} + // expected-note@-2 {{use 'custom_attrs_A.' to reference the attribute 'Builder' in module 'custom_attrs_A'}} {{9-9=custom_attrs_A.}} + // expected-note@-3 {{use 'custom_attrs_B.' to reference the attribute 'Builder' in module 'custom_attrs_B'}} {{9-9=custom_attrs_B.}} +} + diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil index 32cfdebb32c0f..f65cee1ca6e16 100644 --- a/test/SIL/Parser/async.sil +++ b/test/SIL/Parser/async.sil @@ -16,7 +16,7 @@ bb0(%int : $Builtin.Int32): return %0 : $() } -// CHECK: sil @async_test : $@async +// CHECK: sil @async_test : $@convention(thin) @async sil @async_test : $@async () -> () { bb0: %0 = tuple () diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index 1d9f1de1a810e..f6950e30ab2a5 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -15,7 +15,7 @@ bb0(%0 : @guaranteed $Builtin.NativeObject): return undef : $() } -// CHECK-LABEL: sil @async_test : $@async @convention(thin) +// CHECK-LABEL: sil @async_test : $@convention(thin) @async sil @async_test : $@async () -> () { bb0: %0 = tuple () diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift index 8fc06fb8ed67a..0895a9a0f018a 100644 --- a/test/SILGen/default_arguments.swift +++ b/test/SILGen/default_arguments.swift @@ -156,7 +156,7 @@ class Foo { return x } - // CHECK-LABEL: sil private [ossa] @globalinit_33_E52D764B1F2009F2390B2B8DF62DAEB8_func0 + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ // CHECK: string_literal utf8 "Foo" static let x = Foo(int:0) diff --git a/test/SILGen/fragile_globals.swift b/test/SILGen/fragile_globals.swift index 0a4ace7ffa3a1..c6c6e412eece0 100644 --- a/test/SILGen/fragile_globals.swift +++ b/test/SILGen/fragile_globals.swift @@ -11,7 +11,7 @@ var mygg = 29 // Check if we have one token: from mygg. // Initializers from other modules are never fragile. -// CHECK: sil_global private{{.*}} @globalinit_[[T3:.*]]_token0 +// CHECK: sil_global private{{.*}} @[[T3:.*]]Wz //@inlinable public func sum() -> Int { @@ -21,8 +21,8 @@ public func sum() -> Int { // Check if all the addressors are inlined. // CHECK-LABEL: sil {{.*}}@$s15fragile_globals3sumSiyF -// CHECK-DAG: global_addr @globalinit_[[T1:.*]]_token0 -// CHECK-DAG: function_ref @globalinit_[[T1]]_func0 +// CHECK-DAG: global_addr @[[T1:.*]]Wz +// CHECK-DAG: function_ref @[[T1]]WZ // CHECK-DAG: global_addr @$s15fragile_globals4myggSivp // CHECK-DAG: function_ref @$s7ModuleA2ggSivau // CHECK-DAG: function_ref @$s7ModuleB2ggSivau diff --git a/test/SILGen/global_resilience.swift b/test/SILGen/global_resilience.swift index 78b425a9ed684..2f5ea45c549e8 100644 --- a/test/SILGen/global_resilience.swift +++ b/test/SILGen/global_resilience.swift @@ -43,21 +43,21 @@ public var myEmptyGlobal = MyEmptyStruct() // Mutable addressor for fixed-layout global -// CHECK-LABEL: sil private [ossa] @globalinit_{{.*}}_func1 +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ // CHECK: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return // CHECK-LABEL: sil [global_init] [ossa] @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvau -// CHECK: function_ref @globalinit_{{.*}}_func1 +// CHECK: function_ref @{{.*}}WZ // CHECK: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK: return -// CHECK-OPT-LABEL: sil private @globalinit_{{.*}}_func1 +// CHECK-OPT-LABEL: sil private [global_init_once_fn] @{{.*}}WZ // CHECK-OPT: alloc_global @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVv // CHECK-OPT: return // CHECK-OPT-LABEL: sil [global_init] @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvau -// CHECK-OPT: function_ref @globalinit_{{.*}}_func1 +// CHECK-OPT: function_ref @{{.*}}WZ // CHECK-OPT: global_addr @$s17global_resilience19myFixedLayoutGlobalAA13MyEmptyStructVvp // CHECK-OPT: return diff --git a/test/SILGen/lazy_globals.swift b/test/SILGen/lazy_globals.swift index 4e1cc299c3468..c5604dc5a159a 100644 --- a/test/SILGen/lazy_globals.swift +++ b/test/SILGen/lazy_globals.swift @@ -1,14 +1,14 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func0 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals1xSiv // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: store {{%.*}} to [trivial] [[XADDR]] : $*Int // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals1xSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token0 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func0 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals1xSivp : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -16,7 +16,7 @@ // CHECK: } var x: Int = 0 -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func1 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3FooV3fooSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -24,9 +24,9 @@ var x: Int = 0 struct Foo { // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals3FooV3fooSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token1 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func1 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals3FooV3fooSivpZ : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -40,7 +40,7 @@ struct Foo { static var initialized: Int = 57 } -// CHECK: sil private [ossa] @globalinit_[[T:.*]]_func3 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*3bar.*]]WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s12lazy_globals3BarO3barSivpZ // CHECK: [[XADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: store {{.*}} to [trivial] [[XADDR]] : $*Int @@ -48,9 +48,9 @@ struct Foo { enum Bar { // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals3BarO3barSivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @globalinit_[[T]]_token3 : $*Builtin.Word +// CHECK: [[TOKEN_ADDR:%.*]] = global_addr @[[T]]Wz : $*Builtin.Word // CHECK: [[TOKEN_PTR:%.*]] = address_to_pointer [[TOKEN_ADDR]] : $*Builtin.Word to $Builtin.RawPointer -// CHECK: [[INIT_FUNC:%.*]] = function_ref @globalinit_[[T]]_func3 : $@convention(c) () -> () +// CHECK: [[INIT_FUNC:%.*]] = function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: builtin "once"([[TOKEN_PTR]] : $Builtin.RawPointer, [[INIT_FUNC]] : $@convention(c) () -> ()) : $() // CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s12lazy_globals3BarO3barSivpZ : $*Int // CHECK: [[GLOBAL_PTR:%.*]] = address_to_pointer [[GLOBAL_ADDR]] : $*Int to $Builtin.RawPointer @@ -63,13 +63,13 @@ enum Bar { func f() -> (Int, Int) { return (1, 2) } -// CHECK: sil private [ossa] @globalinit_[[T]]_func4 : $@convention(c) () -> () { +// CHECK: sil private [global_init_once_fn] [ossa] @[[T:.*2a1.*2b1.*]]WZ : $@convention(c) () -> () { // CHECK: function_ref @$s12lazy_globals1fSi_SityF : $@convention(thin) () -> (Int, Int) // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2a1Sivau : $@convention(thin) () -> Builtin.RawPointer -// CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () +// CHECK: function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: global_addr @$s12lazy_globals2a1Sivp : $*Int // CHECK: sil hidden [global_init] [ossa] @$s12lazy_globals2b1Sivau : $@convention(thin) () -> Builtin.RawPointer { -// CHECK: function_ref @globalinit_[[T]]_func4 : $@convention(c) () -> () +// CHECK: function_ref @[[T]]WZ : $@convention(c) () -> () // CHECK: global_addr @$s12lazy_globals2b1Sivp : $*Int var (a1, b1) = f() diff --git a/test/SILGen/lazy_globals_multiple_vars.swift b/test/SILGen/lazy_globals_multiple_vars.swift index 0c415d5c20231..059cfa8267cbf 100644 --- a/test/SILGen/lazy_globals_multiple_vars.swift +++ b/test/SILGen/lazy_globals_multiple_vars.swift @@ -1,34 +1,34 @@ // RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s -// CHECK: sil private [ossa] [[INIT_A_B:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_A_B:@.*1a.*1b.*WZ]] : // CHECK: alloc_global @$s26lazy_globals_multiple_vars1aSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1aSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1bSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1bSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1aSivau -// CHECK: global_addr [[TOKEN_A_B:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_A_B:@.*1a.*1b.*Wz]] : // CHECK: function_ref [[INIT_A_B]] // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1bSivau // CHECK: global_addr [[TOKEN_A_B]] // CHECK: function_ref [[INIT_A_B]] var (a, b) = (1, 2) -// CHECK: sil private [ossa] [[INIT_C:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_C:@.*1c.*WZ]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1cSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1cSivau -// CHECK: global_addr [[TOKEN_C:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_C:@.*1c.*Wz]] : // CHECK: function_ref [[INIT_C]] -// CHECK: sil private [ossa] [[INIT_D:@globalinit_.*]] : +// CHECK: sil private [global_init_once_fn] [ossa] [[INIT_D:@.*1d.*WZ]] : // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: alloc_global @$s26lazy_globals_multiple_vars1dSiv // CHECK: global_addr @$s26lazy_globals_multiple_vars1dSiv // CHECK-NOT: global_addr @$s26lazy_globals_multiple_vars1cSiv // CHECK: sil hidden [global_init] [ossa] @$s26lazy_globals_multiple_vars1dSivau // CHECK-NOT: global_addr [[TOKEN_C]] -// CHECK: global_addr [[TOKEN_D:@globalinit_.*]] : +// CHECK: global_addr [[TOKEN_D:@.*1d.*Wz]] : // CHECK-NOT: global_addr [[TOKEN_C]] // CHECK: function_ref [[INIT_D]] var c = 1, d = 2 diff --git a/test/SILGen/observers.swift b/test/SILGen/observers.swift index 3051c0a1126c7..6b6c6d4503fa1 100644 --- a/test/SILGen/observers.swift +++ b/test/SILGen/observers.swift @@ -171,7 +171,7 @@ public struct DidSetWillSetTests { var global_observing_property : Int = zero { // The variable is initialized with "zero". - // CHECK-LABEL: sil private [ossa] @globalinit_{{.*}}_func1 : $@convention(c) () -> () { + // CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: bb0: // CHECK-NEXT: alloc_global @$s9observers25global_observing_propertySiv // CHECK-NEXT: %1 = global_addr @$s9observers25global_observing_propertySivp : $*Int diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index 1ed6f62f84fdd..6062f4116579f 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -627,17 +627,17 @@ func testShims() -> UInt32 { // --- global variable initialization. var globalString1 = "⓪" // start non-empty -// CHECK-LABEL: sil private [ossa] @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString1SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString1SSvp : $*String // CHECK: apply // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[GA]] : $*String // CHECK: store %{{.*}} to [init] [[ACCESS]] : $*String // CHECK: end_access -// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func0' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' var globalString2 = globalString1 -// CHECK-LABEL: sil private [ossa] @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify13globalString2SSvp // CHECK: [[GA:%.*]] = global_addr @$s20access_marker_verify13globalString2SSvp : $*String // CHECK: apply @@ -648,7 +648,7 @@ var globalString2 = globalString1 // CHECK: end_access [[INIT]] : $*String // CHECK: end_access [[ACCESS]] : $*String // CHECK-NOT: end_access -// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' // --- getter. @@ -1037,13 +1037,13 @@ func testPointerInit(x: Int, y: UnsafeMutablePointer) { class testInitExistentialGlobal { static var testProperty: P = StructP() } -// CHECK-LABEL: sil private [ossa] @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () { // CHECK: alloc_global @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ // CHECK: [[GADR:%.*]] = global_addr @$s20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P // CHECK: %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP // CHECK: [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP // CHECK: store %{{.*}} to [trivial] [[EADR]] : $*StructP -// CHECK-LABEL: } // end sil function 'globalinit +// CHECK-LABEL: } // end sil function '{{.*}}WZ public enum SomeError: Swift.Error { case error diff --git a/test/SILOptimizer/access_marker_verify_objc.swift b/test/SILOptimizer/access_marker_verify_objc.swift index b9fc5fbaa7c0e..c3e1ed48efe35 100644 --- a/test/SILOptimizer/access_marker_verify_objc.swift +++ b/test/SILOptimizer/access_marker_verify_objc.swift @@ -12,14 +12,14 @@ import Foundation // --- initializer `let` of CFString. // The verifier should ignore this. -// CHECK_LABEL: sil private @globalinit{{.*}} : $@convention(c) () -> () { +// CHECK_LABEL: sil private @{{.*}}WZ : $@convention(c) () -> () { // CHECK: bb0: // CHECK: alloc_global @$s25access_marker_verify_objc12testCFStringC8cfStringSo0F3RefavpZ // CHECK: [[GA:%.*]] = global_addr @$s25access_marker_verify_objc12testCFStringC8cfStringSo0F3RefavpZ : $*CFString // CHECK-NOT: begin_access // CHECK: store %{{.*}} to [init] [[GA]] : $*CFString // CHECK: return %{{.*}} : $() -// CHECK-LABEL: } // end sil function 'globalinit{{.*}}' +// CHECK-LABEL: } // end sil function '{{.*}}WZ' class testCFString { public static let cfString: CFString = "" as CFString } diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil index bc8b42ba2426d..21944bbe21603 100644 --- a/test/SILOptimizer/escape_analysis.sil +++ b/test/SILOptimizer/escape_analysis.sil @@ -1983,3 +1983,27 @@ bb4: %z = tuple () return %z : $() } + +// Test CGNode mapping for result of an apply to no return function +// CHECK-LABEL:CG of $testcaller +// CHECK: Arg [ref] %0 Esc: A, Succ: (%0.1) +// CHECK: Con [int] %0.1 Esc: A, Succ: (%0.2) +// CHECK: Con [ref] %0.2 Esc: A, Succ: +// CHECK-LABEL:End +sil hidden [noinline] @$testcaller : $@convention(thin) (@owned Z) -> () { +bb0(%0 : $Z): + %2 = function_ref @$noreturncallee : $@convention(thin) (@guaranteed Z) -> @owned Z + %3 = apply %2(%0) : $@convention(thin) (@guaranteed Z) -> @owned Z + dealloc_ref %3 : $Z + %5 = tuple () + return %5 : $() +} + +// CHECK-LABEL:CG of $noreturncallee +// CHECK: Arg [ref] %0 Esc: A, Succ: +// CHECK-LABEL:End +sil hidden [noinline] @$noreturncallee : $@convention(thin) (@guaranteed Z) -> @owned Z { +bb0(%0 : $Z): + unreachable +} + diff --git a/test/SILOptimizer/globalopt_trivial_nontrivial.sil b/test/SILOptimizer/globalopt_trivial_nontrivial.sil index 3625c10946211..8f094f633febb 100644 --- a/test/SILOptimizer/globalopt_trivial_nontrivial.sil +++ b/test/SILOptimizer/globalopt_trivial_nontrivial.sil @@ -38,7 +38,7 @@ sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word sil_global hidden [let] @$nontrivialglobal : $TClass -sil private @globalinit_trivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_trivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$trivialglobal %1 = global_addr @$trivialglobal : $*TStruct @@ -83,13 +83,13 @@ bb0: return %4 : $Int32 } -// CHECK-LABEL: sil private @globalinit_nontrivialglobal_func : +// CHECK-LABEL: sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : // CHECK: alloc_global @$nontrivialglobal // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass // CHECK: [[REF:%.*]] = alloc_ref $TClass // CHECK: store [[REF]] to [[GLOBL_ADDR]] : $*TClass // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' -sil private @globalinit_nontrivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$nontrivialglobal %1 = global_addr @$nontrivialglobal : $*TClass diff --git a/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil b/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil index 182210cb2671e..433aff21f011f 100644 --- a/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil +++ b/test/SILOptimizer/globalopt_trivial_nontrivial_ossa.sil @@ -32,7 +32,7 @@ sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word sil_global hidden [let] @$nontrivialglobal : $TClass -sil private [ossa] @globalinit_trivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] [ossa] @globalinit_trivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$trivialglobal %1 = global_addr @$trivialglobal : $*TStruct @@ -75,13 +75,13 @@ bb0: return %4 : $Int32 } -// CHECK-LABEL: sil private [ossa] @globalinit_nontrivialglobal_func : +// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @globalinit_nontrivialglobal_func : // CHECK: alloc_global @$nontrivialglobal // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass // CHECK: [[REF:%.*]] = alloc_ref $TClass // CHECK: store [[REF]] to [init] [[GLOBL_ADDR]] : $*TClass // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' -sil private [ossa] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { +sil private [global_init_once_fn] [ossa] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { bb0: alloc_global @$nontrivialglobal %1 = global_addr @$nontrivialglobal : $*TClass diff --git a/test/SILOptimizer/inline_addressor.swift b/test/SILOptimizer/inline_addressor.swift index c78e0a25c5f41..369799a725370 100644 --- a/test/SILOptimizer/inline_addressor.swift +++ b/test/SILOptimizer/inline_addressor.swift @@ -11,10 +11,10 @@ var totalsum = nonTrivialInit(true) //CHECK-LABEL: sil {{.*}}testit //CHECK: {{^bb0}} -//CHECK: globalinit_ +//CHECK: WZ //CHECK-NOT: {{^bb0}} //CHECK: {{^bb1}} -//CHECK-NOT: globalinit +//CHECK-NOT: WZ //CHECK-NOT: totalsum //CHECK-NOT: inputval //CHECK: {{^}$}} diff --git a/test/SILOptimizer/static_initializer.sil b/test/SILOptimizer/static_initializer.sil index bcdb29794c702..dbc5e28526a4f 100644 --- a/test/SILOptimizer/static_initializer.sil +++ b/test/SILOptimizer/static_initializer.sil @@ -25,8 +25,8 @@ sil_global private @globalinit_token0 : $Builtin.Word // CHECK-NEXT: } sil_global @_Tv2ch1xSi : $Outer -// CHECK-LABEL: sil private @globalinit_func0 : $@convention(c) () -> () { -sil private @globalinit_func0 : $@convention(c) () -> () { +// CHECK-LABEL: sil private [global_init_once_fn] @globalinit_func0 : $@convention(c) () -> () { +sil private [global_init_once_fn] @globalinit_func0 : $@convention(c) () -> () { bb0: %0 = global_addr @_Tv2ch1xSi : $*Outer %1 = integer_literal $Builtin.Int32, 2 diff --git a/test/ScanDependencies/Inputs/CHeaders/G.h b/test/ScanDependencies/Inputs/CHeaders/G.h index ef09c49a98e0f..4da23ffcbb4f6 100644 --- a/test/ScanDependencies/Inputs/CHeaders/G.h +++ b/test/ScanDependencies/Inputs/CHeaders/G.h @@ -1 +1,6 @@ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000 +#include "X.h" +#endif + void funcG(void); + diff --git a/test/ScanDependencies/Inputs/CHeaders/X.h b/test/ScanDependencies/Inputs/CHeaders/X.h new file mode 100644 index 0000000000000..11c123884ef12 --- /dev/null +++ b/test/ScanDependencies/Inputs/CHeaders/X.h @@ -0,0 +1 @@ +void funcX(void); diff --git a/test/ScanDependencies/Inputs/CHeaders/module.modulemap b/test/ScanDependencies/Inputs/CHeaders/module.modulemap index 481266591c912..95fc7fef133c2 100644 --- a/test/ScanDependencies/Inputs/CHeaders/module.modulemap +++ b/test/ScanDependencies/Inputs/CHeaders/module.modulemap @@ -37,3 +37,8 @@ module I { header "I.h" export * } + +module X { + header "X.h" + export * +} diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift index 08151fc4eb6f6..59189771b340f 100644 --- a/test/ScanDependencies/batch_module_scan.swift +++ b/test/ScanDependencies/batch_module_scan.swift @@ -28,6 +28,7 @@ // CHECK-PCM-NEXT: }, // CHECK-PCM-NEXT: { // CHECK-PCM-NEXT: "modulePath": "F.pcm", +// CHECK-PCM: "-I // CHECK-SWIFT: { // CHECK-SWIFT-NEXT: "mainModuleName": "F", diff --git a/test/ScanDependencies/batch_module_scan_versioned.swift b/test/ScanDependencies/batch_module_scan_versioned.swift new file mode 100644 index 0000000000000..02725a2ff0160 --- /dev/null +++ b/test/ScanDependencies/batch_module_scan_versioned.swift @@ -0,0 +1,49 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: %empty-directory(%t/outputs) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: echo "[{" > %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"G\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-Xcc -target -Xcc x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/G_109.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}," >> %/t/inputs/input.json +// RUN: echo "{" >> %/t/inputs/input.json +// RUN: echo "\"clangModuleName\": \"G\"," >> %/t/inputs/input.json +// RUN: echo "\"arguments\": \"-Xcc -target -Xcc x86_64-apple-macosx11.0\"," >> %/t/inputs/input.json +// RUN: echo "\"output\": \"%/t/outputs/G_110.pcm.json\"" >> %/t/inputs/input.json +// RUN: echo "}]" >> %/t/inputs/input.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json + +// Check the contents of the JSON output +// RUN: %FileCheck %s -check-prefix=CHECK-PCM109 < %t/outputs/G_109.pcm.json +// RUN: %FileCheck %s -check-prefix=CHECK-PCM110 < %t/outputs/G_110.pcm.json + +// CHECK-PCM109: { +// CHECK-PCM109-NEXT: "mainModuleName": "G", +// CHECK-PCM109-NEXT: "modules": [ +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "clang": "G" +// CHECK-PCM109-NEXT: }, +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "modulePath": "G.pcm", +// CHECK-PCM109: "directDependencies": [ +// CHECK-PCM109-NEXT: { +// CHECK-PCM109-NEXT: "clang": "X" +// CHECK-PCM109-NEXT: } +// CHECK-PCM109-NEXT: ], +// CHECK-PCM109: "-I + +// CHECK-PCM110: { +// CHECK-PCM110-NEXT: "mainModuleName": "G", +// CHECK-PCM110-NEXT: "modules": [ +// CHECK-PCM110-NEXT: { +// CHECK-PCM110-NEXT: "clang": "G" +// CHECK-PCM110-NEXT: }, +// CHECK-PCM110-NEXT: { +// CHECK-PCM110-NEXT: "modulePath": "G.pcm", +// CHECK-PCM110: "directDependencies": [ +// CHECK-PCM110-NEXT: ], +// CHECK-PCM110-NOT: "clang": "X" +// CHECK-PCM110: "-I diff --git a/test/ScanDependencies/can_import_placeholder.swift b/test/ScanDependencies/can_import_placeholder.swift new file mode 100644 index 0000000000000..8c14c6b2a125e --- /dev/null +++ b/test/ScanDependencies/can_import_placeholder.swift @@ -0,0 +1,55 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// RUN: mkdir -p %t/inputs + +// RUN: echo "[{" > %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SomeExternalModule\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/t/inputs/SomeExternalModule.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"docPath\": \"%/t/inputs/SomeExternalModule.swiftdoc\"," >> %/t/inputs/map.json +// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/SomeExternalModule.swiftsourceinfo\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}]" >> %/t/inputs/map.json + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 + +// Check the contents of the JSON output +// RUN: %FileCheck %s < %t/deps.json + +// REQUIRES: executable_test +// REQUIRES: objc_interop +#if canImport(SomeExternalModule) +import SomeExternalModule +#endif + +// CHECK: "mainModuleName": "deps" + +/// --------Main module +// CHECK-LABEL: "modulePath": "deps.swiftmodule", +// CHECK-NEXT: sourceFiles +// CHECK-NEXT: can_import_placeholder.swift + +// CHECK: directDependencies +// CHECK-NEXT: { +// CHECK-NEXT: "swiftPlaceholder": "SomeExternalModule" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "Swift" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "SwiftOnoneSupport" +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "F" +// CHECK-NEXT: } +// CHECK-NEXT: ], + diff --git a/test/ScanDependencies/diagnose_dependency_cycle.swift b/test/ScanDependencies/diagnose_dependency_cycle.swift index 1157d364a7954..609fd331646eb 100644 --- a/test/ScanDependencies/diagnose_dependency_cycle.swift +++ b/test/ScanDependencies/diagnose_dependency_cycle.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules &> %t/out.txt +// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 &> %t/out.txt // RUN: %FileCheck %s < %t/out.txt diff --git a/test/ScanDependencies/module_deps.swift b/test/ScanDependencies/module_deps.swift index 7e3a62507ed99..dc48ba5e0998d 100644 --- a/test/ScanDependencies/module_deps.swift +++ b/test/ScanDependencies/module_deps.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json @@ -105,7 +105,6 @@ import SubE // CHECK-NEXT: "-only-use-extra-clang-opts" // CHECK-NEXT: "-Xcc" // CHECK-NEXT: "clang" -// CHECK: "-fno-implicit-modules" /// --------Swift module E // CHECK: "swift": "E" @@ -195,9 +194,7 @@ import SubE /// --------Clang module SwiftShims // CHECK-LABEL: "modulePath": "SwiftShims.pcm", -// CHECK-NO-SEARCH-PATHS-NOT: "-I" // CHECK-NO-SEARCH-PATHS-NOT: "-sdk" -// CHECK-NO-SEARCH-PATHS-NOT: "-F" // CHECK-NO-SEARCH-PATHS-NOT: "-prebuilt-module-cache-path" // Check make-style dependencies diff --git a/test/ScanDependencies/module_deps_clang_only.swift b/test/ScanDependencies/module_deps_clang_only.swift index e406bacd74889..34ac0c6eeefd1 100644 --- a/test/ScanDependencies/module_deps_clang_only.swift +++ b/test/ScanDependencies/module_deps_clang_only.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-clang-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules -module-name C +// RUN: %target-swift-frontend -scan-clang-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -module-name C // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_cross_import_overlay.swift b/test/ScanDependencies/module_deps_cross_import_overlay.swift index 7b1bfd9b63363..94031c4ce38bc 100644 --- a/test/ScanDependencies/module_deps_cross_import_overlay.swift +++ b/test/ScanDependencies/module_deps_cross_import_overlay.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_external.swift b/test/ScanDependencies/module_deps_external.swift index c7eb47a7f4e87..f3b2147a487da 100644 --- a/test/ScanDependencies/module_deps_external.swift +++ b/test/ScanDependencies/module_deps_external.swift @@ -20,7 +20,7 @@ // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_deps_private_interface.swift b/test/ScanDependencies/module_deps_private_interface.swift index bbf0a2dfbd053..2098775216ea8 100644 --- a/test/ScanDependencies/module_deps_private_interface.swift +++ b/test/ScanDependencies/module_deps_private_interface.swift @@ -6,7 +6,7 @@ // RUN: cp %t/Foo.swiftinterface %t/Foo.private.swiftinterface -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ScanDependencies/module_framework.swift b/test/ScanDependencies/module_framework.swift index 937667d98d025..9756277074277 100644 --- a/test/ScanDependencies/module_framework.swift +++ b/test/ScanDependencies/module_framework.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -Xcc -Xclang // Check the contents of the JSON output // RUN: %FileCheck %s < %t/deps.json diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift index beae8a87fa53e..d43c5c299b806 100644 --- a/test/Sema/immutability.swift +++ b/test/Sema/immutability.swift @@ -61,13 +61,13 @@ class FooClass { mutating init(a : Bool) {} // expected-error {{'mutating' may only be used on 'func' declarations}} {{3-12=}} - mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} + mutating // expected-error {{'mutating' is not valid on instance methods in classes}} {{3-12=}} func baz() {} - nonmutating // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} {{3-15=}} + nonmutating // expected-error {{'nonmutating' is not valid on instance methods in classes}} {{3-15=}} func bay() {} - mutating nonmutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + mutating nonmutating // expected-error {{'mutating' is not valid on instance methods in classes}} expected-error {{'nonmutating' is not valid on instance methods in classes}} func bax() {} var x : Int { @@ -86,6 +86,15 @@ class FooClass { } } + var computed: Int { + mutating get { 0 } // expected-error {{'mutating' is not valid on getters in classes}} {{5-14=}} + nonmutating set {} // expected-error {{'nonmutating' is not valid on setters in classes}} {{5-17=}} + } + + var storedWithObservers: Int = 0 { + mutating willSet {} // expected-error {{'mutating' is not valid on willSet observers in classes}} {{5-14=}} + nonmutating didSet {} // expected-error {{'nonmutating' is not valid on didSet observers in classes}} {{5-17=}} + } } @@ -241,7 +250,7 @@ func test_arguments(_ a : Int, protocol ClassBoundProtocolMutating : class { - mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} + mutating // expected-error {{'mutating' is not valid on instance methods in class-bound protocols}} {{3-12=}} func f() } diff --git a/test/Serialization/Inputs/objc-xref/module.modulemap b/test/Serialization/Inputs/objc-xref/module.modulemap new file mode 100644 index 0000000000000..7c036997bed3b --- /dev/null +++ b/test/Serialization/Inputs/objc-xref/module.modulemap @@ -0,0 +1,4 @@ +module ObjCXRef { + header "objc_xref.h" + export * +} diff --git a/test/Serialization/Inputs/objc-xref/objc_xref.h b/test/Serialization/Inputs/objc-xref/objc_xref.h new file mode 100644 index 0000000000000..d3b7a87ef6439 --- /dev/null +++ b/test/Serialization/Inputs/objc-xref/objc_xref.h @@ -0,0 +1,2 @@ +@interface MyObject +@end diff --git a/test/Serialization/xref-deinit.swift b/test/Serialization/xref-deinit.swift new file mode 100644 index 0000000000000..98c43b6670a87 --- /dev/null +++ b/test/Serialization/xref-deinit.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-sib %s -o %t/xref-deinit.sib -I%t -I %S/Inputs/objc-xref +// RUN: %target-swift-frontend -emit-sil %t/xref-deinit.sib -I%t -I %S/Inputs/objc-xref + +// REQUIRES: objc_interop + +import ObjCXRef + +public class Object: MyObject {} diff --git a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift index 388c09e57af33..84753c3a8c3f2 100644 --- a/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift +++ b/test/SourceKit/CodeComplete/complete_checkdeps_vfs.swift @@ -4,8 +4,8 @@ func foo(value: MyStruct) { // REQUIRES: shell -// RUN: DEPCHECK_INTERVAL=1 -// RUN: SLEEP_TIME=2 +// RUN: DEPCHECK_INTERVAL=2 +// RUN: SLEEP_TIME=3 // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/VFS) @@ -23,7 +23,14 @@ func foo(value: MyStruct) { // RUN: -shell -- echo "### Keep" == \ // RUN: -shell -- sleep ${SLEEP_TIME} == \ -// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject_mod/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject_mod/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ + +// RUN: -shell -- echo "### Rollback without sleep" == \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift == \ + +// RUN: -shell -- echo "### After sleep" == \ +// RUN: -shell -- sleep ${SLEEP_TIME} == \ +// RUN: -req=complete -pos=2:9 -pass-as-sourcetext -vfs-files=%t/VFS/Main.swift=@%s,%t/VFS/Library.swift=@%S/Inputs/checkdeps/MyProject/Library.swift %t/VFS/Main.swift -- -target %target-triple %t/VFS/Main.swift %t/VFS/LibraryExt.swift %t/VFS/Library.swift \ // RUN: | %FileCheck %s @@ -50,3 +57,19 @@ func foo(value: MyStruct) { // CHECK-DAG: key.description: "self" // CHECK: ] // CHECK: key.reusingastcontext: 1 + +// CHECK-LABEL: ### Rollback without sleep +// CHECK: key.results: [ +// CHECK-DAG: key.description: "myStructMethod_mod()" +// CHECK-DAG: key.description: "extensionMethod()" +// CHECK-DAG: key.description: "self" +// CHECK: ] +// CHECK: key.reusingastcontext: 1 + +// CHECK-LABEL: ### After sleep +// CHECK: key.results: [ +// CHECK-DAG: key.description: "myStructMethod()" +// CHECK-DAG: key.description: "extensionMethod()" +// CHECK-DAG: key.description: "self" +// CHECK: ] +// CHECK-NOT: key.reusingastcontext: 1 diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift index 3de399487412f..b1728b6f61d48 100644 --- a/test/api-digester/Inputs/cake.swift +++ b/test/api-digester/Inputs/cake.swift @@ -139,3 +139,6 @@ public class UnavailableOnMac {} extension SwiftObjcClass { public func functionUnavailableOnMac() {} } + +@_alwaysEmitIntoClient +public func emitIntoClientFunc() {} diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json index 8a487febb665b..08a230436a852 100644 --- a/test/api-digester/Outputs/cake.json +++ b/test/api-digester/Outputs/cake.json @@ -1340,6 +1340,25 @@ ], "hasMissingDesignatedInitializers": true }, + { + "kind": "Function", + "name": "emitIntoClientFunc", + "printedName": "emitIntoClientFunc()", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + } + ], + "declKind": "Func", + "usr": "s:4cake18emitIntoClientFuncyyF", + "moduleName": "cake", + "declAttributes": [ + "AlwaysEmitIntoClient" + ], + "funcSelfKind": "NonMutating" + }, { "kind": "TypeDecl", "name": "Int", diff --git a/test/api-digester/compare-clang-dump.swift b/test/api-digester/compare-clang-dump.swift index cdb59d1bf93a4..3cafec46d6288 100644 --- a/test/api-digester/compare-clang-dump.swift +++ b/test/api-digester/compare-clang-dump.swift @@ -3,7 +3,7 @@ // RUN: %empty-directory(%t.module-cache) // RUN: %api-digester -dump-sdk -module Foo -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo -avoid-location // RUN: %api-digester -dump-sdk -module Foo -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %S/Inputs/Foo-new-version -avoid-location -// RUN: %api-digester -diagnose-sdk -protocol-requirement-white-list %S/Inputs/Foo-prot-allowlist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result +// RUN: %api-digester -diagnose-sdk -protocol-requirement-allow-list %S/Inputs/Foo-prot-allowlist.txt -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -o %t.result // RUN: %clang -E -P -x c %S/Outputs/Foo-diff.txt -o - | sed '/^\s*$/d' > %t.expected // RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp diff --git a/test/api-digester/use-interface-for.swift b/test/api-digester/use-interface-for.swift new file mode 100644 index 0000000000000..6399084893092 --- /dev/null +++ b/test/api-digester/use-interface-for.swift @@ -0,0 +1,20 @@ +// REQUIRES: VENDOR=apple + +// RUN: %empty-directory(%t.mod) +// RUN: %empty-directory(%t.sdk) +// RUN: %empty-directory(%t.module-cache) + +// RUN: echo "public func foo() {}" > %t.swift + +// RUN: %target-swift-frontend -emit-module -emit-module-interface-path %t.mod/cake.swiftinterface %t.swift %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache -emit-module-path %t.mod/cake.swiftmodule -module-name cake -swift-version 5 + +// Step 1: we should be able to load if we prefer cake.swiftinterface +// RUN: %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail -use-interface-for-module cake + +// RUN: echo "Swift Syntax Error" >> %t.mod/cake.swiftinterface + +// Step 2: we shouldn't be able to load if we prefer cake.swiftinterface and cake.swiftinterface is broken +// RUN: not %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail -use-interface-for-module cake + +// Step 3: we should be able to load if we don't prefer cake.swiftinterface +// RUN: %api-digester -dump-sdk -print-module -module cake -I %t.mod -sdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.json -abi -abort-on-module-fail diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index 6729bba8d1e07..b6f5133acfd8d 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -267,14 +267,14 @@ extension ImposeClassReq1 where Self: AnyObject { var wrappingProperty2: Int { get { return someProperty } - mutating set { someProperty = newValue } // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} + mutating set { someProperty = newValue } // expected-error {{'mutating' is not valid on setters in class-bound protocols}} } - mutating func foo() { // expected-error {{mutating' isn't valid on methods in classes or class-bound protocols}} + mutating func foo() { // expected-error {{mutating' is not valid on instance methods in class-bound protocols}} someProperty = 1 } - nonmutating func bar() { // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + nonmutating func bar() { // expected-error {{'nonmutating' is not valid on instance methods in class-bound protocols}} someProperty = 2 } @@ -309,14 +309,14 @@ extension ImposeClassReq2 { var wrappingProperty2: Int { get { return someProperty } - mutating set { someProperty = newValue } // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} + mutating set { someProperty = newValue } // expected-error {{'mutating' is not valid on setters in class-bound protocols}} } - mutating func foo() { // expected-error {{mutating' isn't valid on methods in classes or class-bound protocols}} + mutating func foo() { // expected-error {{mutating' is not valid on instance methods in class-bound protocols}} someProperty = 1 } - nonmutating func bar() { // expected-error {{'nonmutating' isn't valid on methods in classes or class-bound protocols}} + nonmutating func bar() { // expected-error {{'nonmutating' is not valid on instance methods in class-bound protocols}} someProperty = 2 } diff --git a/test/decl/protocol/fixits_missing_protocols_in_context.swift b/test/decl/protocol/fixits_missing_protocols_in_context.swift new file mode 100644 index 0000000000000..0511266896062 --- /dev/null +++ b/test/decl/protocol/fixits_missing_protocols_in_context.swift @@ -0,0 +1,45 @@ +// RUN: %target-swift-frontend -typecheck -diagnostics-editor-mode -verify %s + +// Test that we emit fix-its to insert requirement stubs for the missing protocol conformance, in addition to adding the conformance. + +protocol P { + func method() + var property: Int { get } +} + +class C { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C'}} {{8-8=: P}} {{10-10=\n func method() {\n <#code#>\n \}\n\n var property: Int\n}} + } +} + +// Test that we don't emit fix-it to insert a requirement stub if there is already a satisfying witness. + +class C1 { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C1' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C1'}} {{9-9=: P}} {{11-11=\n var property: Int\n}} + } + + func method() {} +} + +class C2 { + var p: P? + + func assign() { + p = self + // expected-error@-1 {{cannot assign value of type 'C2' to type 'P?'}} + // expected-note@-2 {{add missing conformance to 'P' to class 'C2'}} {{9-9=: P}} + } + + func method() {} + var property: Int = 0 +} diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift new file mode 100644 index 0000000000000..2691574dbd321 --- /dev/null +++ b/test/expr/delayed-ident/member_chains.swift @@ -0,0 +1,346 @@ +// RUN: %target-typecheck-verify-swift -swift-version 5 + +struct ImplicitMembers: Equatable { + struct Other { + var implicit: ImplicitMembers { ImplicitMembers() } + } + + static var other = Other() + static func createOther() -> Other { + Other() + } + var anotherOther: Other { Other() } + func getAnotherOther() -> Other { + Other() + } + + static var implicit = ImplicitMembers() + static let implicitLet = ImplicitMembers() // expected-note2 {{change 'let' to 'var' to make it mutable}} + static var implicitImmutable: ImplicitMembers { ImplicitMembers() } + static func createImplicit() -> ImplicitMembers { + ImplicitMembers() + } + + static var optional: ImplicitMembers? = ImplicitMembers() + static func createOptional() -> ImplicitMembers? { + ImplicitMembers() + } + static var superOptional: ImplicitMembers??? = ImplicitMembers() + + static func createIUOArg(_: Int) -> ImplicitMembers { ImplicitMembers() } + var anotherIUO: ImplicitMembers! { ImplicitMembers() } + func getAnotherIUO() -> ImplicitMembers! { ImplicitMembers() } + + var another: ImplicitMembers { ImplicitMembers() } + var anotherMutable: ImplicitMembers { + get { ImplicitMembers() } + set {} + } + + func getAnother() -> ImplicitMembers { + ImplicitMembers() + } + + func getAnother(arg: Int) -> ImplicitMembers { + ImplicitMembers() + } + + var anotherOptional: ImplicitMembers? { ImplicitMembers() } + var anotherOptionalMutable: ImplicitMembers? { + get { ImplicitMembers() } + set {} + } + + func getAnotherOptional() -> ImplicitMembers? { + ImplicitMembers() + } + + func getAnotherOptional(arg: Int) -> ImplicitMembers? { + ImplicitMembers() + } + + static func takesClosure(_: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + static func takesArgClosure(_: Int, _: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + func methodTakesClosure(_: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + func methodTakesArgClosure(_: Int, _: (Int) -> Void) -> ImplicitMembers { ImplicitMembers() } + + subscript(arg: Void) -> ImplicitMembers { + get { ImplicitMembers() } + set {} + } + subscript(optional arg: Void) -> ImplicitMembers? { + get { ImplicitMembers() } + set {} + } + subscript(immutable arg: Void) -> ImplicitMembers { ImplicitMembers() } + subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } + subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } + subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } + subscript(other arg: Void) -> Other { Other() } +} + +let _: ImplicitMembers = .implicit +let _: ImplicitMembers? = .implicit +let _: ImplicitMembers? = .optional + +let _: ImplicitMembers = .implicit.another.another +let _: ImplicitMembers = .createImplicit().another.another +let _: ImplicitMembers = .init().another.another + +let _: ImplicitMembers = .implicit.getAnother().another +let _: ImplicitMembers = .createImplicit().getAnother().another +let _: ImplicitMembers = .init().getAnother().another + +let _: ImplicitMembers = .implicit.getAnother(arg: 0).another +let _: ImplicitMembers = .createImplicit().getAnother(arg: 0).another +let _: ImplicitMembers = .init().getAnother(arg: 0).another + +let _: ImplicitMembers = .implicit.another.getAnother() +let _: ImplicitMembers = .createImplicit().another.getAnother() +let _: ImplicitMembers = .init().another.getAnother() + +let _: ImplicitMembers = .implicit.another.getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().another.getAnother(arg: 0) +let _: ImplicitMembers = .init().another.getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .init().getAnother().getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.getAnother().getAnother(arg: 0).another +let _: ImplicitMembers = .createImplicit().getAnother().getAnother(arg: 0).another +let _: ImplicitMembers = .init().getAnother().getAnother(arg: 0).another + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0) +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.another.another.another.another.another +let _: ImplicitMembers = .implicit.getAnother().getAnother().getAnother().getAnother().getAnother() +let _: ImplicitMembers = .implicit.getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0).getAnother(arg: 0) + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0).anotherIUO +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0).anotherIUO +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0).anotherIUO + +let _: ImplicitMembers = .implicit.another.getAnother().getAnother(arg: 0).getAnotherIUO() +let _: ImplicitMembers = .createImplicit().another.getAnother().getAnother(arg: 0).getAnotherIUO() +let _: ImplicitMembers = .init().another.getAnother().getAnother(arg: 0).getAnotherIUO() + +let _: ImplicitMembers = .createIUOArg(_:)(0) + +let _: ImplicitMembers = .optional! +let _: ImplicitMembers = .optional!.another +let _: ImplicitMembers = .createOptional()!.another +let _: ImplicitMembers = .optional!.anotherOptional! +let _: ImplicitMembers = .createOptional()!.anotherOptional! +let _: ImplicitMembers = .optional!.getAnotherOptional()! +let _: ImplicitMembers = .createOptional()!.getAnotherOptional()! +let _: ImplicitMembers = .implicit.getAnotherIUO() +let _: ImplicitMembers = .createImplicit().anotherIUO +let _: ImplicitMembers = .implicit.anotherIUO +let _: ImplicitMembers = .createImplicit().anotherIUO + +let _: ImplicitMembers = .optional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{35-35= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{35-35=!}} +let _: ImplicitMembers = .implicit.anotherOptional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{51-51= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{51-51=!}} +let _: ImplicitMembers = .createOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{43-43= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{43-43=!}} +let _: ImplicitMembers = .implicit.getAnotherOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{56-56= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{56-56=!}} +let _: ImplicitMembers = .implicit[optional: ()] // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{49-49= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{49-49=!}} +let _: ImplicitMembers = .implicit[funcOptional: ()]() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{55-55= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{55-55=!}} + +// FIXME: Improve these diagnostics (should probably offer unwrapping, as above) +let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{type of expression is ambiguous without more context}} +let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{type of expression is ambiguous without more context}} + + +let _: ImplicitMembers = .other.implicit +let _: ImplicitMembers = .implicit.anotherOther.implicit +let _: ImplicitMembers = .createOther().implicit +let _: ImplicitMembers = .implicit.getAnotherOther().implicit +let _: ImplicitMembers = .implicit[other: ()].implicit + +let _: ImplicitMembers = .other // expected-error {{member 'other' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'anotherOther' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod() // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember.another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} +let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod().another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} +let _: ImplicitMembers = .implicit.getAnotherOther() // expected-error {{member 'getAnotherOther()' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit[other: ()] // expected-error {{member 'subscript(other:)' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} + +let _: ImplicitMembers? = .implicit.another +let _: ImplicitMembers? = .implicit.anotherOptional + +let _: ImplicitMembers? = .optional +let _: ImplicitMembers? = .optional?.another +let _: ImplicitMembers? = .optional?.anotherOptional +let _: ImplicitMembers? = .optional?.getAnother() +let _: ImplicitMembers? = .optional?.getAnotherOptional() +let _: ImplicitMembers? = .optional?.anotherOptional?.another +let _: ImplicitMembers? = .optional?.getAnotherOptional()?.another +let _: ImplicitMembers? = .createOptional() +let _: ImplicitMembers? = .createOptional()?.another +let _: ImplicitMembers? = .createOptional()?.anotherOptional +let _: ImplicitMembers? = .createOptional()?.getAnother() +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional() +let _: ImplicitMembers? = .createOptional()?.anotherOptional?.another +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.another +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.anotherIUO +let _: ImplicitMembers? = .createOptional()?.getAnotherOptional()?.getAnotherIUO() +// FIXME: This should be allowed +// let _: ImplicitMembers? = .superOptional???.another + +let _: ImplicitMembers = .takesClosure { _ in } +let _: ImplicitMembers = .takesArgClosure(0) { _ in } +let _: ImplicitMembers = .implicit.methodTakesClosure { _ in } +let _: ImplicitMembers = .implicit.methodTakesArgClosure(0) { _ in } +let _: ImplicitMembers? = .optional?.methodTakesClosure { _ in } +let _: ImplicitMembers? = .optional?.methodTakesArgClosure(0) { _ in } + +let _: ImplicitMembers = .implicit[()] +let _: ImplicitMembers = .implicit[optional: ()]! +let _: ImplicitMembers? = .implicit[optional: ()] +let _: ImplicitMembers = .implicit[func: ()]() +let _: ImplicitMembers = .implicit[funcOptional: ()]()! +let _: ImplicitMembers? = .implicit[funcOptional: ()]() +let _: ImplicitMembers = .implicit[optionalFunc: ()]!() +let _: ImplicitMembers? = .implicit[optionalFunc: ()]?() +let _: ImplicitMembers = .implicit.another[()] +let _: ImplicitMembers = .implicit.another[optional: ()]! +let _: ImplicitMembers? = .implicit.another[optional: ()] +let _: ImplicitMembers = .implicit.another[func: ()]() +let _: ImplicitMembers = .implicit.another[funcOptional: ()]()! +let _: ImplicitMembers? = .implicit.another[funcOptional: ()]() +let _: ImplicitMembers = .implicit.another[optionalFunc: ()]!() +let _: ImplicitMembers? = .implicit.another[optionalFunc: ()]?() +let _: ImplicitMembers = .implicit[()].another +let _: ImplicitMembers = .implicit[optional: ()]!.another +let _: ImplicitMembers? = .implicit[optional: ()]?.another +let _: ImplicitMembers = .implicit[func: ()]().another +let _: ImplicitMembers = .implicit[funcOptional: ()]()!.another +let _: ImplicitMembers? = .implicit[funcOptional: ()]()?.another +let _: ImplicitMembers = .implicit[optionalFunc: ()]!().another +let _: ImplicitMembers? = .implicit[optionalFunc: ()]?().another + +func implicit(_ i: inout ImplicitMembers) { + if i == .implicit {} + if i == .implicit.another {} + if i == .implicit.getAnother() {} + if i == .optional?.another {} + if i == .optional!.another {} + if i == .createOptional()?.another {} +} + +func testLValues() { + let local = ImplicitMembers(); + + .implicit = local; + .implicit.anotherMutable = local; + .implicit.anotherOptionalMutable? = local; + .implicit.anotherOptionalMutable! = local; + .implicit[()] = local; + .implicit[()].anotherMutable = local; + .optional?[optional: ()]?.anotherOptionalMutable! = local; + + .implicitLet = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} + .implicitImmutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} + .createImplicit() = local; // expected-error {{expression is not assignable: function call returns immutable value}} + .implicit.another = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} + .implicit[immutable: ()] = local; // expected-error {{cannot assign through subscript: subscript is get-only}} + .implicit.getAnother() = local; // expected-error {{expression is not assignable: function call returns immutable value}} + + .implicitLet.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitLet' is a 'let' constant}} + .implicitImmutable.anotherMutable = local; // expected-error {{cannot assign to property: 'implicitImmutable' is a get-only property}} + .createImplicit().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} + .implicit.another.anotherMutable = local; // expected-error {{cannot assign to property: 'another' is a get-only property}} + .implicit[immutable: ()].anotherMutable = local; // expected-error {{cannot assign to property: subscript is get-only}} + .implicit.getAnother().anotherMutable = local; // expected-error {{cannot assign to property: function call returns immutable value}} + + + // FIXME: These should probably be allowed + //.implicit.anotherOptionalMutable = local; + //.optional = local; +} + +struct ImplicitGeneric { // expected-note4 {{arguments to generic parameter 'T' ('Int' and 'String') are expected to be equal}} + static var implicit: ImplicitGeneric { ImplicitGeneric() } + var another: ImplicitGeneric { ImplicitGeneric() } + func getAnother() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +extension ImplicitGeneric where T == Int { + static var implicitInt: ImplicitGeneric { ImplicitGeneric() } + static var implicitString: ImplicitGeneric { ImplicitGeneric() } + var anotherInt: ImplicitGeneric { ImplicitGeneric() } + var anotherIntString: ImplicitGeneric { ImplicitGeneric() } + func getAnotherInt() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +extension ImplicitGeneric where T == String { + static var implicitString: ImplicitGeneric { ImplicitGeneric() } + var anotherString: ImplicitGeneric { ImplicitGeneric() } + var anotherStringInt: ImplicitGeneric { ImplicitGeneric() } + func getAnotherString() -> ImplicitGeneric { + ImplicitGeneric() + } + func getAnotherStringInt() -> ImplicitGeneric { + ImplicitGeneric() + } +} + +func implicit(_ arg: ImplicitGeneric) {} + +implicit(.implicitInt) +implicit(.implicit.anotherInt) +implicit(.implicit.anotherInt.another) +implicit(.implicit.another.anotherInt) +implicit(.implicit.getAnotherInt()) +implicit(.implicit.another.getAnotherInt()) +implicit(.implicit.getAnother().anotherInt) +implicit(.implicit.getAnotherInt()) +implicit(.implicit.getAnother().getAnotherInt()) +implicit(.implicitString.anotherStringInt) +// Member types along the chain can have different generic arguments +implicit(.implicit.anotherIntString.anotherStringInt) + +implicit(.implicit.anotherString.anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.getAnotherString().anotherStringInt) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.anotherString.getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} +implicit(.implicit.getAnotherString().getAnotherStringInt()) // expected-error {{member chain produces result of type 'ImplicitGeneric' but contextual base was inferred as 'ImplicitGeneric'}} + +// Implicit member syntax can be used to apply curried instance methods: +struct Curried { + func method() -> Curried { Curried() } + func method(with arg: Int) -> Curried { Curried() } + func method(with arg1: Int, and arg2: String) -> Curried { Curried() } + func takesClosure(_: (Int) -> Void) -> Curried { Curried() } + func takesArgClosure(_: Int, _: (Int) -> Void) -> Curried { Curried() } + static func curried(_ _self: Curried) -> () -> Curried{ return { _self } } + static func curriedWithArgs(_ _self: Curried) -> (Int, String) -> Curried { return { _, _ in _self } } +} + +let _: Curried = .method(Curried())() +let _: Curried = .method(Curried())(with: 0) +let _: Curried = .method(Curried())(with: 0, and: "") +let _: Curried = .takesClosure(Curried())() { _ in } +let _: Curried = .takesArgClosure(Curried())(0) { _ in } +let _: Curried = .curried(Curried())() +let _: Curried = .curriedWithArgs(Curried())(0, "") + + +struct CurriedGeneric { + func create(_: U.Type) -> CurriedGeneric { return CurriedGeneric() } +} + +extension CurriedGeneric where T == Int { + func createInt() -> Self { + return self + } +} + +let _: CurriedGeneric = .createInt(CurriedGeneric())() +let _: CurriedGeneric = .create(CurriedGeneric())(Int.self) diff --git a/test/expr/delayed-ident/nested_type.swift b/test/expr/delayed-ident/nested_type.swift index da8a3fece6538..520d08c90dea9 100644 --- a/test/expr/delayed-ident/nested_type.swift +++ b/test/expr/delayed-ident/nested_type.swift @@ -4,12 +4,21 @@ class Base { class Derived : Base { init(x: Int) {} + class Sub: Derived { + init(y: Int) {} + } + typealias Ident = Derived + typealias Ident2 = Base } typealias Ident = Base } let _: Base = .Derived(x: 12) let _: Base = .Ident() +let _: Base = .Derived.Sub(y: 1) +let _: Base = .Derived.init(x: 3) +let _: Base = .Derived.Ident(x: 3) +let _: Base = .Derived.Ident2() // Typealias in protocol. protocol P { @@ -19,9 +28,19 @@ extension P { typealias Impl2 = ConcreteP } struct ConcreteP : P { + struct NestedP: P {} + typealias Same = ConcreteP } let _: P = .Impl1() let _: P = .Impl2() let _: ConcreteP = .Impl1() let _: ConcreteP = .Impl2() +let _: P = .Impl1.NestedP() +let _: P = .Impl2.NestedP() +let _: ConcreteP = .Impl1.Same() +let _: ConcreteP = .Impl2.Same() +let _: P = .Impl1.init() +let _: P = .Impl2.init() +let _: ConcreteP = .Impl1.init() +let _: ConcreteP = .Impl2.init() diff --git a/test/expr/delayed-ident/static_var.swift b/test/expr/delayed-ident/static_var.swift index cfe701754f791..3a01e7ff4137c 100644 --- a/test/expr/delayed-ident/static_var.swift +++ b/test/expr/delayed-ident/static_var.swift @@ -50,8 +50,7 @@ var _: HasClosure = .factoryOpt(3) // expected-error@-1 {{value of optional type '((Int) -> HasClosure)?' must be unwrapped to a value of type '(Int) -> HasClosure'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} -// FIXME: we should accept this -var _: HasClosure = .factoryOpt!(4) // expected-error {{cannot infer contextual base in reference to member 'factoryOpt'}} +var _: HasClosure = .factoryOpt!(4) infix operator =%: ComparisonPrecedence diff --git a/test/expr/postfix/dot/optional_context_member.swift b/test/expr/postfix/dot/optional_context_member.swift index b761c21657ab6..c3279781e40b0 100644 --- a/test/expr/postfix/dot/optional_context_member.swift +++ b/test/expr/postfix/dot/optional_context_member.swift @@ -27,9 +27,8 @@ func nonOptContext() -> Foo { // expected-error@-1 {{value of optional type 'Foo?' must be unwrapped to a value of type 'Foo'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} - // TODO - //case (): - // return .someOptFunc()! + case (): // expected-warning {{case is already handled by previous patterns; consider removing it}} + return .someOptFunc()! } } diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 9b0333b0c0de4..326e148b5b6a7 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -1006,9 +1006,12 @@ func testMemberAccessOnOptionalKeyPathComponent() { // expected-error@-1 {{value of optional type '(Int, Int)?' must be unwrapped to refer to member '0' of wrapped base type '(Int, Int)'}} // expected-note@-2 {{use unwrapped type '(Int, Int)' as key path root}}{{4-15=(Int, Int)}} - // TODO(diagnostics) Improve diagnostics refering to key path root not able to be infered as an optional type. - SR5688_KP(\.count) - // expected-error@-1 {{value of optional type 'String?' must be unwrapped to refer to member 'count' of wrapped base type 'String'}} + SR5688_KP(\.count) // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} + // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{15-15=?.}} + // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{15-15=!.}} + let _ : KeyPath = \.count // expected-error {{key path root inferred as optional type 'String?' must be unwrapped to refer to member 'count' of unwrapped type 'String'}} + // expected-note@-1 {{chain the optional using '?.' to access unwrapped type member 'count'}} {{37-37=?.}} + // expected-note@-2 {{unwrap the optional using '!.' to access unwrapped type member 'count'}} {{37-37=!.}} } func testSyntaxErrors() { diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 7aa13a7d6097d..7d245c5a28d0f 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -92,8 +92,8 @@ if "@SWIFT_AST_VERIFIER@" == "TRUE": if "@SWIFT_OPTIMIZED@" == "TRUE": config.available_features.add("optimized_stdlib") -if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE": - config.available_features.add("nonatomic_rc") +if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": + config.available_features.add("single_threaded_runtime") if "@SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS@" == "TRUE": config.available_features.add('runtime_function_counters') diff --git a/test/stdlib/Casts.swift b/test/stdlib/Casts.swift deleted file mode 100644 index 5e81f6643b154..0000000000000 --- a/test/stdlib/Casts.swift +++ /dev/null @@ -1,236 +0,0 @@ -// Casts.swift - Tests for conversion between types. -// -// 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 -// -// ----------------------------------------------------------------------------- -/// -/// Contains tests for conversions between types which shouldn't trap. -/// -// ----------------------------------------------------------------------------- -// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-concurrency) -// REQUIRES: executable_test -// UNSUPPORTED: use_os_stdlib - -import StdlibUnittest -#if _runtime(_ObjC) -import Foundation -#endif - -private func blackhole(_ t: T) {} - -let CastsTests = TestSuite("Casts") - -// Test for SR-426: missing release for some types after failed conversion -CastsTests.test("No leak for failed tuple casts") { - let t: Any = (1, LifetimeTracked(0)) - expectFalse(t is Any.Type) -} - -protocol P {} -class ErrClass : Error { } - -CastsTests.test("No overrelease of existential boxes in failed casts") { - // Test for crash from SR-392 - // We fail casts of an existential box repeatedly - // to ensure it does not get over-released. - func bar(_ t: T) { - for _ in 0..<10 { - if case let a as P = t { - _ = a - } - } - } - - let err: Error = ErrClass() - bar(err) -} - -extension Int : P {} - -// Test for SR-7664: Inconsistent optional casting behaviour with generics -// Runtime failed to unwrap multiple levels of Optional when casting. -CastsTests.test("Multi-level optionals can be casted") { - func testSuccess(_ x: From, from: From.Type, to: To.Type) { - expectNotNil(x as? To) - } - func testFailure(_ x: From, from: From.Type, to: To.Type) { - expectNil(x as? To) - } - testSuccess(42, from: Int?.self, to: Int.self) - testSuccess(42, from: Int??.self, to: Int.self) - testSuccess(42, from: Int???.self, to: Int.self) - testSuccess(42, from: Int???.self, to: Int?.self) - testSuccess(42, from: Int???.self, to: Int??.self) - testSuccess(42, from: Int???.self, to: Int???.self) - testFailure(42, from: Int?.self, to: String.self) - testFailure(42, from: Int??.self, to: String.self) - testFailure(42, from: Int???.self, to: String.self) -} - -// Test for SR-9837: Optional.none not casting to Optional.none in generic context -CastsTests.test("Optional.none can be casted to Optional.none in generic context") { - func test(_ type: T.Type) -> T? { - return Any?.none as? T - } - - expectEqual(type(of: test(Bool.self)), Bool?.self) - expectEqual(type(of: test(Bool?.self)), Bool??.self) -} - -// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject -#if _runtime(_ObjC) -protocol P2 {} -CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") { - if #available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { - struct S: P2 {} - - class ObjCWrapper { - @objc dynamic let any: Any = S() - init() {} - } - let a = ObjCWrapper().any - expectTrue(a is P2) - // In SR-3871, the following cast failed (everything else here succeeded) - expectNotNil(a as? P2) - expectNotNil(a as? S) - let b = a as AnyObject - expectTrue(a is P2) - expectNotNil(b as? P2) - expectNotNil(b as? S) - } -} -#endif - -protocol P3 {} -CastsTests.test("Cast from Swift existential to Protocol") { - struct S: P3 {} - class SwiftWrapper { - let any: Any = S() - init() {} - } - let a = SwiftWrapper().any - expectTrue(a is P3) - expectNotNil(a as? P3) - expectNotNil(a as? S) - let b = a as AnyObject - expectTrue(b is P3) - expectNotNil(b as? P3) - expectNotNil(b as? S) -} - - -#if _runtime(_ObjC) -extension CFBitVector : P { - static func makeImmutable(from values: Array) -> CFBitVector { - return CFBitVectorCreate(/*allocator:*/ nil, values, values.count * 8) - } -} - -extension CFMutableBitVector { - static func makeMutable(from values: Array) -> CFMutableBitVector { - return CFBitVectorCreateMutableCopy( - /*allocator:*/ nil, - /*capacity:*/ 0, - CFBitVector.makeImmutable(from: values)) - } -} - -func isP(_ t: T) -> Bool { - return t is P -} - -CastsTests.test("Dynamic casts of CF types to protocol existentials") - .skip(.custom( - { !_isDebugAssertConfiguration() }, - reason: "This test behaves unpredictably in optimized mode.")) - .code { - expectTrue(isP(10 as Int)) - - // FIXME: SR-2289: dynamic casting of CF types to protocol existentials - // should work, but there is a bug in the runtime that prevents them from - // working. - expectFailure { - expectTrue(isP(CFBitVector.makeImmutable(from: [10, 20]))) - } - expectFailure { - expectTrue(isP(CFMutableBitVector.makeMutable(from: [10, 20]))) - } -} -#endif - -CastsTests.test("Any.Protocol") { - class C {} - struct S {} - func isAnyProtocol(_ type: T.Type) -> Bool { - let result = T.self is Any.Protocol - if result { - // `as!` should succeed if `is` does - blackhole(T.self as! Any.Protocol) - } - return result - } - func isAnyType(_ type: T.Type) -> Bool { - return T.self is Any.Type - } - func isType(_ type: T.Type, to: U.Type) -> Bool { - return T.self is U.Type - } - - expectTrue(Int.self is Any.Type) - expectNotNil(Int.self as? Any.Type) - expectTrue(isAnyType(Int.self)) - expectFalse(Int.self is Any.Protocol) - expectNil(Int.self as? Any.Protocol) - expectFalse(isAnyProtocol(Int.self)) - expectFalse(isType(Int.self, to: Any.self)) - - expectTrue(C.self is Any.Type) - expectNotNil(C.self as? Any.Type) - expectTrue(isAnyType(C.self)) - expectFalse(C.self is Any.Protocol) - expectNil(C.self as? Any.Protocol) - expectFalse(isAnyProtocol(C.self)) - expectFalse(isType(C.self, to: Any.self)) - - expectTrue(S.self is Any.Type) - expectNotNil(S.self as? Any.Type) - expectTrue(isAnyType(S.self)) - expectFalse(S.self is Any.Protocol) - expectNil(S.self as? Any.Protocol) - expectFalse(isAnyProtocol(S.self)) - expectFalse(isType(S.self, to: Any.self)) - - expectTrue(Any.self is Any.Type) - expectNotNil(Any.self as? Any.Type) - expectTrue(isAnyType(Any.self)) - expectTrue(Any.self is Any.Protocol) - expectNotNil(Any.self as? Any.Protocol) - expectTrue(isAnyProtocol(Any.self)) - expectTrue(isType(Any.self, to: Any.self)) - - expectTrue(Any?.self is Any.Type) - expectNotNil(Any?.self as? Any.Type) - expectTrue(isAnyType(Any?.self)) - expectFalse(Any?.self is Any.Protocol) - expectNil(Any?.self as? Any.Protocol) - expectFalse(isAnyProtocol(Any?.self)) - expectFalse(isType(Any?.self, to: Any.self)) -} - -CastsTests.test("Async function types") { - let asyncFnType: Any.Type = (() async -> Void).self - let fnType: Any.Type = (() -> Void).self - - expectTrue(fnType is (() -> Void).Type) - expectTrue(asyncFnType is (() async -> Void).Type) - expectFalse(fnType is (() async -> Void).Type) - expectFalse(asyncFnType is (() -> Void).Type) -} - -runAllTests() diff --git a/test/stdlib/Reflection_jit.swift b/test/stdlib/Reflection_jit.swift index c36b6b6e8cc9f..8704ba6069ceb 100644 --- a/test/stdlib/Reflection_jit.swift +++ b/test/stdlib/Reflection_jit.swift @@ -2,3 +2,8 @@ // RUN: %target-jit-run -parse-stdlib %S/Reflection.swift -- %S/Inputs/shuffle.jpg | %FileCheck %S/Reflection.swift // REQUIRES: swift_interpreter + +// Only run this test when we build host tools (e.g. bin/swift-frontend), avoid running it for standalone stdlib builds. +// Standalone stdlib builds use downloadable toolchains from swift.org, which are codesigned in a way that doesn't let +// the interpreter process (swift-frontend) dynamically load locally-built modules (libswiftCore). +// REQUIRES: swift_tools_extra diff --git a/test/stdlib/symbol-visibility-linux.test-sh b/test/stdlib/symbol-visibility-linux.test-sh index 86a7a6dab377d..2472610c3e51b 100644 --- a/test/stdlib/symbol-visibility-linux.test-sh +++ b/test/stdlib/symbol-visibility-linux.test-sh @@ -31,6 +31,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftCore-all.txt @@ -55,6 +56,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \ // RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftRemoteMirror-all.txt diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift index b2594eb8f3398..93de7f6efabc8 100644 --- a/test/stmt/statements.swift +++ b/test/stmt/statements.swift @@ -280,7 +280,7 @@ func RepeatWhileStmt4() { func brokenSwitch(_ x: Int) -> Int { switch x { - case .Blah(var rep): // expected-error{{pattern cannot match values of type 'Int'}} + case .Blah(var rep): // expected-error{{type 'Int' has no member 'Blah'}} return rep } } diff --git a/tools/SourceKit/lib/Support/CMakeLists.txt b/tools/SourceKit/lib/Support/CMakeLists.txt index 901720a521069..3b18cc18e98c9 100644 --- a/tools/SourceKit/lib/Support/CMakeLists.txt +++ b/tools/SourceKit/lib/Support/CMakeLists.txt @@ -1,6 +1,5 @@ add_sourcekit_library(SourceKitSupport Concurrency-libdispatch.cpp - FuzzyStringMatcher.cpp Logging.cpp ImmutableTextBuffer.cpp ThreadSafeRefCntPtr.cpp diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h index 266282ab3f15b..f8098fbaf8390 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h @@ -132,12 +132,6 @@ class CompletionBuilder { Optional moduleImportDepth; PopularityFactor popularityFactor; -public: - static void getFilterName(CodeCompletionString *str, raw_ostream &OS); - static void getDescription(SwiftResult *result, raw_ostream &OS, - bool leadingPunctuation, - bool annotatedDecription = false); - public: CompletionBuilder(CompletionSink &sink, SwiftResult &base); diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 8ac901da4de3c..c24e17a0e1afd 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "CodeCompletionOrganizer.h" -#include "SourceKit/Support/FuzzyStringMatcher.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/IDE/CodeCompletionResultPrinter.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "swift/Frontend/Frontend.h" #include "swift/Markup/XMLUtils.h" #include "clang/Basic/CharInfo.h" @@ -1209,72 +1209,6 @@ bool LimitedResultView::walk(CodeCompletionView::Walker &walker) const { // CompletionBuilder //===----------------------------------------------------------------------===// -void CompletionBuilder::getFilterName(CodeCompletionString *str, - raw_ostream &OS) { - using ChunkKind = CodeCompletionString::Chunk::ChunkKind; - - // FIXME: we need a more uniform way to handle operator completions. - if (str->getChunks().size() == 1 && str->getChunks()[0].is(ChunkKind::Dot)) { - OS << "."; - return; - } else if (str->getChunks().size() == 2 && - str->getChunks()[0].is(ChunkKind::QuestionMark) && - str->getChunks()[1].is(ChunkKind::Dot)) { - OS << "?."; - return; - } - - auto FirstTextChunk = str->getFirstTextChunkIndex(); - if (FirstTextChunk.hasValue()) { - auto chunks = str->getChunks().slice(*FirstTextChunk); - for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) { - auto &C = *i; - - if (C.is(ChunkKind::BraceStmtWithCursor)) - break; // Don't include brace-stmt in filter name. - - if (C.is(ChunkKind::Equal)) { - OS << C.getText(); - break; - } - - bool shouldPrint = !C.isAnnotation(); - switch (C.getKind()) { - case ChunkKind::TypeAnnotation: - case ChunkKind::CallParameterInternalName: - case ChunkKind::CallParameterClosureType: - case ChunkKind::CallParameterClosureExpr: - case ChunkKind::CallParameterType: - case ChunkKind::DeclAttrParamColon: - case ChunkKind::Comma: - case ChunkKind::Whitespace: - case ChunkKind::Ellipsis: - case ChunkKind::Ampersand: - case ChunkKind::OptionalMethodCallTail: - continue; - case ChunkKind::CallParameterTypeBegin: - case ChunkKind::TypeAnnotationBegin: { - // Skip call parameter type or type annotation structure. - auto nestingLevel = C.getNestingLevel(); - do { ++i; } while (i != e && !i->endsPreviousNestedGroup(nestingLevel)); - --i; - continue; - } - case ChunkKind::CallParameterColon: - // Since we don't add the type, also don't add the space after ':'. - if (shouldPrint) - OS << ":"; - continue; - default: - break; - } - - if (C.hasText() && shouldPrint) - OS << C.getText(); - } - } -} - CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base) : sink(sink), current(base) { typeRelation = current.getExpectedTypeRelation(); @@ -1286,7 +1220,7 @@ CompletionBuilder::CompletionBuilder(CompletionSink &sink, SwiftResult &base) // strings for our inner "." result. if (current.getCompletionString()->getFirstTextChunkIndex().hasValue()) { llvm::raw_svector_ostream OSS(originalName); - getFilterName(current.getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(current, OSS); } } @@ -1336,7 +1270,7 @@ Completion *CompletionBuilder::finish() { } llvm::raw_svector_ostream OSS(nameStorage); - getFilterName(base.getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(base, OSS); name = OSS.str(); } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 69f9da9c58b02..81fa025b8704e 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -40,36 +40,6 @@ using namespace SourceKit; using namespace swift; using namespace swift::sys; -namespace { -class StreamDiagConsumer : public DiagnosticConsumer { - llvm::raw_ostream &OS; - -public: - StreamDiagConsumer(llvm::raw_ostream &OS) : OS(OS) {} - - void handleDiagnostic(SourceManager &SM, - const DiagnosticInfo &Info) override { - // FIXME: Print location info if available. - switch (Info.Kind) { - case DiagnosticKind::Error: - OS << "error: "; - break; - case DiagnosticKind::Warning: - OS << "warning: "; - break; - case DiagnosticKind::Note: - OS << "note: "; - break; - case DiagnosticKind::Remark: - OS << "remark: "; - break; - } - DiagnosticEngine::formatDiagnosticText(OS, Info.FormatString, - Info.FormatArgs); - } -}; -} // end anonymous namespace - void SwiftASTConsumer::failed(StringRef Error) { } //===----------------------------------------------------------------------===// @@ -445,46 +415,6 @@ convertFileContentsToInputs(const SmallVectorImpl &contents) { return inputsAndOutputs; } -static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( - FrontendInputsAndOutputs &inputsAndOutputs, StringRef UnresolvedPrimaryFile, - llvm::IntrusiveRefCntPtr FileSystem, - std::string &Error) { - assert(FileSystem); - - llvm::SmallString<128> PrimaryFile; - if (auto err = FileSystem->getRealPath(UnresolvedPrimaryFile, PrimaryFile)) - PrimaryFile = UnresolvedPrimaryFile; - - unsigned primaryCount = 0; - // FIXME: The frontend should be dealing with symlinks, maybe similar to - // clang's FileManager ? - FrontendInputsAndOutputs replacementInputsAndOutputs; - for (const InputFile &input : inputsAndOutputs.getAllInputs()) { - llvm::SmallString<128> newFilename; - if (auto err = FileSystem->getRealPath(input.file(), newFilename)) - newFilename = input.file(); - llvm::sys::path::native(newFilename); - bool newIsPrimary = input.isPrimary() || - (!PrimaryFile.empty() && PrimaryFile == newFilename); - if (newIsPrimary) { - ++primaryCount; - } - assert(primaryCount < 2 && "cannot handle multiple primaries"); - replacementInputsAndOutputs.addInput( - InputFile(newFilename.str(), newIsPrimary, input.buffer())); - } - - if (PrimaryFile.empty() || primaryCount == 1) { - return replacementInputsAndOutputs; - } - - llvm::SmallString<64> Err; - llvm::raw_svector_ostream OS(Err); - OS << "'" << PrimaryFile << "' is not part of the input files"; - Error = std::string(OS.str()); - return replacementInputsAndOutputs; -} - bool SwiftASTManager::initCompilerInvocation( CompilerInvocation &Invocation, ArrayRef OrigArgs, DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, @@ -500,104 +430,13 @@ bool SwiftASTManager::initCompilerInvocation( DiagnosticEngine &Diags, StringRef UnresolvedPrimaryFile, llvm::IntrusiveRefCntPtr FileSystem, std::string &Error) { - SmallVector Args; - // Make sure to put '-resource-dir' and '-diagnostic-documentation-path' at - // the top to allow overriding them with the passed in arguments. - Args.push_back("-resource-dir"); - Args.push_back(Impl.RuntimeResourcePath.c_str()); - Args.push_back("-Xfrontend"); - Args.push_back("-diagnostic-documentation-path"); - Args.push_back("-Xfrontend"); - Args.push_back(Impl.DiagnosticDocumentationPath.c_str()); - Args.append(OrigArgs.begin(), OrigArgs.end()); - - SmallString<32> ErrStr; - llvm::raw_svector_ostream ErrOS(ErrStr); - StreamDiagConsumer DiagConsumer(ErrOS); - Diags.addConsumer(DiagConsumer); - - bool HadError = driver::getSingleFrontendInvocationFromDriverArguments( - Args, Diags, [&](ArrayRef FrontendArgs) { - return Invocation.parseArgs(FrontendArgs, Diags); - }, /*ForceNoOutputs=*/true); - - // Remove the StreamDiagConsumer as it's no longer needed. - Diags.removeConsumer(DiagConsumer); - - if (HadError) { - Error = std::string(ErrOS.str()); - return true; - } - - Invocation.getFrontendOptions().InputsAndOutputs = - resolveSymbolicLinksInInputs( - Invocation.getFrontendOptions().InputsAndOutputs, - UnresolvedPrimaryFile, FileSystem, Error); - if (!Error.empty()) - return true; - - ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions(); - ImporterOpts.DetailedPreprocessingRecord = true; - - // SWIFT_ENABLE_TENSORFLOW - ImporterOpts.InMemoryOutputFileSystem = Impl.InMemoryOutputFileSystem; - - assert(!Invocation.getModuleName().empty()); - - auto &LangOpts = Invocation.getLangOptions(); - LangOpts.AttachCommentsToDecls = true; - LangOpts.DiagnosticsEditorMode = true; - LangOpts.CollectParsedToken = true; - if (LangOpts.PlaygroundTransform) { - // The playground instrumenter changes the AST in ways that disrupt the - // SourceKit functionality. Since we don't need the instrumenter, and all we - // actually need is the playground semantics visible to the user, like - // silencing the "expression resolves to an unused l-value" error, disable it. - LangOpts.PlaygroundTransform = false; - } - - // Disable the index-store functionality for the sourcekitd requests. - auto &FrontendOpts = Invocation.getFrontendOptions(); - FrontendOpts.IndexStorePath.clear(); - ImporterOpts.IndexStorePath.clear(); - - // Force the action type to be -typecheck. This affects importing the - // SwiftONoneSupport module. - FrontendOpts.RequestedAction = FrontendOptions::ActionType::Typecheck; - - // We don't care about LLVMArgs - FrontendOpts.LLVMArgs.clear(); - - // SwiftSourceInfo files provide source location information for decls coming - // from loaded modules. For most IDE use cases it either has an undesirable - // impact on performance with no benefit (code completion), results in stale - // locations being used instead of more up-to-date indexer locations (cursor - // info), or has no observable effect (diagnostics, which are filtered to just - // those with a location in the primary file, and everything else). - if (Impl.Config->shouldOptimizeForIDE()) - FrontendOpts.IgnoreSwiftSourceInfo = true; - - // To save the time for module validation, consider the lifetime of ASTManager - // as a single build session. - // NOTE: Do this only if '-disable-modules-validate-system-headers' is *not* - // explicitly enabled. - auto &SearchPathOpts = Invocation.getSearchPathOptions(); - if (!SearchPathOpts.DisableModulesValidateSystemDependencies) { - // NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may - // cause unnecessary validations if they happens within one second - // from the SourceKit startup. - ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" + - std::to_string(Impl.SessionTimestamp - 1)); - ImporterOpts.ExtraArgs.push_back( - "-fmodules-validate-once-per-build-session"); - - SearchPathOpts.DisableModulesValidateSystemDependencies = true; - } - - // Disable expensive SIL options to reduce time spent in SILGen. - disableExpensiveSILOptions(Invocation.getSILOptions()); - - return false; + return ide::initCompilerInvocation( + Invocation, OrigArgs, Diags, UnresolvedPrimaryFile, FileSystem, + // SWIFT_ENABLE_TENSORFLOW + Impl.InMemoryOutputFileSystem, + // SWIFT_ENABLE_TENSORFLOW END + Impl.RuntimeResourcePath, Impl.DiagnosticDocumentationPath, + Impl.Config->shouldOptimizeForIDE(), Impl.SessionTimestamp, Error); } bool SwiftASTManager::initCompilerInvocation(CompilerInvocation &CompInvok, diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 0870461fede85..06d3a912d4b51 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -49,8 +49,7 @@ struct SwiftToSourceKitCompletionAdapter { llvm::SmallString<64> name; { llvm::raw_svector_ostream OSS(name); - CodeCompletion::CompletionBuilder::getFilterName( - result->getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(*result, OSS); } llvm::SmallString<64> description; @@ -75,9 +74,6 @@ struct SwiftToSourceKitCompletionAdapter { bool legacyLiteralToKeyword, bool annotatedDescription); - static void getResultSourceText(const CodeCompletionString *CCStr, - raw_ostream &OS); - static void getResultAssociatedUSRs(ArrayRef AssocUSRs, raw_ostream &OS); }; @@ -466,7 +462,7 @@ bool SwiftToSourceKitCompletionAdapter::handleResult( unsigned TextBegin = SS.size(); { llvm::raw_svector_ostream ccOS(SS); - getResultSourceText(Result->getCompletionString(), ccOS); + ide::printCodeCompletionResultSourceText(*Result, ccOS); } unsigned TextEnd = SS.size(); @@ -603,121 +599,6 @@ getCodeCompletionKeywordKindForUID(UIdent uid) { return CodeCompletionKeywordKind::None; } -using ChunkKind = CodeCompletionString::Chunk::ChunkKind; - -/// Provide the text for the call parameter, including constructing a typed -/// editor placeholder for it. -static void constructTextForCallParam( - ArrayRef ParamGroup, raw_ostream &OS) { - assert(ParamGroup.front().is(ChunkKind::CallParameterBegin)); - - for (; !ParamGroup.empty(); ParamGroup = ParamGroup.slice(1)) { - auto &C = ParamGroup.front(); - if (C.isAnnotation()) - continue; - if (C.is(ChunkKind::CallParameterInternalName) || - C.is(ChunkKind::CallParameterType) || - C.is(ChunkKind::CallParameterTypeBegin) || - C.is(ChunkKind::CallParameterClosureExpr)) { - break; - } - if (!C.hasText()) - continue; - OS << C.getText(); - } - - SmallString<32> DisplayString; - SmallString<32> TypeString; - SmallString<32> ExpansionTypeString; - - for (auto i = ParamGroup.begin(), e = ParamGroup.end(); i != e; ++i) { - auto &C = *i; - if (C.is(ChunkKind::CallParameterTypeBegin)) { - assert(TypeString.empty()); - auto nestingLevel = C.getNestingLevel(); - ++i; - for (; i != e; ++i) { - if (i->endsPreviousNestedGroup(nestingLevel)) - break; - if (!i->isAnnotation() && i->hasText()) { - TypeString += i->getText(); - DisplayString += i->getText(); - } - } - --i; - continue; - } - if (C.is(ChunkKind::CallParameterClosureType)) { - assert(ExpansionTypeString.empty()); - ExpansionTypeString = C.getText(); - continue; - } - if (C.is(ChunkKind::CallParameterType)) { - assert(TypeString.empty()); - TypeString = C.getText(); - } - if (C.is(ChunkKind::CallParameterClosureExpr)) { - // We have a closure expression, so provide it directly instead of in - // a placeholder. - OS << "{"; - if (!C.getText().empty()) - OS << " " << C.getText(); - OS << "\n" << getCodePlaceholder() << "\n}"; - return; - } - if (C.isAnnotation() || !C.hasText()) - continue; - DisplayString += C.getText(); - } - - StringRef Display = DisplayString.str(); - StringRef Type = TypeString.str(); - StringRef ExpansionType = ExpansionTypeString.str(); - if (ExpansionType.empty()) - ExpansionType = Type; - - OS << "<#T##" << Display; - if (Display == Type && Display == ExpansionType) { - // Short version, display and type are the same. - } else { - OS << "##" << Type; - if (ExpansionType != Type) - OS << "##" << ExpansionType; - } - OS << "#>"; -} - -void SwiftToSourceKitCompletionAdapter::getResultSourceText( - const CodeCompletionString *CCStr, raw_ostream &OS) { - auto Chunks = CCStr->getChunks(); - for (size_t i = 0; i < Chunks.size(); ++i) { - auto &C = Chunks[i]; - if (C.is(ChunkKind::BraceStmtWithCursor)) { - OS << " {\n" << getCodePlaceholder() << "\n}"; - continue; - } - if (C.is(ChunkKind::CallParameterBegin)) { - size_t Start = i++; - for (; i < Chunks.size(); ++i) { - if (Chunks[i].endsPreviousNestedGroup(C.getNestingLevel())) - break; - } - constructTextForCallParam(Chunks.slice(Start, i-Start), OS); - --i; - continue; - } - if (C.is(ChunkKind::TypeAnnotationBegin)) { - // Skip type annotation structure. - auto level = C.getNestingLevel(); - do { ++i; } while (i != Chunks.size() && !Chunks[i].endsPreviousNestedGroup(level)); - --i; - } - if (!C.isAnnotation() && C.hasText()) { - OS << C.getText(); - } - } -} - void SwiftToSourceKitCompletionAdapter::getResultAssociatedUSRs( ArrayRef AssocUSRs, raw_ostream &OS) { bool First = true; @@ -1005,8 +886,7 @@ filterInnerResults(ArrayRef results, bool includeInner, llvm::SmallString<64> filterName; { llvm::raw_svector_ostream OSS(filterName); - CodeCompletion::CompletionBuilder::getFilterName( - result->getCompletionString(), OSS); + ide::printCodeCompletionResultFilterName(*result, OSS); } llvm::SmallString<64> description; { @@ -1140,8 +1020,7 @@ static void transformAndForwardResults( std::string str = inputBuf->getBuffer().slice(0, offset).str(); { llvm::raw_string_ostream OSS(str); - SwiftToSourceKitCompletionAdapter::getResultSourceText( - exactMatch->getCompletionString(), OSS); + ide::printCodeCompletionResultSourceText(*exactMatch, OSS); } auto buffer = diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp index 6b0fe110a774c..d77474f197d5c 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp @@ -1601,9 +1601,6 @@ class PlaceholderExpansionScanner { if (auto *CE = dyn_cast(E)) { // Call expression can have argument. Arg = CE->getArg(); - } else if (auto UME = dyn_cast(E)) { - // Unresolved member can have argument too. - Arg = UME->getArgument(); } if (!Arg) return false; diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index 9e91584e84659..813a7bd843097 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -1603,6 +1603,11 @@ SDKContext::shouldIgnore(Decl *D, const Decl* Parent) const { if (isa(VD)) return true; } + // Exclude decls with @_alwaysEmitIntoClient if we are checking ABI. + // These decls are considered effectively public because they are usable + // from inline, so we have to manually exclude them here. + if (D->getAttrs().hasAttribute()) + return true; } else { if (D->isPrivateStdlibDecl(false)) return true; diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 2b089bf718c5f..ed3c61d7623c9 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -72,7 +72,7 @@ ModuleList("module-list-file", llvm::cl::cat(Category)); static llvm::cl::opt -ProtReqWhiteList("protocol-requirement-white-list", +ProtReqAllowList("protocol-requirement-allow-list", llvm::cl::desc("File containing a new-line separated list of protocol names"), llvm::cl::cat(Category)); @@ -1057,6 +1057,17 @@ void swift::ide::api::SDKNodeTypeFunc::diagnose(SDKNode *Right) { } namespace { +static void diagnoseRemovedDecl(const SDKNodeDecl *D) { + if (D->getSDKContext().checkingABI()) { + // Don't complain about removing @_alwaysEmitIntoClient if we are checking ABI. + // We shouldn't include these decls in the ABI baseline file. This line is + // added so the checker is backward compatible. + if (D->hasDeclAttribute(DeclAttrKind::DAK_AlwaysEmitIntoClient)) + return; + } + D->emitDiag(SourceLoc(), diag::removed_decl, D->isDeprecated()); +} + // This is first pass on two given SDKNode trees. This pass removes the common part // of two versions of SDK, leaving only the changed part. class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { @@ -1074,7 +1085,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { SDKContext &Ctx; UpdatedNodesMap &UpdateMap; - llvm::StringSet<> ProtocolReqWhitelist; + llvm::StringSet<> ProtocolReqAllowlist; SDKNodeRoot *LeftRoot; SDKNodeRoot *RightRoot; @@ -1123,10 +1134,10 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { public: PrunePass(SDKContext &Ctx): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()) {} - PrunePass(SDKContext &Ctx, llvm::StringSet<> prWhitelist): + PrunePass(SDKContext &Ctx, llvm::StringSet<> prAllowlist): Ctx(Ctx), UpdateMap(Ctx.getNodeUpdateMap()), - ProtocolReqWhitelist(std::move(prWhitelist)) {} + ProtocolReqAllowlist(std::move(prAllowlist)) {} void diagnoseMissingAvailable(SDKNodeDecl *D) { // For extensions of external types, we diagnose individual member's missing @@ -1178,7 +1189,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { ShouldComplain = false; } if (ShouldComplain && - ProtocolReqWhitelist.count(getParentProtocolName(D))) { + ProtocolReqAllowlist.count(getParentProtocolName(D))) { // Ignore protocol requirement additions if the protocol has been added // to the allowlist. ShouldComplain = false; @@ -1241,7 +1252,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { TD->isProtocol()); } if (auto *Acc = dyn_cast(Left)) { - Acc->emitDiag(SourceLoc(), diag::removed_decl, Acc->isDeprecated()); + diagnoseRemovedDecl(Acc); } return; case NodeMatchReason::FuncToProperty: @@ -2084,7 +2095,7 @@ static bool diagnoseRemovedExtensionMembers(const SDKNode *Node) { if (DT->isExtension()) { for (auto *C: DT->getChildren()) { auto *MD = cast(C); - MD->emitDiag(SourceLoc(), diag::removed_decl, MD->isDeprecated()); + diagnoseRemovedDecl(MD); } return true; } @@ -2161,7 +2172,7 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) { } bool handled = diagnoseRemovedExtensionMembers(Node); if (!handled) - Node->emitDiag(SourceLoc(), diag::removed_decl, Node->isDeprecated()); + diagnoseRemovedDecl(Node); return; } case NodeAnnotation::Rename: { @@ -2311,7 +2322,7 @@ createDiagConsumer(llvm::raw_ostream &OS, bool &FailOnError) { static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, SDKNodeRoot *RightModule, StringRef OutputPath, - llvm::StringSet<> ProtocolReqWhitelist) { + llvm::StringSet<> ProtocolReqAllowlist) { assert(LeftModule); assert(RightModule); llvm::raw_ostream *OS = &llvm::errs(); @@ -2334,7 +2345,7 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, RightModule->getJsonFormatVersion())); TypeAliasDiffFinder(LeftModule, RightModule, Ctx.getTypeAliasUpdateMap()).search(); - PrunePass Prune(Ctx, std::move(ProtocolReqWhitelist)); + PrunePass Prune(Ctx, std::move(ProtocolReqAllowlist)); Prune.pass(LeftModule, RightModule); ChangeRefinementPass RefinementPass(Ctx.getNodeUpdateMap()); RefinementPass.pass(LeftModule, RightModule); @@ -2347,7 +2358,7 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule, static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, StringRef OutputPath, CheckerOptions Opts, - llvm::StringSet<> ProtocolReqWhitelist) { + llvm::StringSet<> ProtocolReqAllowlist) { if (!fs::exists(LeftPath)) { llvm::errs() << LeftPath << " does not exist\n"; return 1; @@ -2362,7 +2373,7 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath, SwiftDeclCollector RightCollector(Ctx); RightCollector.deSerialize(RightPath); diagnoseModuleChange(Ctx, LeftCollector.getSDKRoot(), RightCollector.getSDKRoot(), - OutputPath, std::move(ProtocolReqWhitelist)); + OutputPath, std::move(ProtocolReqAllowlist)); return options::CompilerStyleDiags && Ctx.getDiags().hadAnyError() ? 1 : 0; } @@ -2837,9 +2848,9 @@ int main(int argc, char *argv[]) { case ActionType::MigratorGen: case ActionType::DiagnoseSDKs: { ComparisonInputMode Mode = checkComparisonInputMode(); - llvm::StringSet<> protocolWhitelist; - if (!options::ProtReqWhiteList.empty()) { - if (readFileLineByLine(options::ProtReqWhiteList, protocolWhitelist)) + llvm::StringSet<> protocolAllowlist; + if (!options::ProtReqAllowList.empty()) { + if (readFileLineByLine(options::ProtReqAllowList, protocolAllowlist)) return 1; } if (options::Action == ActionType::MigratorGen) { @@ -2853,21 +2864,21 @@ int main(int argc, char *argv[]) { return diagnoseModuleChange(options::SDKJsonPaths[0], options::SDKJsonPaths[1], options::OutputFile, Opts, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } case ComparisonInputMode::BaselineJson: { SDKContext Ctx(Opts); return diagnoseModuleChange(Ctx, getBaselineFromJson(argv[0], Ctx), getSDKRoot(argv[0], Ctx, false), options::OutputFile, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } case ComparisonInputMode::BothLoad: { SDKContext Ctx(Opts); return diagnoseModuleChange(Ctx, getSDKRoot(argv[0], Ctx, true), getSDKRoot(argv[0], Ctx, false), options::OutputFile, - std::move(protocolWhitelist)); + std::move(protocolAllowlist)); } } } diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index c06ec35de5f81..8846f4452e855 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -668,12 +668,15 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, Demangle::Demangler Dem; auto Demangled = Dem.demangleType(Line); - auto *TypeRef = - swift::Demangle::decodeMangledType(builder, Demangled); - if (TypeRef == nullptr) { - fprintf(file, "Invalid typeref:%s\n", Line.c_str()); + auto Result = swift::Demangle::decodeMangledType(builder, Demangled); + if (Result.isError()) { + auto *error = Result.getError(); + char *str = error->copyErrorString(); + fprintf(file, "Invalid typeref:%s - %s\n", Line.c_str(), str); + error->freeErrorString(str); continue; } + auto TypeRef = Result.getType(); TypeRef->dump(file); auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef); diff --git a/unittests/ClangImporter/ClangImporterTests.cpp b/unittests/ClangImporter/ClangImporterTests.cpp index 4068678fd8433..e353fba57745f 100644 --- a/unittests/ClangImporter/ClangImporterTests.cpp +++ b/unittests/ClangImporter/ClangImporterTests.cpp @@ -6,10 +6,6 @@ #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangImporterOptions.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/FileSystemOptions.h" -#include "clang/Basic/FileSystemStatCache.h" -#include "clang/Frontend/CompilerInstance.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -58,6 +54,7 @@ TEST(ClangImporterTest, emitPCHInMemory) { // Create the includes. std::string include = createFilename(temp, "include"); ASSERT_FALSE(llvm::sys::fs::create_directory(include)); + options.ExtraArgs.emplace_back("-nosysteminc"); options.ExtraArgs.emplace_back((llvm::Twine("-I") + include).str()); ASSERT_FALSE(emitFileWithContents(include, "module.modulemap", "module A {\n" @@ -91,105 +88,3 @@ TEST(ClangImporterTest, emitPCHInMemory) { ASSERT_FALSE(emitFileWithContents(PCH, "garbage")); ASSERT_TRUE(importer->canReadPCH(PCH)); } - -class ForgetfulStatCache : public clang::FileSystemStatCache { -private: - std::unique_ptr RealStatCache; - -public: - ForgetfulStatCache() { - RealStatCache = std::make_unique(); - } - ~ForgetfulStatCache() = default; - - std::error_code getStat(StringRef Path, llvm::vfs::Status &Status, - bool isFile, - std::unique_ptr *F, - llvm::vfs::FileSystem &FS) override { - if (llvm::sys::path::extension(Path) == ".pcm") { - const auto UID = llvm::sys::fs::UniqueID(1, std::numeric_limits::max()); - Status = llvm::vfs::Status(Path, UID, - /*MTime*/{}, /*User*/0, /*Group*/0, - /*Size*/0, - llvm::sys::fs::file_type::regular_file, - llvm::sys::fs::perms::all_all); - return std::error_code(); - } - - return clang::FileSystemStatCache::get(Path, Status, isFile, F, - RealStatCache.get(), FS); - } -}; - -TEST(ClangImporterTest, missingSubmodule) { - // Create a temporary cache on disk and clean it up at the end. - ClangImporterOptions options; - SmallString<256> temp; - ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory( - "ClangImporterTest.missingSubmodule", temp)); - SWIFT_DEFER { llvm::sys::fs::remove_directories(temp); }; - - // Create a cache subdirectory for the modules and PCH. - std::string cache = createFilename(temp, "cache"); - ASSERT_FALSE(llvm::sys::fs::create_directory(cache)); - options.ModuleCachePath = cache; - options.PrecompiledHeaderOutputDir = cache; - - // Create the includes. - std::string include1 = createFilename(temp, "include1"); - ASSERT_FALSE(llvm::sys::fs::create_directory(include1)); - - std::string include2 = createFilename(temp, "include2"); - ASSERT_FALSE(llvm::sys::fs::create_directory(include2)); - - options.ExtraArgs.emplace_back((llvm::Twine("-I") + include1).str()); - options.ExtraArgs.emplace_back((llvm::Twine("-I") + include2).str()); - options.ExtraArgs.emplace_back("-DEXTRA_C_DEFINE=2"); - - ASSERT_FALSE(emitFileWithContents(include1, "module.modulemap", - "module CLib1 {\n" - " umbrella header \"" + include1 + "/Clib1.h\"\n" - " export * \n" - "}\n" - "module CLib2 {\n" - " umbrella header \"" + include2 + "/Clib2.h\"\n" - " export * \n" - "}\n")); - ASSERT_FALSE(emitFileWithContents(include1, "CLib1.h", - "#if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2\n" - "#error \"unexpected compiler flags\"\n" - "#endif\n" - "void foo(void);\n")); - ASSERT_FALSE(emitFileWithContents(include2, "CLib2.h", - "#if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2\n" - "#error \"unexpected compiler flags\"\n" - "#endif\n" - "void foo(void);\n")); - - // Set up the importer. - swift::LangOptions langOpts; - langOpts.Target = llvm::Triple("x86_64", "apple", "darwin"); - swift::TypeCheckerOptions typeckOpts; - INITIALIZE_LLVM(); - swift::SearchPathOptions searchPathOpts; - swift::SourceManager sourceMgr; - swift::DiagnosticEngine diags(sourceMgr); - std::unique_ptr context( - ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags)); - auto importer = ClangImporter::create(*context, options); - - // Install a stats cache that conveniently "forgets" that PCMs have different - // underlying FileEntry values. - importer->getClangInstance() - .getFileManager() - .setStatCache(std::make_unique()); - - context->addModuleLoader(std::move(importer)); - - auto CLib1 = context->getIdentifier("CLib1"); - auto CLib2 = context->getIdentifier("CLib2"); - // The first load succeeds and primes the ModuleManager with PCM data. - (void)context->getModule({ Located{ CLib1, {} } }); - // The second load fails because we collide in the ModuleManager. - ASSERT_TRUE(context->getModule({ Located{ CLib2, {} } }) == nullptr); -} diff --git a/unittests/IDE/CMakeLists.txt b/unittests/IDE/CMakeLists.txt index f55846dd2c6ad..607a574214a71 100644 --- a/unittests/IDE/CMakeLists.txt +++ b/unittests/IDE/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_unittest(SwiftIDETests CodeCompletionToken.cpp + FuzzyStringMatcherTest.cpp Placeholders.cpp ) target_link_libraries(SwiftIDETests diff --git a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp b/unittests/IDE/FuzzyStringMatcherTest.cpp similarity index 99% rename from unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp rename to unittests/IDE/FuzzyStringMatcherTest.cpp index e0e7e83b4220c..e190933fcd988 100644 --- a/unittests/SourceKit/Support/FuzzyStringMatcherTest.cpp +++ b/unittests/IDE/FuzzyStringMatcherTest.cpp @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "SourceKit/Support/FuzzyStringMatcher.h" +#include "swift/IDE/FuzzyStringMatcher.h" #include "gtest/gtest.h" -using FuzzyStringMatcher = SourceKit::FuzzyStringMatcher; +using FuzzyStringMatcher = swift::ide::FuzzyStringMatcher; TEST(FuzzyStringMatcher, BasicMatching) { { diff --git a/unittests/SourceKit/Support/CMakeLists.txt b/unittests/SourceKit/Support/CMakeLists.txt index da17a059b87b3..54cbdce081c87 100644 --- a/unittests/SourceKit/Support/CMakeLists.txt +++ b/unittests/SourceKit/Support/CMakeLists.txt @@ -1,5 +1,4 @@ add_swift_unittest(SourceKitSupportTests - FuzzyStringMatcherTest.cpp ImmutableTextBufferTest.cpp ) diff --git a/unittests/runtime/CompatibilityOverride.cpp b/unittests/runtime/CompatibilityOverride.cpp index 80a9b086980b9..6056f26117930 100644 --- a/unittests/runtime/CompatibilityOverride.cpp +++ b/unittests/runtime/CompatibilityOverride.cpp @@ -35,8 +35,8 @@ namespace { return MetadataResponse{nullptr, MetadataState::Complete}; } - template<> - TypeInfo getEmptyValue() { + template <> + TypeLookupErrorOr getEmptyValue>() { return TypeInfo(); } } @@ -172,13 +172,13 @@ TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledNode) { Demangler demangler; auto Result = swift_getTypeByMangledNode(MetadataState::Abstract, demangler, nullptr, nullptr, nullptr,nullptr); - ASSERT_EQ(Result.getMetadata(), nullptr); + ASSERT_EQ(Result.getType().getMetadata(), nullptr); } TEST_F(CompatibilityOverrideTest, test_swift_getTypeByMangledName) { auto Result = swift_getTypeByMangledName(MetadataState::Abstract, "", nullptr, nullptr, nullptr); - ASSERT_EQ(Result.getMetadata(), nullptr); + ASSERT_EQ(Result.getType().getMetadata(), nullptr); } TEST_F(CompatibilityOverrideTest, test_swift_getAssociatedTypeWitnessSlow) { diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 21381b23729b1..253ed30b79dba 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -212,21 +212,6 @@ skip-test-ios-simulator skip-test-tvos-simulator skip-test-watchos-simulator -[preset: buildbot,tools=RA,stdlib=RD,single-thread] -mixin-preset= - mixin_buildbot_tools_RA_stdlib_RD - -dash-dash - -# Enable non-atomic build of the stdlib -swift-stdlib-use-nonatomic-rc=true - -# Don't run host tests for iOS, tvOS and watchOS platforms to make the build -# faster. -skip-test-ios-host -skip-test-tvos-host -skip-test-watchos-host - [preset: buildbot,tools=R,stdlib=RD] mixin-preset= mixin_buildbot_tools_R_stdlib_RD @@ -1328,6 +1313,8 @@ dash-dash no-assertions +# SKIP LLDB TESTS (67923799) +skip-test-lldb [preset: buildbot_osx_package,no_assertions,lto] mixin-preset=buildbot_osx_package,no_assertions diff --git a/utils/build-script-impl b/utils/build-script-impl index 22bdafcb8cb02..0f2010108fb0c 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -186,7 +186,6 @@ KNOWN_SETTINGS=( swift-primary-variant-sdk "" "default SDK for target binaries" swift-runtime-enable-leak-checker "0" "Enable leaks checking routines in the runtime" swift-stdlib-enable-assertions "1" "enable assertions in Swift" - swift-stdlib-use-nonatomic-rc "0" "build the Swift stdlib and overlays with nonatomic reference count operations enabled" swift-tools-enable-lto "" "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime. Must be set to one of 'thin' or 'full'" extra-swift-args "" "Extra arguments to pass to swift modules which match regex. Assumed to be a flattened cmake list consisting of [module_regexp, args, module_regexp, args, ...]" report-statistics "0" "set to 1 to generate compilation statistics files for swift libraries" @@ -1410,6 +1409,13 @@ for host in "${ALL_HOSTS[@]}"; do fi fi + if [[ "${NATIVE_CLANG_TOOLS_PATH}" ]] ; then + common_cmake_options_host+=( + -DCMAKE_C_COMPILER="${NATIVE_CLANG_TOOLS_PATH}/clang" + -DCMAKE_CXX_COMPILER="${NATIVE_CLANG_TOOLS_PATH}/clang++" + ) + fi + llvm_cmake_options=( "${llvm_cmake_options[@]}" -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" @@ -1757,7 +1763,6 @@ for host in "${ALL_HOSTS[@]}"; do -DSWIFT_ANALYZE_CODE_COVERAGE:STRING=$(toupper "${SWIFT_ANALYZE_CODE_COVERAGE}") -DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}" -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}") - -DSWIFT_STDLIB_USE_NONATOMIC_RC:BOOL=$(true_false "${SWIFT_STDLIB_USE_NONATOMIC_RC}") -DSWIFT_ENABLE_COMPATIBILITY_OVERRIDES:BOOL=$(true_false "${SWIFT_ENABLE_COMPATIBILITY_OVERRIDES}") -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME:BOOL=$(true_false "${SWIFT_STDLIB_SINGLE_THREADED_RUNTIME}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") @@ -2991,12 +2996,13 @@ for host in "${ALL_HOSTS[@]}"; do # # Exclude shell scripts and static archives. # Exclude swift-api-digester dSYM to reduce debug toolchain size. + # Run sequentially -- dsymutil is multithreaded and can be memory intensive (cd "${host_symroot}" && find ./"${CURRENT_PREFIX}" -perm -0111 -type f -print | \ grep -v '.py$' | \ grep -v '.a$' | \ grep -v 'swift-api-digester' | \ - xargs -n 1 -P ${BUILD_JOBS} ${dsymutil_path}) + xargs -n 1 -P 1 ${dsymutil_path}) # Strip executables, shared libraries and static libraries in # `host_install_destdir`. diff --git a/utils/parser-lib/darwin-extract-symbols b/utils/parser-lib/darwin-extract-symbols index a4ee1e4c61e96..1e10f61c7c11b 100755 --- a/utils/parser-lib/darwin-extract-symbols +++ b/utils/parser-lib/darwin-extract-symbols @@ -46,11 +46,12 @@ function xcrun_find_tool() { # Run dsymutil on executables and shared libraries. # # Exclude shell scripts. +# Run sequentially -- dsymutil is multithreaded and can be memory intensive (cd "${INSTALL_SYMROOT}" && find ./"${INSTALL_PREFIX}" -perm -0111 -type f -print | \ grep -v crashlog.py | \ grep -v symbolication.py | \ - xargs -n 1 -P ${BUILD_JOBS} $(xcrun_find_tool dsymutil)) + xargs -n 1 -P 1 $(xcrun_find_tool dsymutil)) # Strip executables, shared libraries and static libraries in INSTALL_DIR. find "${INSTALL_DIR}${INSTALL_PREFIX}/" \ diff --git a/utils/sil-mode.el b/utils/sil-mode.el index fe29c99d9b58b..59cc44ba0c4c7 100644 --- a/utils/sil-mode.el +++ b/utils/sil-mode.el @@ -259,6 +259,7 @@ ;; *NOTE* viewcfg must be in the $PATH and .dot files should be associated with ;; the graphviz app. (defvar sil-mode-viewcfg-program-name "viewcfg") +(defvar sil-mode-viewcfg-renderer "dot") (defvar sil-mode-viewcfg-buffer-name "*viewcfg*") (defcustom sil-mode-viewcfg-command-default "viewcfg" @@ -281,7 +282,8 @@ (process-connection-type nil)) (let ((p (start-process sil-mode-viewcfg-program-name sil-mode-viewcfg-buffer-name - sil-mode-viewcfg-command))) + sil-mode-viewcfg-command + (concat "--renderer=" sil-mode-viewcfg-renderer)))) (process-send-region p brace-start brace-end) (process-send-eof p))))) diff --git a/utils/swift-api-dump.py b/utils/swift-api-dump.py index 9022e9c89d5b2..d44b33ae19839 100755 --- a/utils/swift-api-dump.py +++ b/utils/swift-api-dump.py @@ -102,6 +102,8 @@ def create_parser(): parser.add_argument('--enable-infer-import-as-member', action='store_true', help='Infer when a global could be imported as a ' + 'member.') + parser.add_argument('--enable-experimental-concurrency', action='store_true', + help='Enable experimental concurrency model.') parser.add_argument('-swift-version', metavar='N', help='the Swift version to use') parser.add_argument('-show-overlay', action='store_true', @@ -328,6 +330,8 @@ def main(): extra_args = ['-skip-imports'] if args.enable_infer_import_as_member: extra_args = extra_args + ['-enable-infer-import-as-member'] + if args.enable_experimental_concurrency: + extra_args = extra_args + ['-enable-experimental-concurrency'] if args.swift_version: extra_args = extra_args + ['-swift-version', '%s' % args.swift_version] diff --git a/utils/swift_build_sdk_interfaces.py b/utils/swift_build_sdk_interfaces.py index 900bae30064e0..c8381193a9bd4 100755 --- a/utils/swift_build_sdk_interfaces.py +++ b/utils/swift_build_sdk_interfaces.py @@ -354,6 +354,14 @@ def process_module_files(pool, module_files): return overall_exit_status +def getSDKVersion(sdkroot): + settingPath = os.path.join(sdkroot, 'SDKSettings.json') + with open(settingPath) as json_file: + data = json.load(json_file) + return data['Version'] + fatal("Failed to get SDK version from: " + settingPath) + + def main(): global args, shared_output_lock parser = create_parser() @@ -373,6 +381,12 @@ def main(): if not os.path.isdir(args.sdk): fatal("invalid SDK: " + args.sdk) + # if the given output dir ends with 'prebuilt-modules', we should + # append the SDK version number so all modules will built into + # the SDK-versioned sub-directory. + if os.path.basename(args.output_dir) == 'prebuilt-modules': + args.output_dir = os.path.join(args.output_dir, getSDKVersion(args.sdk)) + xfails = () if args.ignore_non_stdlib_failures: if args.xfails: diff --git a/utils/swift_build_support/swift_build_support/cmake.py b/utils/swift_build_support/swift_build_support/cmake.py index 85a97dfa747e2..5ef74e0cf5ee4 100644 --- a/utils/swift_build_support/swift_build_support/cmake.py +++ b/utils/swift_build_support/swift_build_support/cmake.py @@ -18,7 +18,6 @@ from __future__ import absolute_import, unicode_literals import os -import platform import re from numbers import Number @@ -256,9 +255,6 @@ def build_cmake(self, source_root, build_root): # the source and build the source if necessary. Returns the path to the # cmake binary. def check_cmake_version(self, source_root, build_root): - if platform.system() != 'Linux': - return - cmake_source_dir = os.path.join(source_root, 'cmake') # If the source is not checked out then don't attempt to build cmake. if not os.path.isdir(cmake_source_dir): diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 26c4e1bdbd243..bd3fe3346c470 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -348,26 +348,26 @@ "tensorflow": { "aliases": ["tensorflow"], "repos": { - "llvm-project": "7763104ea26a2d58348cd540ad1687c66f2efcf9", + "llvm-project": "14a10d635b229fb3d8fc0d80340f98430b46fcff", "swift": "tensorflow", - "cmark": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", + "cmark": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", "swift-tools-support-core": "0.1.8", - "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", + "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", "swift-argument-parser": "0.3.0", - "swift-driver": "029d4baa708755c46d6bc879c6f701df6886395d", - "swift-syntax": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", + "swift-driver": "b590b0c8e8a26c68602af7224af1bb203f23c31a", + "swift-syntax": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", "ninja": "release", "icu": "release-65-1", "yams": "3.0.1-patched", - "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", - "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-18-a", + "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", + "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-31-a", "PythonKit": "master", "swift-format": "master", "tensorflow": "v2.3.0", diff --git a/validation-test/BuildSystem/skip-local-build.test-sh b/validation-test/BuildSystem/skip-local-build.test-sh index b658957c70a85..36657e3d6fa37 100644 --- a/validation-test/BuildSystem/skip-local-build.test-sh +++ b/validation-test/BuildSystem/skip-local-build.test-sh @@ -1,8 +1,8 @@ # REQUIRES: standalone_build # -# RUN: %swift_src_root/utils/build-script --dump-config --skip-local-build 2>&1 | %FileCheck %s -check-prefix=CONFIG +# RUN: %swift_src_root/utils/build-script --dump-config --skip-local-build 2>&1 | %FileCheck %s -check-prefix=CONFIG --dump-input=always # CONFIG: "skip_local_build": true -# RUN: %swift_src_root/utils/build-script --dry-run --verbose-build --skip-local-build 2>&1 | %FileCheck %s -check-prefix=DRY +# RUN: %swift_src_root/utils/build-script --dry-run --verbose-build --skip-local-build 2>&1 | %FileCheck %s -check-prefix=DRY --dump-input=always # DRY: build-script-impl # DRY-SAME: --skip-local-build diff --git a/validation-test/Casting/BoxingCasts.swift.gyb b/validation-test/Casting/BoxingCasts.swift.gyb new file mode 100644 index 0000000000000..7ee19e67a85fb --- /dev/null +++ b/validation-test/Casting/BoxingCasts.swift.gyb @@ -0,0 +1,264 @@ +// BoxingCasts.swift - Tests for boxing/unboxing casts +// +// 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 +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for existential, optional, and other casts that box/unbox values. +/// +// ----------------------------------------------------------------------------- +// RUN: %empty-directory(%t) +// +// RUN: %gyb %s -o %t/BoxingCasts.swift +// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -module-name a -swift-version 5 -Onone %t/BoxingCasts.swift -o %t/a.swift5.Onone.out +// RUN: %target-codesign %t/a.swift5.Onone.out +// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift5.Onone.out +// +// Note: The RUN directives above override the default test optimizations. +// This test is deliberately run non-optimized in order to verify the +// behavior of runtime methods that may not be called for optimized casts. +// +// XXX FIXME XXX TODO XXX _Also_ build this with optimizations in order to +// verify compiler behaviors. +// +// REQUIRES: executable_test + +import StdlibUnittest +#if _runtime(_ObjC) +import Foundation +#endif + +fileprivate func runtimeCast (_ x: From, to: To.Type) -> To? { + return x as? To +} + +fileprivate func optional(_ x: T) -> Optional { + return runtimeCast(x, to: Optional.self)! +} + +fileprivate protocol FilePrivateProtocol {} +internal protocol InternalProtocol {} +public protocol PublicProtocol {} +protocol UnimplementedProtocol {} + +fileprivate enum EmptyEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { } + +fileprivate enum SingleCaseEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case case0 + init() {self = .case0} +} + +fileprivate enum TrivialPayloadEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case payloadCase(Int) + init() {self = .payloadCase(42)} +} + +extension TrivialPayloadEnum: Hashable {} + +fileprivate enum MultiPayloadEnum: FilePrivateProtocol, InternalProtocol, PublicProtocol { +case case0(String) +case case1(Int) + init() {self = .case1(42)} +} + +extension MultiPayloadEnum: Hashable {} + +fileprivate class ClassInt: FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) {value = v} +} + +extension ClassInt: Equatable, Hashable { + static func ==(left: ClassInt, right: ClassInt) -> Bool {left.value == right.value} + func hash(into hasher: inout Hasher) { value.hash(into: &hasher) } +} + +fileprivate struct StructInt: FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) { value = v} +} + +extension StructInt: Hashable, Equatable { } + +#if _runtime(_ObjC) +fileprivate class OCClassInt: NSObject, FilePrivateProtocol, InternalProtocol, PublicProtocol { + public var value: Int + private var tracker = LifetimeTracked(77) + init(_ v: Int = 42) { value = v} +} +#endif + +let BoxingCasts = TestSuite("BoxingCasts") + +%{ +import random +# The test body goes into a named function and the test case just invokes that +# function by name. This makes debugging easier, since it's easier to set break +# points on named functions than on arbitrary closures. +# The function names are included in the test name +# for ease of reference. +testNumber = 0 +def testFunctionName(): + return "test{number}".format(number=testNumber) +def nextTestNumber(): + global testNumber + testNumber += 1 + +# Type used for intermediate casts. The base object gets +# cast to one or more of these before the final test. +class Box: + def __init__(self, name, typeName=None, cast=None): + self.name = name + self.typeName = typeName or name + self.cast_template = cast or "runtimeCast({expr}, to: {typeName}.self)!" + def cast_oper(self, expr): + return self.cast_template.format(expr=expr, typeName=self.typeName) + +anyHashableBox = Box(name="AnyHashable") +all_boxes = [ + Box(name="Any", typeName="Any"), + Box(name="AnyStatic", cast="({expr} as Any)"), + Box(name="AnyObject"), + Box(name="SwiftValueBox", cast="_bridgeAnythingToObjectiveC({expr})"), + Box(name="Optional", cast="optional({expr})") +] +protocol_boxes = [ + Box(name="PublicProtocol"), +# Box(name="FilePrivateProtocol"), # Blocked by SR-2620 aka rdar://28281488 + Box(name="InternalProtocol"), +] + +# Describes a base object that will be subject to a variety of casts +default_protocols = [ + "PublicProtocol", + "InternalProtocol", + # "FilePrivateProtocol" # Blocked by SR-2620 aka rdar://28281488 +] + +class Contents: + def __init__(self, name, constructor=None, extra_targets=[], hashable=True, roundtrips=True, protocols=default_protocols, objc_only=False): + self.name = name + self.constructor = constructor or "{name}()".format(name=name) + self.objc_only = objc_only + + self.targets = ["Any"] + self.targets.extend(protocols) + self.targets.extend(extra_targets) + if roundtrips: + self.targets.append(self.name) + + self.boxes = [] + self.boxes.extend(all_boxes) + self.boxes.extend([Box(name=n) for n in protocols]) + if hashable: + self.boxes.append(anyHashableBox) + +contents = [ + Contents(name="StructInt", + # extra_targets=["StructInt?"], + ), + Contents(name="StructInt?", + constructor="Optional.some(StructInt())", + extra_targets=["StructInt"], + roundtrips=False, # Compiler bug rejects roundtrip cast T? => Any => T? + ), + Contents(name="ClassInt"), + Contents(name="OCClassInt", objc_only=True), + Contents(name="SingleCaseEnum"), + Contents(name="TrivialPayloadEnum"), + Contents(name="TrivialPayloadEnum"), + Contents(name="MultiPayloadEnum"), + Contents(name="StructInt.Type", + constructor="StructInt.self", + hashable=False, + protocols=[], + ), + Contents(name="StructInt.Type?", + constructor="Optional.some(StructInt.self)", + hashable=False, + protocols=[], + extra_targets=["StructInt.Type"], + roundtrips=False, # Compiler bug rejects roundtrip cast T? => Any => T? + ), + Contents(name="PublicProtocol.Protocol", + constructor="PublicProtocol.self", + hashable=False, + protocols=[], + ), +] + +# Code below generates a separate test case for each combination of content, +# target type, and one or more box/intermediate types. +}% + +% for content in contents: +% if content.objc_only: +#if _runtime(_ObjC) +% end +% for target in content.targets: +% for box in content.boxes: +% nextTestNumber() +BoxingCasts.test("${testFunctionName()}(): Casting ${box.name}(${content.name}) to ${target}") { + // TODO: Selectively enable/disable cases that work with earlier stdlib + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + ${testFunctionName()}() + } +} +func ${testFunctionName()}() { + let a = ${content.constructor} + let b = ${box.cast_oper("a")} +% # // Skip trivial cast from T? to T +% if not (content.name == target and box.name == "Optional"): +% # // Skip trivial cast from protocol box to protocol +% if box.name != target: +% # // Skip trivial cast from T? => P +% if not (target.endswith("Protocol") and box.name == "Optional"): + let c = /* ${box.name}(${content.name})) */ b as? ${target} + expectNotNil(c) +% end +% end +% end + let d = runtimeCast(/* ${box.name}(${content.name}) */ b, to: ${target}.self) + expectNotNil(d) +} + +% for innerBox in [random.choice(content.boxes)]: +% nextTestNumber() +BoxingCasts.test("${testFunctionName()}(): Casting ${box.name}(${innerBox.name}(${content.name})) to ${target}") { + // TODO: Selectively enable/disable cases that work with earlier stdlib + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + ${testFunctionName()}() + } +} +func ${testFunctionName()}() { + let a = ${content.constructor} + let b = ${innerBox.cast_oper("a")} + let c = ${box.cast_oper("b")} +% # // Skip trivial cast from T? to T +% if not (innerBox.name == target and box.name == "Optional"): +% # // Skip trivial cast from protocol box to protocol +% if box.name != target: + let d = /* ${box.name}(${innerBox.name}(${content.name})) */ c as? ${target} + expectNotNil(d) +% end +% end + let e = runtimeCast(/* ${box.name}(${innerBox.name}(${content.name})) */ c, to: ${target}.self) + expectNotNil(e) +} +% end +% end +% end +% if content.objc_only: +#endif +% end +% end + +runAllTests() diff --git a/validation-test/Runtime/weak-reference-racetests.swift b/validation-test/Runtime/weak-reference-racetests.swift index 1d759c12c60ff..23fc108b6f9f0 100644 --- a/validation-test/Runtime/weak-reference-racetests.swift +++ b/validation-test/Runtime/weak-reference-racetests.swift @@ -1,7 +1,7 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 6285e4b97c75b..6b6093f78552b 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -15,7 +15,7 @@ // Check if the optimizer can optimize the whole array into a statically // initialized global -// CHECK: sil_global private @globalinit_{{.*}} : $_ContiguousArrayStorage = { +// CHECK: sil_global private @{{.*9str_array.*}}WZTv_ : $_ContiguousArrayStorage = { // CHECK: %initval = object $_ContiguousArrayStorage public let str_array: [String] = [ diff --git a/validation-test/SILOptimizer/string_switch.swift b/validation-test/SILOptimizer/string_switch.swift index b30c80b7cc48e..555c1d972847c 100644 --- a/validation-test/SILOptimizer/string_switch.swift +++ b/validation-test/SILOptimizer/string_switch.swift @@ -4,7 +4,7 @@ // REQUIRES: swift_stdlib_no_asserts,optimized_stdlib // REQUIRES: stress_test // REQUIRES: executable_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest diff --git a/validation-test/StdlibUnittest/AtomicInt.swift b/validation-test/StdlibUnittest/AtomicInt.swift index 00bf5d1c0f8c2..9bc3e8b3f1f8a 100644 --- a/validation-test/StdlibUnittest/AtomicInt.swift +++ b/validation-test/StdlibUnittest/AtomicInt.swift @@ -4,7 +4,7 @@ // RUN: %target-run %t.out // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest diff --git a/validation-test/StdlibUnittest/RaceTest.swift b/validation-test/StdlibUnittest/RaceTest.swift index b3c296036f371..d0f1efc0ef750 100644 --- a/validation-test/StdlibUnittest/RaceTest.swift +++ b/validation-test/StdlibUnittest/RaceTest.swift @@ -2,7 +2,7 @@ // RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out // RUN: %target-run %t.out | %FileCheck %s // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest diff --git a/validation-test/compiler_crashers_2_fixed/rdar67239650.swift b/validation-test/compiler_crashers_2_fixed/rdar67239650.swift new file mode 100644 index 0000000000000..5ec036b8b61cf --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar67239650.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -typecheck %s + +@_functionBuilder +struct SillyBuilder { + static func buildBlock() -> () {} +} + +struct SillyStruct { + init(@SillyBuilder _: () -> ()) {} +} + +struct UsesSillyStruct { + var x: Int = 0 + + func foo() { + SillyStruct { + let fn = { + if true { + _ = x + } + } + } + } +} diff --git a/validation-test/compiler_crashers_2_fixed/sr13461.swift b/validation-test/compiler_crashers_2_fixed/sr13461.swift new file mode 100644 index 0000000000000..b6bda64bdce53 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr13461.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -o /dev/null %s +// REQUIRES: asserts + +final class Klass { + static var current: Klass { + fatalError() + } +} +private struct Build { + let val: T + unowned let unownedBinding = Klass.current + unowned(unsafe) let unownedUnsafeBinding = Klass.current + weak var weakBinding = Klass.current +} +private func phase(_ val: T) -> Build { + return Build(val: val) +} diff --git a/validation-test/lit.site.cfg.in b/validation-test/lit.site.cfg.in index 12aaec7150e00..649281bef0df2 100644 --- a/validation-test/lit.site.cfg.in +++ b/validation-test/lit.site.cfg.in @@ -87,8 +87,8 @@ if "@SWIFT_OPTIMIZED@" == "TRUE": if "@SWIFT_ENABLE_SOURCEKIT_TESTS@" == "TRUE": config.available_features.add('sourcekit') -if "@SWIFT_STDLIB_USE_NONATOMIC_RC@" == "TRUE": - config.available_features.add("nonatomic_rc") +if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": + config.available_features.add("single_threaded_runtime") if "@SWIFT_BUILT_STANDALONE@" == "TRUE": config.available_features.add('standalone_build') diff --git a/validation-test/stdlib/ArrayBridging.swift b/validation-test/stdlib/ArrayBridging.swift index 3fd92fa951dda..6c24bfe8dd0cf 100644 --- a/validation-test/stdlib/ArrayBridging.swift +++ b/validation-test/stdlib/ArrayBridging.swift @@ -9,7 +9,7 @@ // REQUIRES: objc_interop // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest import Foundation diff --git a/validation-test/stdlib/CommandLine.swift b/validation-test/stdlib/CommandLine.swift index 610ec08eee400..a43defe135d37 100644 --- a/validation-test/stdlib/CommandLine.swift +++ b/validation-test/stdlib/CommandLine.swift @@ -8,7 +8,7 @@ // RUN: %target-run %t/CommandLineStressTest foo bar baz qux quux corge grault garply waldo fred plugh xyzzy and thud // REQUIRES: executable_test // REQUIRES: stress_test -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime // This file is an empty stub to call into the command line stress test which // houses `main`. diff --git a/validation-test/stdlib/DictionaryBridging.swift b/validation-test/stdlib/DictionaryBridging.swift index 4a2d203e2ca79..eed83d32a67ec 100644 --- a/validation-test/stdlib/DictionaryBridging.swift +++ b/validation-test/stdlib/DictionaryBridging.swift @@ -8,7 +8,7 @@ // REQUIRES: stress_test // REQUIRES: objc_interop -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import StdlibUnittest import Foundation diff --git a/validation-test/stdlib/ErrorProtocol.swift b/validation-test/stdlib/ErrorProtocol.swift index 5e8a8b7862d38..6b2cf70ef7838 100644 --- a/validation-test/stdlib/ErrorProtocol.swift +++ b/validation-test/stdlib/ErrorProtocol.swift @@ -2,7 +2,7 @@ // REQUIRES: executable_test // REQUIRES: stress_test // REQUIRES: objc_interop -// UNSUPPORTED: nonatomic_rc +// UNSUPPORTED: single_threaded_runtime import SwiftPrivate import StdlibUnittest