Merge pull request #11623 from CodaFi/fundef
[stdlib]Custom message for recursive Strideable witness
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index 8f21b7c..c8b41ec 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -117,6 +117,10 @@
global ::= global 'Tm' // merged function
global ::= entity // some identifiable thing
global ::= type type generic-signature? 'T' REABSTRACT-THUNK-TYPE // reabstraction thunk helper function
+ global ::= entity generic-signature? type type* 'TK' // key path getter
+ global ::= entity generic-signature? type type* 'Tk' // key path setter
+ global ::= type generic-signature 'TH' // key path equality
+ global ::= type generic-signature 'Th' // key path hasher
REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk helper function
REABSTRACT-THUNK-TYPE ::= 'r' // reabstraction thunk
diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h
index 2a64e80..052946a 100644
--- a/include/swift/AST/ASTContext.h
+++ b/include/swift/AST/ASTContext.h
@@ -170,7 +170,6 @@
};
class SILLayout; // From SIL
-
/// \brief Describes either a nominal type declaration or an extension
/// declaration.
typedef llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *>
@@ -438,6 +437,9 @@
FuncDecl *get##Name(LazyResolver *resolver) const;
#include "swift/AST/KnownDecls.def"
+ /// Get the '+' function on two RangeReplaceableCollection.
+ FuncDecl *getPlusFunctionOnRangeReplaceableCollection() const;
+
/// Check whether the standard library provides all the correct
/// intrinsic support for Optional<T>.
///
diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h
index 4fd228a..feebb2e 100644
--- a/include/swift/AST/ASTMangler.h
+++ b/include/swift/AST/ASTMangler.h
@@ -114,12 +114,18 @@
Type FromType, Type ToType,
ModuleDecl *Module);
- std::string mangleKeyPathGetterThunkHelper(const VarDecl *property,
+ std::string mangleKeyPathGetterThunkHelper(const AbstractStorageDecl *property,
GenericSignature *signature,
- CanType baseType);
- std::string mangleKeyPathSetterThunkHelper(const VarDecl *property,
+ CanType baseType,
+ ArrayRef<CanType> subs);
+ std::string mangleKeyPathSetterThunkHelper(const AbstractStorageDecl *property,
GenericSignature *signature,
- CanType baseType);
+ CanType baseType,
+ ArrayRef<CanType> subs);
+ std::string mangleKeyPathEqualsHelper(ArrayRef<CanType> indices,
+ GenericSignature *signature);
+ std::string mangleKeyPathHashHelper(ArrayRef<CanType> indices,
+ GenericSignature *signature);
std::string mangleTypeForDebugger(Type decl, const DeclContext *DC,
GenericEnvironment *GE);
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index b484580..2857478 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -367,7 +367,7 @@
unsigned BodyKind : 3;
/// Number of curried parameter lists.
- unsigned NumParameterLists : 6;
+ unsigned NumParameterLists : 5;
/// Whether we are overridden later.
unsigned Overridden : 1;
@@ -380,6 +380,9 @@
/// Whether NeedsNewVTableEntry is valid.
unsigned HasComputedNeedsNewVTableEntry : 1;
+
+ /// The ResilienceExpansion to use for default arguments.
+ unsigned DefaultArgumentResilienceExpansion : 1;
};
enum { NumAbstractFunctionDeclBits = NumValueDeclBits + 13 };
static_assert(NumAbstractFunctionDeclBits <= 32, "fits in an unsigned");
@@ -4859,6 +4862,8 @@
AbstractFunctionDeclBits.Throws = Throws;
AbstractFunctionDeclBits.NeedsNewVTableEntry = false;
AbstractFunctionDeclBits.HasComputedNeedsNewVTableEntry = false;
+ AbstractFunctionDeclBits.DefaultArgumentResilienceExpansion =
+ unsigned(ResilienceExpansion::Maximal);
// Verify no bitfield truncation.
assert(AbstractFunctionDeclBits.NumParameterLists == NumParameterLists);
@@ -5076,6 +5081,21 @@
/// Resolved during type checking
void setIsOverridden() { AbstractFunctionDeclBits.Overridden = true; }
+ /// The ResilienceExpansion for default arguments.
+ ///
+ /// In Swift 4 mode, default argument expressions are serialized, and must
+ /// obey the restrictions imposed upon inlineable function bodies.
+ ResilienceExpansion getDefaultArgumentResilienceExpansion() const {
+ return ResilienceExpansion(
+ AbstractFunctionDeclBits.DefaultArgumentResilienceExpansion);
+ }
+
+ /// Set the ResilienceExpansion for default arguments.
+ void setDefaultArgumentResilienceExpansion(ResilienceExpansion expansion) {
+ AbstractFunctionDeclBits.DefaultArgumentResilienceExpansion =
+ unsigned(expansion);
+ }
+
/// Set information about the foreign error convention used by this
/// declaration.
void setForeignErrorConvention(const ForeignErrorConvention &convention);
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index 63c3da0..b6260cf 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -589,6 +589,15 @@
"keypath must have at least one component", ())
ERROR(sil_keypath_no_root,none,
"keypath must have a root component declared",())
+ERROR(sil_keypath_index_not_hashable,none,
+ "key path index type %0 does not conform to Hashable", (Type))
+ERROR(sil_keypath_index_operand_type_conflict,none,
+ "conflicting types for key path operand %0: %1 vs. %2",
+ (unsigned, Type, Type))
+ERROR(sil_keypath_no_use_of_operand_in_pattern,none,
+ "operand %0 is not referenced by any component in the pattern",
+ (unsigned))
+
// SIL Basic Blocks
ERROR(expected_sil_block_name,none,
"expected basic block name or '}'", ())
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 130ab65..4d8eb8a 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -470,6 +470,8 @@
"string interpolation can only appear inside a string literal", ())
ERROR(unsupported_keypath_tuple_element_reference,none,
"key path cannot reference tuple elements", ())
+ERROR(expr_keypath_subscript_index_not_hashable, none,
+ "subscript index of type %0 in a key path must be Hashable", (Type))
// Selector expressions.
ERROR(expr_selector_no_objc_runtime,none,
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index e78e864..c4e6cf0 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -4674,6 +4674,7 @@
llvm::PointerIntPair<Expr *, 3, Kind> SubscriptIndexExprAndKind;
ArrayRef<Identifier> SubscriptLabels;
+ ArrayRef<ProtocolConformanceRef> SubscriptHashableConformances;
Type ComponentType;
SourceLoc Loc;
@@ -4681,20 +4682,22 @@
DeclNameOrRef decl,
Expr *indexExpr,
ArrayRef<Identifier> subscriptLabels,
+ ArrayRef<ProtocolConformanceRef> indexHashables,
Kind kind,
Type type,
SourceLoc loc);
public:
Component()
- : Component(nullptr, {}, nullptr, {}, Kind::Invalid, Type(), SourceLoc())
+ : Component(nullptr, {}, nullptr, {}, {}, Kind::Invalid,
+ Type(), SourceLoc())
{}
/// Create an unresolved component for a property.
static Component forUnresolvedProperty(DeclName UnresolvedName,
SourceLoc Loc) {
return Component(nullptr,
- UnresolvedName, nullptr, {},
+ UnresolvedName, nullptr, {}, {},
Kind::UnresolvedProperty,
Type(),
Loc);
@@ -4720,13 +4723,14 @@
SourceLoc loc) {
return Component(&context,
- {}, index, subscriptLabels, Kind::UnresolvedSubscript,
+ {}, index, subscriptLabels, {},
+ Kind::UnresolvedSubscript,
Type(), loc);
}
/// Create an unresolved optional force `!` component.
static Component forUnresolvedOptionalForce(SourceLoc BangLoc) {
- return Component(nullptr, {}, nullptr, {},
+ return Component(nullptr, {}, nullptr, {}, {},
Kind::OptionalForce,
Type(),
BangLoc);
@@ -4734,7 +4738,7 @@
/// Create an unresolved optional chain `?` component.
static Component forUnresolvedOptionalChain(SourceLoc QuestionLoc) {
- return Component(nullptr, {}, nullptr, {},
+ return Component(nullptr, {}, nullptr, {}, {},
Kind::OptionalChain,
Type(),
QuestionLoc);
@@ -4744,7 +4748,7 @@
static Component forProperty(ConcreteDeclRef property,
Type propertyType,
SourceLoc loc) {
- return Component(nullptr, property, nullptr, {},
+ return Component(nullptr, property, nullptr, {}, {},
Kind::Property,
propertyType,
loc);
@@ -4752,14 +4756,15 @@
/// Create a component for a subscript.
static Component forSubscript(ASTContext &ctx,
- ConcreteDeclRef subscript,
- SourceLoc lSquareLoc,
- ArrayRef<Expr *> indexArgs,
- ArrayRef<Identifier> indexArgLabels,
- ArrayRef<SourceLoc> indexArgLabelLocs,
- SourceLoc rSquareLoc,
- Expr *trailingClosure,
- Type elementType);
+ ConcreteDeclRef subscript,
+ SourceLoc lSquareLoc,
+ ArrayRef<Expr *> indexArgs,
+ ArrayRef<Identifier> indexArgLabels,
+ ArrayRef<SourceLoc> indexArgLabelLocs,
+ SourceLoc rSquareLoc,
+ Expr *trailingClosure,
+ Type elementType,
+ ArrayRef<ProtocolConformanceRef> indexHashables);
/// Create a component for a subscript.
///
@@ -4767,11 +4772,12 @@
/// list of index arguments.
static Component forSubscriptWithPrebuiltIndexExpr(
ConcreteDeclRef subscript, Expr *index, ArrayRef<Identifier> labels,
- Type elementType, SourceLoc loc);
+ Type elementType, SourceLoc loc,
+ ArrayRef<ProtocolConformanceRef> indexHashables);
/// Create an optional-forcing `!` component.
static Component forOptionalForce(Type forcedType, SourceLoc bangLoc) {
- return Component(nullptr, {}, nullptr, {},
+ return Component(nullptr, {}, nullptr, {}, {},
Kind::OptionalForce, forcedType,
bangLoc);
}
@@ -4779,7 +4785,7 @@
/// Create an optional-chaining `?` component.
static Component forOptionalChain(Type unwrappedType,
SourceLoc questionLoc) {
- return Component(nullptr, {}, nullptr, {},
+ return Component(nullptr, {}, nullptr, {}, {},
Kind::OptionalChain, unwrappedType,
questionLoc);
}
@@ -4788,7 +4794,7 @@
/// syntax but may appear when the non-optional result of an optional chain
/// is implicitly wrapped.
static Component forOptionalWrap(Type wrappedType) {
- return Component(nullptr, {}, nullptr, {},
+ return Component(nullptr, {}, nullptr, {}, {},
Kind::OptionalWrap, wrappedType,
SourceLoc());
}
@@ -4855,6 +4861,26 @@
llvm_unreachable("no subscript labels for this kind");
}
}
+
+ ArrayRef<ProtocolConformanceRef>
+ getSubscriptIndexHashableConformances() const {
+ switch (getKind()) {
+ case Kind::Subscript:
+ return SubscriptHashableConformances;
+
+ case Kind::UnresolvedSubscript:
+ case Kind::Invalid:
+ case Kind::OptionalChain:
+ case Kind::OptionalWrap:
+ case Kind::OptionalForce:
+ case Kind::UnresolvedProperty:
+ case Kind::Property:
+ llvm_unreachable("no hashable conformances for this kind");
+ }
+ }
+
+ void setSubscriptIndexHashableConformances(
+ ArrayRef<ProtocolConformanceRef> hashables);
DeclName getUnresolvedDeclName() const {
switch (getKind()) {
diff --git a/include/swift/AST/Initializer.h b/include/swift/AST/Initializer.h
index 754f5a6..bb02e88 100644
--- a/include/swift/AST/Initializer.h
+++ b/include/swift/AST/Initializer.h
@@ -154,26 +154,16 @@
public:
explicit DefaultArgumentInitializer(DeclContext *parent, unsigned index)
: Initializer(InitializerKind::DefaultArgument, parent) {
- SpareBits = (unsigned(ResilienceExpansion::Maximal) | index << 1);
+ SpareBits = index;
}
- unsigned getIndex() const { return SpareBits >> 1; }
-
- ResilienceExpansion getResilienceExpansion() const {
- return ResilienceExpansion(SpareBits & 1);
- }
+ unsigned getIndex() const { return SpareBits; }
/// Change the parent of this context. This is necessary because
/// the function signature is parsed before the function
/// declaration/expression itself is built.
void changeFunction(AbstractFunctionDecl *parent);
- /// Change the resilience expansion of this context, necessary
- /// for the same reason as above.
- void changeResilienceExpansion(ResilienceExpansion expansion) {
- SpareBits = (SpareBits & ~1) | unsigned(expansion);
- }
-
static bool classof(const DeclContext *DC) {
if (auto init = dyn_cast<Initializer>(DC))
return classof(init);
diff --git a/include/swift/AST/KnownStdlibTypes.def b/include/swift/AST/KnownStdlibTypes.def
index 8120bbb..904d543 100644
--- a/include/swift/AST/KnownStdlibTypes.def
+++ b/include/swift/AST/KnownStdlibTypes.def
@@ -77,5 +77,6 @@
KNOWN_STDLIB_TYPE_DECL(Decoder, ProtocolDecl, 1)
KNOWN_STDLIB_TYPE_DECL(KeyedEncodingContainer, NominalTypeDecl, 1)
KNOWN_STDLIB_TYPE_DECL(KeyedDecodingContainer, NominalTypeDecl, 1)
+KNOWN_STDLIB_TYPE_DECL(RangeReplaceableCollection, ProtocolDecl, 1)
#undef KNOWN_STDLIB_TYPE_DECL
diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h
index 97000a4..2923787 100644
--- a/include/swift/Basic/LangOptions.h
+++ b/include/swift/Basic/LangOptions.h
@@ -236,9 +236,6 @@
/// Diagnose uses of NSCoding with classes that have unstable mangled names.
bool EnableNSKeyedArchiverDiagnostics = true;
- /// Enable keypath components that aren't fully implemented.
- bool EnableExperimentalKeyPathComponents = false;
-
/// When a conversion from String to Substring fails, emit a fix-it to append
/// the void subscript '[]'.
/// FIXME: Remove this flag when void subscripts are implemented.
diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h
index ce20fb6..199537f 100644
--- a/include/swift/Basic/STLExtras.h
+++ b/include/swift/Basic/STLExtras.h
@@ -786,6 +786,24 @@
return std::transform(C.begin(), C.end(), result, op);
}
+/// Provides default implementations of !=, <=, >, and >= based on == and <.
+template <typename T>
+class RelationalOperationsBase {
+public:
+ friend bool operator>(const T &left, const T &right) {
+ return right < left;
+ }
+ friend bool operator>=(const T &left, const T &right) {
+ return !(left < right);
+ }
+ friend bool operator<=(const T &left, const T &right) {
+ return !(right < left);
+ }
+ friend bool operator!=(const T &left, const T &right) {
+ return !(left == right);
+ }
+};
+
} // end namespace swift
#endif // SWIFT_BASIC_INTERLEAVE_H
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index d0b26c9..92f7c0f 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -97,6 +97,8 @@
CONTEXT_NODE(Initializer)
NODE(KeyPathGetterThunkHelper)
NODE(KeyPathSetterThunkHelper)
+NODE(KeyPathEqualsThunkHelper)
+NODE(KeyPathHashThunkHelper)
NODE(LazyProtocolWitnessTableAccessor)
NODE(LazyProtocolWitnessTableCacheVariable)
NODE(LocalDeclName)
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 867e1e9..8a306eb 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -283,10 +283,6 @@
Flag<["-"], "enable-experimental-property-behaviors">,
HelpText<"Enable experimental property behaviors">;
-def enable_experimental_keypath_components :
- Flag<["-"], "enable-experimental-keypath-components">,
- HelpText<"Enable unimplemented keypath component kinds">;
-
def enable_deserialization_recovery :
Flag<["-"], "enable-deserialization-recovery">,
HelpText<"Attempt to recover from missing xrefs (etc) in swiftmodules">;
diff --git a/include/swift/Runtime/HeapObject.h b/include/swift/Runtime/HeapObject.h
index c78c309..c21291d 100644
--- a/include/swift/Runtime/HeapObject.h
+++ b/include/swift/Runtime/HeapObject.h
@@ -889,13 +889,15 @@
///
/// \param ref - never null
/// \param value - not necessarily a native Swift object; can be null
+/// \return ref
SWIFT_RUNTIME_EXPORT
-void swift_unknownWeakInit(WeakReference *ref, void *value);
+WeakReference *swift_unknownWeakInit(WeakReference *ref, void *value);
#else
-static inline void swift_unknownWeakInit(WeakReference *ref, void *value) {
- swift_weakInit(ref, static_cast<HeapObject *>(value));
+static inline WeakReference *swift_unknownWeakInit(WeakReference *ref,
+ void *value) {
+ return swift_weakInit(ref, static_cast<HeapObject *>(value));
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -906,13 +908,15 @@
///
/// \param ref - never null
/// \param value - not necessarily a native Swift object; can be null
+/// \return ref
SWIFT_RUNTIME_EXPORT
-void swift_unknownWeakAssign(WeakReference *ref, void *value);
+WeakReference *swift_unknownWeakAssign(WeakReference *ref, void *value);
#else
-static inline void swift_unknownWeakAssign(WeakReference *ref, void *value) {
- swift_weakAssign(ref, static_cast<HeapObject *>(value));
+static inline WeakReference *swift_unknownWeakAssign(WeakReference *ref,
+ void *value) {
+ return swift_weakAssign(ref, static_cast<HeapObject *>(value));
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -973,15 +977,16 @@
/// Copy-initialize a weak reference variable from one that might not
/// refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownWeakCopyInit(WeakReference *dest,
- WeakReference *src);
+WeakReference *swift_unknownWeakCopyInit(WeakReference *dest,
+ WeakReference *src);
#else
-static inline void swift_unknownWeakCopyInit(WeakReference *dest,
- WeakReference *src) {
- swift_weakCopyInit(dest, src);
+static inline WeakReference *swift_unknownWeakCopyInit(WeakReference *dest,
+ WeakReference *src) {
+ return swift_weakCopyInit(dest, src);
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -990,15 +995,16 @@
/// Take-initialize a weak reference variable from one that might not
/// refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownWeakTakeInit(WeakReference *dest,
- WeakReference *src);
+WeakReference *swift_unknownWeakTakeInit(WeakReference *dest,
+ WeakReference *src);
#else
-static inline void swift_unknownWeakTakeInit(WeakReference *dest,
- WeakReference *src) {
- swift_weakTakeInit(dest, src);
+static inline WeakReference *swift_unknownWeakTakeInit(WeakReference *dest,
+ WeakReference *src) {
+ return swift_weakTakeInit(dest, src);
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1007,15 +1013,16 @@
/// Copy-assign a weak reference variable from another when either
/// or both variables might not refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownWeakCopyAssign(WeakReference *dest,
- WeakReference *src);
+WeakReference *swift_unknownWeakCopyAssign(WeakReference *dest,
+ WeakReference *src);
#else
-static inline void swift_unknownWeakCopyAssign(WeakReference *dest,
- WeakReference *src) {
- swift_weakCopyAssign(dest, src);
+static inline WeakReference *swift_unknownWeakCopyAssign(WeakReference *dest,
+ WeakReference *src) {
+ return swift_weakCopyAssign(dest, src);
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1024,15 +1031,16 @@
/// Take-assign a weak reference variable from another when either
/// or both variables might not refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownWeakTakeAssign(WeakReference *dest,
- WeakReference *src);
+WeakReference *swift_unknownWeakTakeAssign(WeakReference *dest,
+ WeakReference *src);
#else
-static inline void swift_unknownWeakTakeAssign(WeakReference *dest,
- WeakReference *src) {
- swift_weakTakeAssign(dest, src);
+static inline WeakReference *swift_unknownWeakTakeAssign(WeakReference *dest,
+ WeakReference *src) {
+ return swift_weakTakeAssign(dest, src);
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1045,14 +1053,16 @@
/// Initialize an unowned reference to an object with unknown reference
/// counting.
+/// \return ref
SWIFT_RUNTIME_EXPORT
-void swift_unknownUnownedInit(UnownedReference *ref, void *value);
+UnownedReference *swift_unknownUnownedInit(UnownedReference *ref, void *value);
#else
-static inline void swift_unknownUnownedInit(UnownedReference *ref,
- void *value) {
+static inline UnownedReference *swift_unknownUnownedInit(UnownedReference *ref,
+ void *value) {
swift_unownedInit(ref, static_cast<HeapObject*>(value));
+ return ref;
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1061,14 +1071,17 @@
/// Assign to an unowned reference holding an object with unknown reference
/// counting.
+/// \return ref
SWIFT_RUNTIME_EXPORT
-void swift_unknownUnownedAssign(UnownedReference *ref, void *value);
+UnownedReference *swift_unknownUnownedAssign(UnownedReference *ref,
+ void *value);
#else
-static inline void swift_unknownUnownedAssign(UnownedReference *ref,
- void *value) {
+static inline UnownedReference *
+swift_unknownUnownedAssign(UnownedReference *ref, void *value) {
swift_unownedAssign(ref, static_cast<HeapObject*>(value));
+ return ref;
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1121,15 +1134,17 @@
/// Copy-initialize an unowned reference variable from one that might not
/// refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownUnownedCopyInit(UnownedReference *dest,
- UnownedReference *src);
+UnownedReference *swift_unknownUnownedCopyInit(UnownedReference *dest,
+ UnownedReference *src);
#else
-static inline void swift_unknownUnownedCopyInit(UnownedReference *dest,
- UnownedReference *src) {
+static inline UnownedReference *
+swift_unknownUnownedCopyInit(UnownedReference *dest, UnownedReference *src) {
swift_unownedCopyInit(dest, src);
+ return dest;
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1139,14 +1154,15 @@
/// Take-initialize an unowned reference variable from one that might not
/// refer to a native Swift object.
SWIFT_RUNTIME_EXPORT
-void swift_unknownUnownedTakeInit(UnownedReference *dest,
- UnownedReference *src);
+UnownedReference *swift_unknownUnownedTakeInit(UnownedReference *dest,
+ UnownedReference *src);
#else
-static inline void swift_unknownUnownedTakeInit(UnownedReference *dest,
- UnownedReference *src) {
+static inline UnownedReference *
+swift_unknownUnownedTakeInit(UnownedReference *dest, UnownedReference *src) {
swift_unownedTakeInit(dest, src);
+ return dest;
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1155,15 +1171,17 @@
/// Copy-assign an unowned reference variable from another when either
/// or both variables might not refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownUnownedCopyAssign(UnownedReference *dest,
- UnownedReference *src);
+UnownedReference *swift_unknownUnownedCopyAssign(UnownedReference *dest,
+ UnownedReference *src);
#else
-static inline void swift_unknownUnownedCopyAssign(UnownedReference *dest,
- UnownedReference *src) {
+static inline UnownedReference *
+swift_unknownUnownedCopyAssign(UnownedReference *dest, UnownedReference *src) {
swift_unownedCopyAssign(dest, src);
+ return dest;
}
#endif /* SWIFT_OBJC_INTEROP */
@@ -1172,15 +1190,17 @@
/// Take-assign an unowned reference variable from another when either
/// or both variables might not refer to a native Swift object.
+/// \return dest
SWIFT_RUNTIME_EXPORT
-void swift_unknownUnownedTakeAssign(UnownedReference *dest,
- UnownedReference *src);
+UnownedReference *swift_unknownUnownedTakeAssign(UnownedReference *dest,
+ UnownedReference *src);
#else
-static inline void swift_unknownUnownedTakeAssign(UnownedReference *dest,
- UnownedReference *src) {
+static inline UnownedReference *
+swift_unknownUnownedTakeAssign(UnownedReference *dest, UnownedReference *src) {
swift_unownedTakeAssign(dest, src);
+ return dest;
}
#endif /* SWIFT_OBJC_INTEROP */
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index afa1eb9..0f5ff24 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -520,15 +520,15 @@
// void swift_unknownWeakInit(WeakReference *object, void *value);
FUNCTION(UnknownWeakInit, swift_unknownWeakInit, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(WeakReferencePtrTy),
ARGS(WeakReferencePtrTy, UnknownRefCountedPtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownWeakAssign(WeakReference *object, void *value);
+// WeakReference *swift_unknownWeakAssign(WeakReference *object, void *value);
FUNCTION(UnknownWeakAssign, swift_unknownWeakAssign, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(WeakReferencePtrTy),
ARGS(WeakReferencePtrTy, UnknownRefCountedPtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
// void *swift_unknownWeakLoad(WeakReference *object);
FUNCTION(UnknownWeakLoadStrong, swift_unknownWeakLoadStrong,DefaultCC,
@@ -542,29 +542,29 @@
ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind))
-// void swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src);
+// WeakReference *swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakCopyInit, swift_unknownWeakCopyInit, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(WeakReferencePtrTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src);
+// void *swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakTakeInit, swift_unknownWeakTakeInit, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(WeakReferencePtrTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src);
+// WeakReference *swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakCopyAssign, swift_unknownWeakCopyAssign, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(WeakReferencePtrTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src);
+// WeakReference *swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakTakeAssign, swift_unknownWeakTakeAssign, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(WeakReferencePtrTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
// void swift_unknownUnownedDestroy(UnownedReference *object);
FUNCTION(UnknownUnownedDestroy, swift_unknownUnownedDestroy, DefaultCC,
@@ -572,17 +572,17 @@
ARGS(UnownedReferencePtrTy),
ATTRS(NoUnwind))
-// void swift_unknownUnownedInit(UnownedReference *object, void *value);
+// UnownedReference *swift_unknownUnownedInit(UnownedReference *object, void *value);
FUNCTION(UnknownUnownedInit, swift_unknownUnownedInit, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(UnownedReferencePtrTy),
ARGS(UnownedReferencePtrTy, UnknownRefCountedPtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownUnownedAssign(UnownedReference *object, void *value);
+// UnownedReference *swift_unknownUnownedAssign(UnownedReference *object, void *value);
FUNCTION(UnknownUnownedAssign, swift_unknownUnownedAssign, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(UnownedReferencePtrTy),
ARGS(UnownedReferencePtrTy, UnknownRefCountedPtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
// void *swift_unknownUnownedLoad(UnownedReference *object);
FUNCTION(UnknownUnownedLoadStrong, swift_unknownUnownedLoadStrong, DefaultCC,
@@ -596,29 +596,29 @@
ARGS(UnownedReferencePtrTy),
ATTRS(NoUnwind))
-// void swift_unknownUnownedCopyInit(UnownedReference *dest, UnownedReference *src);
+// UnownedReference *swift_unknownUnownedCopyInit(UnownedReference *dest, UnownedReference *src);
FUNCTION(UnknownUnownedCopyInit, swift_unknownUnownedCopyInit, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(UnownedReferencePtrTy),
ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownUnownedTakeInit(UnownedReference *dest, UnownedReference *src);
+// UnownedReference *swift_unknownUnownedTakeInit(UnownedReference *dest, UnownedReference *src);
FUNCTION(UnknownUnownedTakeInit, swift_unknownUnownedTakeInit, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(UnownedReferencePtrTy),
ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownUnownedCopyAssign(UnownedReference *dest, UnownedReference *src);
+// UnownedReference *swift_unknownUnownedCopyAssign(UnownedReference *dest, UnownedReference *src);
FUNCTION(UnknownUnownedCopyAssign, swift_unknownUnownedCopyAssign, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(UnownedReferencePtrTy),
ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
-// void swift_unknownUnownedTakeAssign(UnownedReference *dest, UnownedReference *src);
+// UnownedReference *swift_unknownUnownedTakeAssign(UnownedReference *dest, UnownedReference *src);
FUNCTION(UnknownUnownedTakeAssign, swift_unknownUnownedTakeAssign, DefaultCC,
- RETURNS(VoidTy),
+ RETURNS(UnownedReferencePtrTy),
ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy),
- ATTRS(NoUnwind))
+ ATTRS(NoUnwind, FirstParamReturned))
// bool swift_isUniquelyReferencedNonObjC(const void *);
FUNCTION(IsUniquelyReferencedNonObjC, swift_isUniquelyReferencedNonObjC,
@@ -1287,6 +1287,10 @@
RETURNS(RefCountedPtrTy),
ARGS(Int8PtrTy, Int8PtrTy),
ATTRS(NoUnwind))
+FUNCTION(CopyKeyPathTrivialIndices, swift_copyKeyPathTrivialIndices, DefaultCC,
+ RETURNS(VoidTy),
+ ARGS(Int8PtrTy, Int8PtrTy, SizeTy),
+ ATTRS(NoUnwind))
#if SWIFT_OBJC_INTEROP || !defined(SWIFT_RUNTIME_GENERATE_GLOBAL_SYMBOLS)
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index e2bba6f..58c86d9 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -535,9 +535,11 @@
KeyPathInst *createKeyPath(SILLocation Loc,
KeyPathPattern *Pattern,
SubstitutionList Subs,
+ ArrayRef<SILValue> Args,
SILType Ty) {
return insert(KeyPathInst::create(getSILDebugLocation(Loc),
- Pattern, Subs, Ty, getFunction()));
+ Pattern, Subs, Args,
+ Ty, getFunction()));
}
/// Convenience function for calling emitLoad on the type lowering for
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 90773f3..6e05444 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -2344,10 +2344,15 @@
template <typename ImplClass>
void SILCloner<ImplClass>::visitKeyPathInst(KeyPathInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+ SmallVector<SILValue, 4> opValues;
+ for (auto &op : Inst->getAllOperands())
+ opValues.push_back(getOpValue(op.get()));
+
doPostProcess(Inst, getBuilder().createKeyPath(
getOpLocation(Inst->getLoc()),
Inst->getPattern(),
getOpSubstitutions(Inst->getSubstitutions()),
+ opValues,
getOpType(Inst->getType())));
}
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index c32b4a6..288bf2b 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -1534,11 +1534,13 @@
OptionalWrap,
};
- // The pair of a captured index value and its Hashable conformance for a
+ // Description of a captured index value and its Hashable conformance for a
// subscript keypath.
- struct IndexPair {
+ struct Index {
unsigned Operand;
- ProtocolConformance *Hashable;
+ CanType FormalType;
+ SILType LoweredType;
+ ProtocolConformanceRef Hashable;
};
private:
@@ -1555,7 +1557,9 @@
ComputedPropertyId::KindType>
SetterAndIdKind;
ComputedPropertyId::ValueType IdValue;
- ArrayRef<IndexPair> Indices;
+ ArrayRef<Index> Indices;
+ SILFunction *IndicesEqual;
+ SILFunction *IndicesHash;
CanType ComponentType;
unsigned kindForPacking(Kind k) {
@@ -1579,13 +1583,21 @@
KeyPathPatternComponent(ComputedPropertyId id, Kind kind,
SILFunction *getter,
SILFunction *setter,
- ArrayRef<IndexPair> indices,
+ ArrayRef<Index> indices,
+ SILFunction *indicesEqual,
+ SILFunction *indicesHash,
CanType ComponentType)
: ValueAndKind(getter, kindForPacking(kind)),
SetterAndIdKind(setter, id.Kind),
IdValue(id.Value),
Indices(indices),
- ComponentType(ComponentType) {}
+ IndicesEqual(indicesEqual),
+ IndicesHash(indicesHash),
+ ComponentType(ComponentType) {
+ assert(indices.empty() == !indicesEqual
+ && indices.empty() == !indicesHash
+ && "must have equals/hash functions iff there are indices");
+ }
public:
KeyPathPatternComponent() : ValueAndKind(nullptr, 0) {}
@@ -1661,7 +1673,7 @@
llvm_unreachable("unhandled kind");
}
- ArrayRef<IndexPair> getComputedPropertyIndices() const {
+ ArrayRef<Index> getComputedPropertyIndices() const {
switch (getKind()) {
case Kind::StoredProperty:
case Kind::OptionalChain:
@@ -1674,6 +1686,13 @@
}
}
+ SILFunction *getComputedPropertyIndexEquals() const {
+ return IndicesEqual;
+ }
+ SILFunction *getComputedPropertyIndexHash() const {
+ return IndicesHash;
+ }
+
bool isComputedSettablePropertyMutating() const;
static KeyPathPatternComponent forStoredProperty(VarDecl *property,
@@ -1684,20 +1703,26 @@
static KeyPathPatternComponent
forComputedGettableProperty(ComputedPropertyId identifier,
SILFunction *getter,
- ArrayRef<IndexPair> indices,
+ ArrayRef<Index> indices,
+ SILFunction *indicesEquals,
+ SILFunction *indicesHash,
CanType ty) {
return KeyPathPatternComponent(identifier, Kind::GettableProperty,
- getter, nullptr, indices, ty);
+ getter, nullptr, indices,
+ indicesEquals, indicesHash, ty);
}
static KeyPathPatternComponent
forComputedSettableProperty(ComputedPropertyId identifier,
SILFunction *getter,
SILFunction *setter,
- ArrayRef<IndexPair> indices,
+ ArrayRef<Index> indices,
+ SILFunction *indicesEquals,
+ SILFunction *indicesHash,
CanType ty) {
return KeyPathPatternComponent(identifier, Kind::SettableProperty,
- getter, setter, indices, ty);
+ getter, setter, indices,
+ indicesEquals, indicesHash, ty);
}
static KeyPathPatternComponent
@@ -1797,32 +1822,40 @@
/// Instantiates a key path object.
class KeyPathInst final
: public SILInstruction,
- private llvm::TrailingObjects<KeyPathInst, Substitution>
+ private llvm::TrailingObjects<KeyPathInst, Substitution, Operand>
{
friend SILBuilder;
friend TrailingObjects;
KeyPathPattern *Pattern;
- unsigned NumSubstitutions;
+ unsigned NumSubstitutions, NumOperands;
static KeyPathInst *create(SILDebugLocation Loc,
KeyPathPattern *Pattern,
SubstitutionList Subs,
+ ArrayRef<SILValue> Args,
SILType Ty,
SILFunction &F);
KeyPathInst(SILDebugLocation Loc,
KeyPathPattern *Pattern,
SubstitutionList Subs,
+ ArrayRef<SILValue> Args,
SILType Ty);
+ size_t numTrailingObjects(OverloadToken<Substitution>) const {
+ return NumSubstitutions;
+ }
+ size_t numTrailingObjects(OverloadToken<Operand>) const {
+ return NumOperands;
+ }
+
public:
KeyPathPattern *getPattern() const;
bool hasPattern() const { return (bool)Pattern; }
ArrayRef<Operand> getAllOperands() const {
- // TODO: Subscript keypaths will have operands.
- return {};
+ return const_cast<KeyPathInst*>(this)->getAllOperands();
}
MutableArrayRef<Operand> getAllOperands();
diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h
index e3b548f..12daf09 100644
--- a/include/swift/SIL/SILType.h
+++ b/include/swift/SIL/SILType.h
@@ -258,8 +258,10 @@
/// True if the type, or the referenced type of an address type, is trivial.
bool isTrivial(SILModule &M) const;
- /// True if the type, or the referenced type of an address type, is a
- /// scalar reference-counted type.
+ /// True if the type, or the referenced type of an address type, is known to
+ /// be a scalar reference-counted type. If this is false, then some part of
+ /// the type may be opaque. It may become reference counted later after
+ /// specialization.
bool isReferenceCounted(SILModule &M) const;
/// Returns true if the referenced type is a function type that never
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index bc7d869..4de46f2 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -326,15 +326,13 @@
/// FIXME: this could be space-compressed.
SILInstruction *Owner;
+public:
Operand(SILInstruction *owner) : Owner(owner) {}
Operand(SILInstruction *owner, SILValue theValue)
: TheValue(theValue), Owner(owner) {
insertIntoCurrent();
}
- template<unsigned N> friend class FixedOperandList;
- template<unsigned N> friend class TailAllocatedOperandList;
-public:
/// Operands are not copyable.
Operand(const Operand &use) = delete;
Operand &operator=(const Operand &use) = delete;
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 4afeb8e..08f2d2e 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
/// in source control, you should also update the comment to briefly
/// 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.
-const uint16_t VERSION_MINOR = 364; // Last change: Builtin.assignCopyArray...
+const uint16_t VERSION_MINOR = 366; // Last change: default argument resilience expansion
using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
@@ -388,6 +388,13 @@
/// TODO: Float, string, char, etc.
};
+// These IDs must \em not be renumbered or reordered without incrementing
+// VERSION_MAJOR.
+enum class ResilienceExpansion : uint8_t {
+ Minimal = 0,
+ Maximal,
+};
+
using EnumElementRawValueKindField = BCFixed<4>;
/// The various types of blocks that can occur within a serialized Swift
@@ -893,6 +900,7 @@
DeclIDField, // overridden decl
AccessLevelField, // access level
BCFixed<1>, // requires a new vtable slot
+ BCFixed<1>, // default argument resilience expansion
BCFixed<1>, // 'required' but overridden is not (used for recovery)
BCVBR<5>, // number of parameter name components
BCArray<IdentifierIDField> // name components,
@@ -957,6 +965,7 @@
AddressorKindField, // addressor kind
AccessLevelField, // access level
BCFixed<1>, // requires a new vtable slot
+ BCFixed<1>, // default argument resilience expansion
BCArray<IdentifierIDField> // name components,
// followed by TypeID dependencies
// The record is trailed by:
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b1a9b87..8d003f1 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -129,6 +129,9 @@
DECL_CLASS *NAME##Decl = nullptr;
#include "swift/AST/KnownStdlibTypes.def"
+ /// The declaration of '+' function for two RangeReplaceableCollection.
+ FuncDecl *PlusFunctionOnRangeReplaceableCollection = nullptr;
+
/// The declaration of Swift.Optional<T>.Some.
EnumElementDecl *OptionalSomeDecl = nullptr;
@@ -545,6 +548,30 @@
return nullptr;
}
+FuncDecl *ASTContext::getPlusFunctionOnRangeReplaceableCollection() const {
+ if (Impl.PlusFunctionOnRangeReplaceableCollection) {
+ return Impl.PlusFunctionOnRangeReplaceableCollection;
+ }
+ // Find all of the declarations with this name in the Swift module.
+ SmallVector<ValueDecl *, 1> Results;
+ lookupInSwiftModule("+", Results);
+ for (auto Result : Results) {
+ if (auto *FD = dyn_cast<FuncDecl>(Result)) {
+ if(!FD->getOperatorDecl())
+ continue;
+ for (auto Req: FD->getGenericRequirements()) {
+ if (Req.getKind() == RequirementKind::Conformance &&
+ Req.getSecondType()->getNominalOrBoundGenericNominal() ==
+ getRangeReplaceableCollectionDecl()) {
+ Impl.PlusFunctionOnRangeReplaceableCollection = FD;
+ }
+ }
+ }
+ }
+ return Impl.PlusFunctionOnRangeReplaceableCollection;
+}
+
+
#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
DECL_CLASS *ASTContext::get##NAME##Decl() const { \
if (!Impl.NAME##Decl) \
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index 8e0db26..0191a17 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -276,30 +276,70 @@
return finalize();
}
-std::string ASTMangler::mangleKeyPathGetterThunkHelper(const VarDecl *property,
- GenericSignature *signature,
- CanType baseType) {
+std::string ASTMangler::mangleKeyPathGetterThunkHelper(
+ const AbstractStorageDecl *property,
+ GenericSignature *signature,
+ CanType baseType,
+ ArrayRef<CanType> subs) {
beginMangling();
appendEntity(property);
if (signature)
appendGenericSignature(signature);
appendType(baseType);
+ if (isa<SubscriptDecl>(property)) {
+ // Subscripts can be generic, and different key paths could capture the same
+ // subscript at different generic arguments.
+ for (auto &sub : subs) {
+ appendType(sub);
+ }
+ }
appendOperator("TK");
return finalize();
}
-std::string ASTMangler::mangleKeyPathSetterThunkHelper(const VarDecl *property,
- GenericSignature *signature,
- CanType baseType) {
+std::string ASTMangler::mangleKeyPathSetterThunkHelper(
+ const AbstractStorageDecl *property,
+ GenericSignature *signature,
+ CanType baseType,
+ ArrayRef<CanType> subs) {
beginMangling();
appendEntity(property);
if (signature)
appendGenericSignature(signature);
appendType(baseType);
+ if (isa<SubscriptDecl>(property)) {
+ // Subscripts can be generic, and different key paths could capture the same
+ // subscript at different generic arguments.
+ for (auto &sub : subs) {
+ appendType(sub);
+ }
+ }
appendOperator("Tk");
return finalize();
}
+std::string ASTMangler::mangleKeyPathEqualsHelper(ArrayRef<CanType> indices,
+ GenericSignature *signature) {
+ beginMangling();
+ for (auto &index : indices)
+ appendType(index);
+ if (signature)
+ appendGenericSignature(signature);
+ appendOperator("TH");
+ return finalize();
+}
+
+std::string ASTMangler::mangleKeyPathHashHelper(ArrayRef<CanType> indices,
+ GenericSignature *signature) {
+ beginMangling();
+ for (auto &index : indices)
+ appendType(index);
+ if (signature)
+ appendGenericSignature(signature);
+ appendOperator("Th");
+ return finalize();
+}
+
std::string ASTMangler::mangleGlobalInit(const VarDecl *decl, int counter,
bool isInitFunc) {
auto topLevelContext = decl->getDeclContext()->getModuleScopeContext();
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index e4055aa..78a2088 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -954,7 +954,8 @@
newIndex,
component.getSubscriptLabels(),
component.getComponentType(),
- component.getLoc())
+ component.getLoc(),
+ component.getSubscriptIndexHashableConformances())
: KeyPathExpr::Component
::forUnresolvedSubscriptWithPrebuiltIndexExpr(
E->getType()->getASTContext(),
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index f8d4e75..45690b5 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -519,8 +519,10 @@
for (const auto *dc = this; dc->isLocalContext(); dc = dc->getParent()) {
// Default argument initializer contexts have their resilience expansion
// set when they're type checked.
- if (auto *DAI = dyn_cast<DefaultArgumentInitializer>(dc))
- return DAI->getResilienceExpansion();
+ if (auto *DAI = dyn_cast<DefaultArgumentInitializer>(dc)) {
+ return cast<AbstractFunctionDecl>(dc->getParent())
+ ->getDefaultArgumentResilienceExpansion();
+ }
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(dc)) {
// If the function is a nested function, we will serialize its body if
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 819fd19..03ba1bb 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2131,14 +2131,15 @@
KeyPathExpr::Component
KeyPathExpr::Component::forSubscript(ASTContext &ctx,
- ConcreteDeclRef subscript,
- SourceLoc lSquareLoc,
- ArrayRef<Expr *> indexArgs,
- ArrayRef<Identifier> indexArgLabels,
- ArrayRef<SourceLoc> indexArgLabelLocs,
- SourceLoc rSquareLoc,
- Expr *trailingClosure,
- Type elementType) {
+ ConcreteDeclRef subscript,
+ SourceLoc lSquareLoc,
+ ArrayRef<Expr *> indexArgs,
+ ArrayRef<Identifier> indexArgLabels,
+ ArrayRef<SourceLoc> indexArgLabelLocs,
+ SourceLoc rSquareLoc,
+ Expr *trailingClosure,
+ Type elementType,
+ ArrayRef<ProtocolConformanceRef> indexHashables) {
SmallVector<Identifier, 4> indexArgLabelsScratch;
SmallVector<SourceLoc, 4> indexArgLabelLocsScratch;
Expr *index = packSingleArgument(ctx, lSquareLoc, indexArgs, indexArgLabels,
@@ -2149,7 +2150,8 @@
return forSubscriptWithPrebuiltIndexExpr(subscript, index,
indexArgLabels,
elementType,
- lSquareLoc);
+ lSquareLoc,
+ indexHashables);
}
KeyPathExpr::Component
@@ -2176,6 +2178,7 @@
DeclNameOrRef decl,
Expr *indexExpr,
ArrayRef<Identifier> subscriptLabels,
+ ArrayRef<ProtocolConformanceRef> indexHashables,
Kind kind,
Type type,
SourceLoc loc)
@@ -2183,13 +2186,35 @@
SubscriptLabels(subscriptLabels.empty()
? subscriptLabels
: ctxForCopyingLabels->AllocateCopy(subscriptLabels)),
+ SubscriptHashableConformances(indexHashables),
ComponentType(type), Loc(loc)
{}
KeyPathExpr::Component
KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr(
ConcreteDeclRef subscript, Expr *index, ArrayRef<Identifier> labels,
- Type elementType, SourceLoc loc) {
+ Type elementType, SourceLoc loc,
+ ArrayRef<ProtocolConformanceRef> indexHashables) {
return Component(&elementType->getASTContext(),
- subscript, index, {}, Kind::Subscript, elementType, loc);
+ subscript, index, labels, indexHashables,
+ Kind::Subscript, elementType, loc);
+}
+
+void KeyPathExpr::Component::setSubscriptIndexHashableConformances(
+ ArrayRef<ProtocolConformanceRef> hashables) {
+ switch (getKind()) {
+ case Kind::Subscript:
+ SubscriptHashableConformances = getComponentType()->getASTContext()
+ .AllocateCopy(hashables);
+ return;
+
+ case Kind::UnresolvedSubscript:
+ case Kind::Invalid:
+ case Kind::OptionalChain:
+ case Kind::OptionalWrap:
+ case Kind::OptionalForce:
+ case Kind::UnresolvedProperty:
+ case Kind::Property:
+ llvm_unreachable("no hashable conformances for this kind");
+ }
}
diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp
index e0155aa..04daaf81 100644
--- a/lib/ClangImporter/ClangAdapter.cpp
+++ b/lib/ClangImporter/ClangAdapter.cpp
@@ -437,7 +437,7 @@
importer::getSwiftNewtypeAttr(const clang::TypedefNameDecl *decl,
ImportNameVersion version) {
// Newtype was introduced in Swift 3
- if (version < ImportNameVersion::Swift3 )
+ if (version <= ImportNameVersion::swift2())
return nullptr;
return retrieveNewTypeAttr(decl);
}
@@ -448,7 +448,7 @@
clang::Sema &clangSema,
ImportNameVersion version) {
// Newtype was introduced in Swift 3
- if (version < ImportNameVersion::Swift3 )
+ if (version <= ImportNameVersion::swift2())
return nullptr;
auto varDecl = dyn_cast<clang::VarDecl>(decl);
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index c707c36..4d4ab55 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -1650,7 +1650,7 @@
BridgingHeaderExplicitlyRequested(!opts.BridgingHeader.empty()),
DisableAdapterModules(opts.DisableAdapterModules),
IsReadingBridgingPCH(false),
- CurrentVersion(nameVersionFromOptions(ctx.LangOpts)),
+ CurrentVersion(ImportNameVersion::fromOptions(ctx.LangOpts)),
BridgingHeaderLookupTable(new SwiftLookupTable(nullptr)),
platformAvailability(ctx.LangOpts),
nameImporter() {}
@@ -2508,32 +2508,34 @@
bool anyMatching = false;
TypeDecl *originalDecl = nullptr;
- owner.forEachDistinctName(clangTypeDecl, [&](ImportedName newName,
- ImportNameVersion nameVersion){
+ owner.forEachDistinctName(clangTypeDecl,
+ [&](ImportedName newName,
+ ImportNameVersion nameVersion) -> bool {
if (anyMatching)
- return;
+ return true;
if (!newName.getDeclName().isSimpleName(name))
- return;
+ return true;
auto decl = dyn_cast_or_null<TypeDecl>(
owner.importDeclReal(clangTypeDecl, nameVersion));
if (!decl)
- return;
+ return false;
if (!originalDecl)
originalDecl = decl;
else if (originalDecl == decl)
- return;
+ return true;
auto *importedContext = decl->getDeclContext()->
getAsNominalTypeOrNominalTypeExtensionContext();
if (importedContext != baseType)
- return;
+ return true;
assert(decl->getFullName().matchesRef(name) &&
"importFullName behaved differently from importDecl");
results.push_back(decl);
anyMatching = true;
+ return true;
});
}
@@ -3150,10 +3152,8 @@
const clang::NamedDecl *recentClangDecl =
clangDecl->getMostRecentDecl();
- forEachImportNameVersionFromCurrent(CurrentVersion,
- [&](ImportNameVersion nameVersion) {
- if (nameVersion == CurrentVersion)
- return;
+ CurrentVersion.forEachOtherImportNameVersion(
+ [&](ImportNameVersion nameVersion) {
if (anyMatching)
return;
@@ -3211,12 +3211,12 @@
forEachDistinctName(clangDecl,
[&](ImportedName importedName,
- ImportNameVersion nameVersion) {
+ ImportNameVersion nameVersion) -> bool {
// Import the declaration.
auto decl =
cast_or_null<ValueDecl>(importDeclReal(clangDecl, nameVersion));
if (!decl)
- return;
+ return false;
// If the name we found matches, report the declaration.
// FIXME: If we didn't need to check alternate decls here, we could avoid
@@ -3232,6 +3232,7 @@
consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup);
}
}
+ return true;
});
}
}
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index e88a2a9..e539e2b 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -349,11 +349,17 @@
void ClangImporter::Implementation::forEachDistinctName(
const clang::NamedDecl *decl,
- llvm::function_ref<void(ImportedName, ImportNameVersion)> action) {
+ llvm::function_ref<bool(ImportedName, ImportNameVersion)> action) {
using ImportNameKey = std::pair<DeclName, EffectiveClangContext>;
SmallVector<ImportNameKey, 8> seenNames;
- forEachImportNameVersionFromCurrent(CurrentVersion,
- [&](ImportNameVersion nameVersion) {
+
+ ImportedName newName = importFullName(decl, CurrentVersion);
+ ImportNameKey key(newName, newName.getEffectiveContext());
+ if (action(newName, CurrentVersion))
+ seenNames.push_back(key);
+
+ CurrentVersion.forEachOtherImportNameVersion(
+ [&](ImportNameVersion nameVersion) {
// Check to see if the name is different.
ImportedName newName = importFullName(decl, nameVersion);
ImportNameKey key(newName, newName.getEffectiveContext());
@@ -365,8 +371,8 @@
});
if (seen)
return;
- seenNames.push_back(key);
- action(newName, nameVersion);
+ if (action(newName, nameVersion))
+ seenNames.push_back(key);
});
}
@@ -1927,7 +1933,7 @@
Optional<ImportedName> &correctSwiftName) {
ImportNameVersion canonicalVersion = getActiveSwiftVersion();
if (isa<clang::TypeDecl>(D) || isa<clang::ObjCContainerDecl>(D)) {
- canonicalVersion = ImportNameVersion::ForTypes;
+ canonicalVersion = ImportNameVersion::forTypes();
}
correctSwiftName = None;
@@ -2113,36 +2119,38 @@
// If we're importing a global as a member, we need to provide the
// effective context.
Impl.printSwiftName(
- correctSwiftName,
+ correctSwiftName, getActiveSwiftVersion(),
/*fullyQualified=*/correctSwiftName.importAsMember(), os);
}
- unsigned majorVersion = majorVersionNumberForNameVersion(getVersion());
DeclAttribute *attr;
- if (isActiveSwiftVersion() || getVersion() == ImportNameVersion::Raw) {
+ if (isActiveSwiftVersion() || getVersion() == ImportNameVersion::raw()) {
// "Raw" is the Objective-C name, which was never available in Swift.
// Variants within the active version are usually declarations that
// have been superseded, like the accessors of a property.
attr = AvailableAttr::createPlatformAgnostic(
ctx, /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()),
PlatformAgnosticAvailabilityKind::UnavailableInSwift);
- } else if (getVersion() < getActiveSwiftVersion()) {
- // A Swift 2 name, for example, was obsoleted in Swift 3.
- attr = AvailableAttr::createPlatformAgnostic(
- ctx, /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()),
- PlatformAgnosticAvailabilityKind::SwiftVersionSpecific,
- clang::VersionTuple(majorVersion + 1));
} else {
- // Future names are introduced in their future version.
- assert(getVersion() > getActiveSwiftVersion());
- attr = new (ctx) AvailableAttr(
- SourceLoc(), SourceRange(), PlatformKind::none,
- /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()),
- /*Introduced*/clang::VersionTuple(majorVersion), SourceRange(),
- /*Deprecated*/clang::VersionTuple(), SourceRange(),
- /*Obsoleted*/clang::VersionTuple(), SourceRange(),
- PlatformAgnosticAvailabilityKind::SwiftVersionSpecific,
- /*Implicit*/false);
+ unsigned majorVersion = getVersion().majorVersionNumber();
+ if (getVersion() < getActiveSwiftVersion()) {
+ // A Swift 2 name, for example, was obsoleted in Swift 3.
+ attr = AvailableAttr::createPlatformAgnostic(
+ ctx, /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()),
+ PlatformAgnosticAvailabilityKind::SwiftVersionSpecific,
+ clang::VersionTuple(majorVersion + 1));
+ } else {
+ // Future names are introduced in their future version.
+ assert(getVersion() > getActiveSwiftVersion());
+ attr = new (ctx) AvailableAttr(
+ SourceLoc(), SourceRange(), PlatformKind::none,
+ /*Message*/StringRef(), ctx.AllocateCopy(renamed.str()),
+ /*Introduced*/clang::VersionTuple(majorVersion), SourceRange(),
+ /*Deprecated*/clang::VersionTuple(), SourceRange(),
+ /*Obsoleted*/clang::VersionTuple(), SourceRange(),
+ PlatformAgnosticAvailabilityKind::SwiftVersionSpecific,
+ /*Implicit*/false);
+ }
}
decl->getAttrs().add(attr);
@@ -2663,31 +2671,33 @@
case EnumKind::Unknown:
Impl.forEachDistinctName(constant,
[&](ImportedName newName,
- ImportNameVersion nameVersion) {
+ ImportNameVersion nameVersion) -> bool {
Decl *imported = Impl.importDecl(constant, nameVersion);
if (!imported)
- return;
+ return false;
if (nameVersion == getActiveSwiftVersion())
enumeratorDecl = imported;
else
variantDecls.push_back(imported);
+ return true;
});
break;
case EnumKind::Options:
Impl.forEachDistinctName(constant,
[&](ImportedName newName,
- ImportNameVersion nameVersion) {
+ ImportNameVersion nameVersion) -> bool {
if (!contextIsEnum(newName))
- return;
+ return true;
SwiftDeclConverter converter(Impl, nameVersion);
Decl *imported =
converter.importOptionConstant(constant, decl, result);
if (!imported)
- return;
+ return false;
if (nameVersion == getActiveSwiftVersion())
enumeratorDecl = imported;
else
variantDecls.push_back(imported);
+ return true;
});
break;
case EnumKind::Enum: {
@@ -2735,18 +2745,19 @@
Impl.forEachDistinctName(constant,
[&](ImportedName newName,
- ImportNameVersion nameVersion) {
+ ImportNameVersion nameVersion) -> bool {
if (nameVersion == getActiveSwiftVersion())
- return;
+ return true;
if (!contextIsEnum(newName))
- return;
+ return true;
SwiftDeclConverter converter(Impl, nameVersion);
Decl *imported =
converter.importEnumCase(constant, decl, cast<EnumDecl>(result),
enumeratorDecl);
if (!imported)
- return;
+ return false;
variantDecls.push_back(imported);
+ return true;
});
break;
}
@@ -4823,7 +4834,7 @@
// we don't care.
Decl *importedDecl = nullptr;
if (getVersion() >= getActiveSwiftVersion())
- importedDecl = Impl.importDecl(decl, ImportNameVersion::ForTypes);
+ importedDecl = Impl.importDecl(decl, ImportNameVersion::forTypes());
if (!importedDecl && getVersion() != getActiveSwiftVersion())
importedDecl = Impl.importDecl(decl, getActiveSwiftVersion());
auto typeDecl = dyn_cast_or_null<TypeDecl>(importedDecl);
@@ -6894,9 +6905,7 @@
{
// Render a swift_name string.
llvm::raw_svector_ostream os(renamed);
- printSwiftName(importedName,
- /*fullyQualified=*/true,
- os);
+ printSwiftName(importedName, CurrentVersion, /*fullyQualified=*/true, os);
}
return SwiftContext.AllocateCopy(StringRef(renamed));
@@ -8023,9 +8032,9 @@
continue;
forEachDistinctName(
- decl, [&](ImportedName newName, ImportNameVersion nameVersion) {
- addMemberAndAlternatesToExtension(decl, newName, nameVersion, ext);
- });
+ decl, [&](ImportedName newName, ImportNameVersion nameVersion) -> bool {
+ return addMemberAndAlternatesToExtension(decl, newName, nameVersion, ext);
+ });
}
}
@@ -8043,29 +8052,30 @@
return result;
}
-void ClangImporter::Implementation::addMemberAndAlternatesToExtension(
+bool ClangImporter::Implementation::addMemberAndAlternatesToExtension(
clang::NamedDecl *decl, ImportedName newName, ImportNameVersion nameVersion,
ExtensionDecl *ext) {
// Quickly check the context and bail out if it obviously doesn't
// belong here.
if (auto *importDC = newName.getEffectiveContext().getAsDeclContext())
if (importDC->isTranslationUnit())
- return;
+ return true;
// Then try to import the decl under the specified name.
auto *member = importDecl(decl, nameVersion);
if (!member)
- return;
+ return false;
member = findMemberThatWillLandInAnExtensionContext(member);
if (!member || member->getDeclContext() != ext)
- return;
+ return true;
ext->addMember(member);
for (auto alternate : getAlternateDecls(member)) {
if (alternate->getDeclContext() == ext)
ext->addMember(alternate);
}
+ return true;
}
static ExtensionDecl *
@@ -8127,26 +8137,27 @@
const clang::NamedDecl *nd, SmallVectorImpl<Decl *> &members) {
llvm::SmallPtrSet<Decl *, 4> knownAlternateMembers;
forEachDistinctName(
- nd, [&](ImportedName name, ImportNameVersion nameVersion) {
- auto member = importDecl(nd, nameVersion);
- if (!member)
- return;
+ nd, [&](ImportedName name, ImportNameVersion nameVersion) -> bool {
+ auto member = importDecl(nd, nameVersion);
+ if (!member)
+ return false;
- // If there are alternate declarations for this member, add them.
- for (auto alternate : getAlternateDecls(member)) {
- if (alternate->getDeclContext() == member->getDeclContext() &&
- knownAlternateMembers.insert(alternate).second) {
- members.push_back(alternate);
- }
- }
+ // If there are alternate declarations for this member, add them.
+ for (auto alternate : getAlternateDecls(member)) {
+ if (alternate->getDeclContext() == member->getDeclContext() &&
+ knownAlternateMembers.insert(alternate).second) {
+ members.push_back(alternate);
+ }
+ }
- // If this declaration shouldn't be visible, don't add it to
- // the list.
- if (shouldSuppressDeclImport(nd))
- return;
+ // If this declaration shouldn't be visible, don't add it to
+ // the list.
+ if (shouldSuppressDeclImport(nd))
+ return true;
- members.push_back(member);
- });
+ members.push_back(member);
+ return true;
+ });
}
void ClangImporter::Implementation::collectMembersToAdd(
diff --git a/lib/ClangImporter/ImportEnumInfo.cpp b/lib/ClangImporter/ImportEnumInfo.cpp
index 4dfb3ee..f9ac7cc 100644
--- a/lib/ClangImporter/ImportEnumInfo.cpp
+++ b/lib/ClangImporter/ImportEnumInfo.cpp
@@ -68,7 +68,7 @@
// If API notes have /removed/ a FlagEnum or EnumExtensibility attribute,
// then we don't need to check the macros.
for (auto *attr : decl->specific_attrs<clang::SwiftVersionedAttr>()) {
- if (!attr->getVersion().empty())
+ if (!attr->getIsReplacedByActive())
continue;
if (isa<clang::FlagEnumAttr>(attr->getAttrToAdd()) ||
isa<clang::EnumExtensibilityAttr>(attr->getAttrToAdd())) {
diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp
index 2d40e02..161f1e9 100644
--- a/lib/ClangImporter/ImportName.cpp
+++ b/lib/ClangImporter/ImportName.cpp
@@ -54,39 +54,6 @@
using clang::CompilerInstance;
using clang::CompilerInvocation;
-ImportNameVersion
-importer::nameVersionFromOptions(const LangOptions &langOpts) {
- auto languageVersion = langOpts.EffectiveLanguageVersion;
- switch (languageVersion[0]) {
- default:
- llvm_unreachable("unknown swift language version");
- case 1:
- case 2:
- return ImportNameVersion::Swift2;
- case 3:
- return ImportNameVersion::Swift3;
- // Fixme: Figure out the importing story for 5 instead of falling back to 4.
- case 4:
- case 5:
- return ImportNameVersion::Swift4;
- }
-}
-
-unsigned importer::majorVersionNumberForNameVersion(ImportNameVersion version) {
- switch (version) {
- case ImportNameVersion::Raw:
- return 0;
- case ImportNameVersion::Swift2:
- return 2;
- case ImportNameVersion::Swift3:
- return 3;
- case ImportNameVersion::Swift4:
- return 4;
- }
-
- llvm_unreachable("Unhandled ImportNameVersion in switch.");
-}
-
/// Determine whether the given Clang selector matches the given
/// selector pieces.
@@ -318,10 +285,9 @@
/// Will recursively print out the fully qualified context for the given name.
/// Ends with a trailing "."
-static void
-printFullContextPrefix(ImportedName name,
- llvm::raw_ostream &os,
- ClangImporter::Implementation &Impl) {
+static void printFullContextPrefix(ImportedName name, ImportNameVersion version,
+ llvm::raw_ostream &os,
+ ClangImporter::Implementation &Impl) {
const clang::NamedDecl *newDeclContextNamed = nullptr;
switch (name.getEffectiveContext().getKind()) {
case EffectiveClangContext::UnresolvedContext:
@@ -347,12 +313,13 @@
// Now, let's print out the parent
assert(newDeclContextNamed && "should of been set");
- auto parentName = Impl.importFullName(newDeclContextNamed, name.getVersion());
- printFullContextPrefix(parentName, os, Impl);
+ auto parentName = Impl.importFullName(newDeclContextNamed, version);
+ printFullContextPrefix(parentName, version, os, Impl);
os << parentName.getDeclName() << ".";
}
void ClangImporter::Implementation::printSwiftName(ImportedName name,
+ ImportNameVersion version,
bool fullyQualified,
llvm::raw_ostream &os) {
// Property accessors.
@@ -376,7 +343,7 @@
}
if (fullyQualified)
- printFullContextPrefix(name, os, *this);
+ printFullContextPrefix(name, version, os, *this);
// Base name.
os << name.getDeclName().getBaseName();
@@ -578,17 +545,63 @@
return None;
}
-template <typename A>
-static bool matchesVersion(A *versionedAttr, ImportNameVersion version) {
- clang::VersionTuple attrVersion = versionedAttr->getVersion();
- if (attrVersion.empty())
- return version == ImportNameVersion::LAST_VERSION;
- return attrVersion.getMajor() == majorVersionNumberForNameVersion(version);
+namespace {
+/// Aggregate struct for the common members of clang::SwiftVersionedAttr and
+/// clang::SwiftVersionedRemovalAttr.
+///
+/// For a SwiftVersionedRemovalAttr, the Attr member will be null.
+struct VersionedSwiftNameInfo {
+ const clang::SwiftNameAttr *Attr;
+ clang::VersionTuple Version;
+ bool IsReplacedByActive;
+};
+
+/// The action to take upon seeing a particular versioned swift_name annotation.
+enum class VersionedSwiftNameAction {
+ /// This annotation is not interesting.
+ Ignore,
+ /// This annotation is better than whatever we have so far.
+ Use,
+ /// This annotation is better than nothing, but that's all; don't bother
+ /// recording its version.
+ UseAsFallback,
+ /// This annotation itself isn't interesting, but its version shows that the
+ /// correct answer is whatever's currently active.
+ ResetToActive
+};
+} // end anonymous namespace
+
+static VersionedSwiftNameAction
+checkVersionedSwiftName(VersionedSwiftNameInfo info,
+ clang::VersionTuple bestSoFar,
+ ImportNameVersion requestedVersion) {
+ if (!bestSoFar.empty() && bestSoFar <= info.Version)
+ return VersionedSwiftNameAction::Ignore;
+
+ if (info.IsReplacedByActive) {
+ // We know that there are no versioned names between the active version and
+ // a replacement version, because otherwise /that/ name would be active.
+ // So if replacement < requested, we want to use the old value that was
+ // replaced (but with very low priority), and otherwise we want to use the
+ // new value that is now active. (Special case: replacement = 0 means that
+ // a header annotation was replaced by an unversioned API notes annotation.)
+ if (info.Version.empty() ||
+ info.Version.getMajor() >= requestedVersion.majorVersionNumber()) {
+ return VersionedSwiftNameAction::ResetToActive;
+ }
+ if (bestSoFar.empty())
+ return VersionedSwiftNameAction::UseAsFallback;
+ return VersionedSwiftNameAction::Ignore;
+ }
+
+ if (info.Version.getMajor() < requestedVersion.majorVersionNumber())
+ return VersionedSwiftNameAction::Ignore;
+ return VersionedSwiftNameAction::Use;
}
-const clang::SwiftNameAttr *
-importer::findSwiftNameAttr(const clang::Decl *decl,
- ImportNameVersion version) {
+
+static const clang::SwiftNameAttr *
+findSwiftNameAttr(const clang::Decl *decl, ImportNameVersion version) {
#ifndef NDEBUG
if (Optional<const clang::Decl *> def = getDefinitionForClangTypeDecl(decl)) {
assert((*def == nullptr || *def == decl) &&
@@ -596,30 +609,64 @@
}
#endif
- if (version == ImportNameVersion::Raw)
+ if (version == ImportNameVersion::raw())
return nullptr;
// Handle versioned API notes for Swift 3 and later. This is the common case.
- if (version != ImportNameVersion::Swift2) {
+ if (version > ImportNameVersion::swift2()) {
+ const auto *activeAttr = decl->getAttr<clang::SwiftNameAttr>();
+ const clang::SwiftNameAttr *result = activeAttr;
+ clang::VersionTuple bestSoFar;
for (auto *attr : decl->attrs()) {
+ VersionedSwiftNameInfo info;
+
if (auto *versionedAttr = dyn_cast<clang::SwiftVersionedAttr>(attr)) {
- if (!matchesVersion(versionedAttr, version))
+ auto *added =
+ dyn_cast<clang::SwiftNameAttr>(versionedAttr->getAttrToAdd());
+ if (!added)
continue;
- if (auto *added =
- dyn_cast<clang::SwiftNameAttr>(versionedAttr->getAttrToAdd())) {
- return added;
- }
+
+ info = {added, versionedAttr->getVersion(),
+ versionedAttr->getIsReplacedByActive()};
+
+ } else if (auto *removeAttr =
+ dyn_cast<clang::SwiftVersionedRemovalAttr>(attr)) {
+ if (removeAttr->getAttrKindToRemove() != clang::attr::SwiftName)
+ continue;
+ info = {nullptr, removeAttr->getVersion(),
+ removeAttr->getIsReplacedByActive()};
+
+ } else {
+ continue;
}
- if (auto *removeAttr = dyn_cast<clang::SwiftVersionedRemovalAttr>(attr)) {
- if (!matchesVersion(removeAttr, version))
- continue;
- if (removeAttr->getAttrKindToRemove() == clang::attr::SwiftName)
- return nullptr;
+ switch (checkVersionedSwiftName(info, bestSoFar, version)) {
+ case VersionedSwiftNameAction::Ignore:
+ continue;
+ case VersionedSwiftNameAction::Use:
+ result = info.Attr;
+ bestSoFar = info.Version;
+ break;
+ case VersionedSwiftNameAction::UseAsFallback:
+ // HACK: If there's a swift_name attribute in the headers /and/ in the
+ // unversioned API notes /and/ in the active versioned API notes, there
+ // will be two "replacement" attributes, one for each of the first two
+ // cases. Prefer the first one we see, because that turns out to be the
+ // one from the API notes, which matches the semantics when there are no
+ // versioned API notes. (This isn't very principled but there's at least
+ // a test to tell us if it changes.)
+ if (result == activeAttr)
+ result = info.Attr;
+ assert(bestSoFar.empty());
+ break;
+ case VersionedSwiftNameAction::ResetToActive:
+ result = activeAttr;
+ bestSoFar = info.Version;
+ break;
}
}
- return decl->getAttr<clang::SwiftNameAttr>();
+ return result;
}
// The remainder of this function emulates the limited form of swift_name
@@ -843,7 +890,7 @@
case EnumKind::Enum:
case EnumKind::Options:
// Enums are mapped to Swift enums, Options to Swift option sets.
- if (version != ImportNameVersion::Raw) {
+ if (version != ImportNameVersion::raw()) {
res = cast<clang::DeclContext>(enumDecl);
break;
}
@@ -960,7 +1007,7 @@
switch (nameImporter.getEnumKind(ED)) {
case EnumKind::Enum:
case EnumKind::Options:
- if (version != ImportNameVersion::Raw)
+ if (version != ImportNameVersion::raw())
break;
LLVM_FALLTHROUGH;
case EnumKind::Constants:
@@ -1125,7 +1172,7 @@
static bool suppressFactoryMethodAsInit(const clang::ObjCMethodDecl *method,
ImportNameVersion version,
CtorInitializerKind initKind) {
- return (version == ImportNameVersion::Raw || method->isPropertyAccessor()) &&
+ return (version == ImportNameVersion::raw() || method->isPropertyAccessor()) &&
(initKind == CtorInitializerKind::Factory ||
initKind == CtorInitializerKind::ConvenienceFactory);
}
@@ -1136,7 +1183,7 @@
ImportedName result;
/// Whether we want a Swift 3 or later name
- bool swift3OrLaterName = version >= ImportNameVersion::Swift3;
+ bool swift3OrLaterName = version > ImportNameVersion::swift2();
// Objective-C categories and extensions don't have names, despite
// being "named" declarations.
@@ -1516,7 +1563,7 @@
// Enumeration constants may have common prefixes stripped.
bool strippedPrefix = false;
- if (version != ImportNameVersion::Raw && isa<clang::EnumConstantDecl>(D)) {
+ if (version != ImportNameVersion::raw() && isa<clang::EnumConstantDecl>(D)) {
auto enumDecl = cast<clang::EnumDecl>(D->getDeclContext());
auto enumInfo = getEnumInfo(enumDecl);
@@ -1723,7 +1770,6 @@
}
++ImportNameNumCacheMisses;
auto res = importNameImpl(decl, version, givenName);
- res.setVersion(version);
if (!givenName)
importNameCache[key] = res;
return res;
diff --git a/lib/ClangImporter/ImportName.h b/lib/ClangImporter/ImportName.h
index b8f33cc..f993b02 100644
--- a/lib/ClangImporter/ImportName.h
+++ b/lib/ClangImporter/ImportName.h
@@ -20,6 +20,7 @@
#include "ImportEnumInfo.h"
#include "SwiftLookupTable.h"
#include "swift/Basic/StringExtras.h"
+#include "swift/Basic/Version.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ForeignErrorConvention.h"
@@ -40,78 +41,88 @@
enum { NumImportedAccessorKindBits = 3 };
/// The name version
-enum class ImportNameVersion : unsigned {
- /// Names as they appear in C/ObjC
- Raw = 0,
+class ImportNameVersion : public RelationalOperationsBase<ImportNameVersion> {
+ unsigned rawValue;
+ friend llvm::DenseMapInfo<ImportNameVersion>;
- /// Names as they appeared in Swift 2 family
- Swift2,
+ enum AsConstExpr_t { AsConstExpr };
- /// Names as they appeared in Swift 3 family
- Swift3,
+ constexpr ImportNameVersion() : rawValue(0) {}
+ constexpr ImportNameVersion(unsigned version, AsConstExpr_t)
+ : rawValue(version) {}
+ explicit ImportNameVersion(unsigned version) : rawValue(version) {
+ assert(version >= 2 && "only Swift 2 and later are supported");
+ }
+public:
+ /// Map a language version into an import name version.
+ static ImportNameVersion fromOptions(const LangOptions &langOpts) {
+ return ImportNameVersion(langOpts.EffectiveLanguageVersion[0]);
+ }
- /// Names as they appeared in Swift 4 family
- Swift4,
+ unsigned majorVersionNumber() const {
+ assert(*this != ImportNameVersion::raw());
+ return rawValue;
+ }
- /// A placeholder for the latest version, to be used in loops and such.
- LAST_VERSION = Swift4,
+ bool operator==(ImportNameVersion other) const {
+ return rawValue == other.rawValue;
+ }
+ bool operator<(ImportNameVersion other) const {
+ return rawValue < other.rawValue;
+ }
+
+ /// Calls \p action for each name version other than this one, first going
+ /// backwards until ImportNameVersion::raw(), and then going forwards to
+ /// ImportNameVersion::maxVersion().
+ ///
+ /// This is the most useful order for importing compatibility stubs.
+ void forEachOtherImportNameVersion(
+ llvm::function_ref<void(ImportNameVersion)> action) const {
+ assert(*this >= ImportNameVersion::swift2());
+
+ ImportNameVersion nameVersion = *this;
+ while (nameVersion > ImportNameVersion::swift2()) {
+ --nameVersion.rawValue;
+ action(nameVersion);
+ }
+
+ action(ImportNameVersion::raw());
+
+ nameVersion = *this;
+ while (nameVersion < ImportNameVersion::maxVersion()) {
+ ++nameVersion.rawValue;
+ action(nameVersion);
+ }
+ }
+
+ /// Names as they appear in C/ObjC.
+ static constexpr inline ImportNameVersion raw() {
+ return ImportNameVersion{};
+ }
+
+ /// Names as they appeared in Swift 2 family.
+ static constexpr inline ImportNameVersion swift2() {
+ return ImportNameVersion{2, AsConstExpr};
+ }
+
+ /// The latest supported version.
+ ///
+ /// FIXME: All other version information is in Version.h. Can this go there
+ /// instead?
+ static constexpr inline ImportNameVersion maxVersion() {
+ return ImportNameVersion{5, AsConstExpr};
+ }
/// The version which should be used for importing types, which need to have
/// one canonical definition.
///
/// FIXME: Is this supposed to be the /newest/ version, or a canonical
/// version that lasts forever as part of the ABI?
- ForTypes = Swift4
+ static constexpr inline ImportNameVersion forTypes() {
+ return ImportNameVersion::maxVersion();
+ }
};
-static inline ImportNameVersion &operator++(ImportNameVersion &value) {
- assert(value != ImportNameVersion::LAST_VERSION);
- value = static_cast<ImportNameVersion>(static_cast<unsigned>(value) + 1);
- return value;
-}
-
-static inline ImportNameVersion &operator--(ImportNameVersion &value) {
- assert(value != ImportNameVersion::Raw);
- value = static_cast<ImportNameVersion>(static_cast<unsigned>(value) - 1);
- return value;
-}
-
-/// Calls \p action for each name version, starting with \p current, then going
-/// backwards until ImportNameVersion::Raw, and then finally going forwards to
-/// ImportNameVersion::LAST_VERSION.
-///
-/// This is the most useful order for importing compatibility stubs.
-static inline void forEachImportNameVersionFromCurrent(
- ImportNameVersion current,
- llvm::function_ref<void(ImportNameVersion)> action) {
- action(current);
- ImportNameVersion nameVersion = current;
- while (nameVersion != ImportNameVersion::Raw) {
- --nameVersion;
- action(nameVersion);
- }
- nameVersion = current;
- while (nameVersion != ImportNameVersion::LAST_VERSION) {
- ++nameVersion;
- action(nameVersion);
- }
-}
-
-/// Calls \p action for each name version, starting with ImportNameVersion::Raw
-/// and going forwards.
-static inline void
-forEachImportNameVersion(llvm::function_ref<void(ImportNameVersion)> action) {
- auto limit = static_cast<unsigned>(ImportNameVersion::LAST_VERSION);
- for (unsigned raw = 0; raw <= limit; ++raw)
- action(static_cast<ImportNameVersion>(raw));
-}
-
-/// Map a language version into an import name version.
-ImportNameVersion nameVersionFromOptions(const LangOptions &langOpts);
-
-/// Map an import name version into a language version.
-unsigned majorVersionNumberForNameVersion(ImportNameVersion version);
-
/// Describes a name that was imported from Clang.
class ImportedName {
friend class NameImporter;
@@ -141,11 +152,6 @@
/// For an initializer, the kind of initializer to import.
CtorInitializerKind initKind;
- /// The version of Swift this name corresponds to.
- ///
- /// \see ImportNameVersion
- unsigned rawVersion : 2;
-
/// What kind of accessor this name refers to, if any.
ImportedAccessorKind accessorKind : NumImportedAccessorKindBits;
@@ -167,9 +173,9 @@
Info()
: errorInfo(), selfIndex(), initKind(CtorInitializerKind::Designated),
- rawVersion(), accessorKind(ImportedAccessorKind::None),
- hasCustomName(false), droppedVariadic(false), importAsMember(false),
- hasSelfIndex(false), hasErrorInfo(false) {}
+ accessorKind(ImportedAccessorKind::None), hasCustomName(false),
+ droppedVariadic(false), importAsMember(false), hasSelfIndex(false),
+ hasErrorInfo(false) {}
} info;
public:
@@ -189,16 +195,6 @@
effectiveContext = ctx;
}
- /// The highest version of Swift that this name comes from
- ImportNameVersion getVersion() const {
- return static_cast<ImportNameVersion>(info.rawVersion);
- }
-
- void setVersion(ImportNameVersion version) {
- info.rawVersion = static_cast<unsigned>(version);
- assert(getVersion() == version && "not enough bits");
- }
-
/// For an initializer, the kind of initializer to import.
CtorInitializerKind getInitKind() const { return info.initKind; }
@@ -272,11 +268,6 @@
/// in "Notification", or it there would be nothing left.
StringRef stripNotification(StringRef name);
-/// Find the swift_name attribute associated with this declaration, if any,
-/// appropriate for \p version.
-const clang::SwiftNameAttr *findSwiftNameAttr(const clang::Decl *decl,
- ImportNameVersion version);
-
/// Class to determine the Swift name of foreign entities. Currently fairly
/// stateless and borrows from the ClangImporter::Implementation, but in the
/// future will be more self-contained and encapsulated.
@@ -387,7 +378,7 @@
return (ImportNameVersion)DMIU::getTombstoneKey();
}
static unsigned getHashValue(const ImportNameVersion &Val) {
- return DMIU::getHashValue((unsigned)Val);
+ return DMIU::getHashValue(Val.rawValue);
}
static bool isEqual(const ImportNameVersion &LHS,
const ImportNameVersion &RHS) {
diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h
index 2d63bcd..d904d35 100644
--- a/lib/ClangImporter/ImporterImpl.h
+++ b/lib/ClangImporter/ImporterImpl.h
@@ -641,7 +641,9 @@
/// Print an imported name as a string suitable for the swift_name attribute,
/// or the 'Rename' field of AvailableAttr.
- void printSwiftName(importer::ImportedName, bool fullyQualified,
+ void printSwiftName(importer::ImportedName name,
+ importer::ImportNameVersion version,
+ bool fullyQualified,
llvm::raw_ostream &os);
/// \brief Import the given Clang identifier into Swift.
@@ -1130,7 +1132,14 @@
void insertMembersAndAlternates(const clang::NamedDecl *nd,
SmallVectorImpl<Decl *> &members);
void loadAllMembersIntoExtension(Decl *D, uint64_t extra);
- void addMemberAndAlternatesToExtension(
+
+ /// Imports \p decl under \p nameVersion with the name \p newName, and adds
+ /// it and its alternates to \p ext.
+ ///
+ /// \returns true if \p decl was successfully imported, whether or not it was
+ /// ultimately added to \p ext. This matches the behavior of
+ /// forEachDistinctName's callback.
+ bool addMemberAndAlternatesToExtension(
clang::NamedDecl *decl, importer::ImportedName newName,
importer::ImportNameVersion nameVersion, ExtensionDecl *ext);
@@ -1221,11 +1230,14 @@
/// will eventually reference that declaration, the contexts will still be
/// considered distinct.
///
- /// The names are generated in the same order as
- /// forEachImportNameVersionFromCurrent. The current name is always first.
+ /// If \p action returns false, the current name will \e not be added to the
+ /// set of seen names.
+ ///
+ /// The active name is always first, followed by the other names in the order
+ /// of ImportNameVersion::forEachOtherImportNameVersion.
void forEachDistinctName(
const clang::NamedDecl *decl,
- llvm::function_ref<void(importer::ImportedName,
+ llvm::function_ref<bool(importer::ImportedName,
importer::ImportNameVersion)> action);
/// Dump the Swift-specific name lookup tables we generate.
diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp
index 176509e..5e4d6f6 100644
--- a/lib/ClangImporter/SwiftLookupTable.cpp
+++ b/lib/ClangImporter/SwiftLookupTable.cpp
@@ -1625,8 +1625,8 @@
}
// If we have a name to import as, add this entry to the table.
- ImportNameVersion currentVersion =
- nameVersionFromOptions(nameImporter.getLangOpts());
+ auto currentVersion =
+ ImportNameVersion::fromOptions(nameImporter.getLangOpts());
if (auto importedName = nameImporter.importName(named, currentVersion)) {
SmallPtrSet<DeclName, 8> distinctNames;
distinctNames.insert(importedName.getDeclName());
@@ -1640,9 +1640,8 @@
ArrayRef<Identifier>()),
named, importedName.getEffectiveContext());
- forEachImportNameVersion([&] (ImportNameVersion alternateVersion) {
- if (alternateVersion == currentVersion)
- return;
+ currentVersion.forEachOtherImportNameVersion(
+ [&](ImportNameVersion alternateVersion) {
auto alternateName = nameImporter.importName(named, alternateVersion);
if (!alternateName)
return;
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index 665b7a2..a46e359 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -1297,15 +1297,65 @@
case 'k': {
auto nodeKind = c == 'K' ? Node::Kind::KeyPathGetterThunkHelper
: Node::Kind::KeyPathSetterThunkHelper;
- auto type = popNode();
- auto sigOrDecl = popNode();
- if (sigOrDecl &&
- sigOrDecl->getKind() == Node::Kind::DependentGenericSignature) {
- auto decl = popNode();
- return createWithChildren(nodeKind, decl, sigOrDecl, type);
+ std::vector<NodePointer> types;
+ auto node = popNode();
+ if (!node || node->getKind() != Node::Kind::Type)
+ return nullptr;
+ do {
+ types.push_back(node);
+ node = popNode();
+ } while (node && node->getKind() == Node::Kind::Type);
+
+ NodePointer result;
+ if (node) {
+ if (node->getKind() == Node::Kind::DependentGenericSignature) {
+ auto decl = popNode();
+ result = createWithChildren(nodeKind, decl, /*sig*/ node);
+ } else {
+ result = createWithChild(nodeKind, /*decl*/ node);
+ }
} else {
- return createWithChildren(nodeKind, sigOrDecl, type);
+ return nullptr;
}
+ for (auto i = types.rbegin(), e = types.rend(); i != e; ++i) {
+ result->addChild(*i, *this);
+ }
+ return result;
+ }
+ case 'H':
+ case 'h': {
+ auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper
+ : Node::Kind::KeyPathHashThunkHelper;
+ NodePointer genericSig = nullptr;
+ std::vector<NodePointer> types;
+
+ auto node = popNode();
+ if (node) {
+ if (node->getKind() == Node::Kind::DependentGenericSignature) {
+ genericSig = node;
+ } else if (node->getKind() == Node::Kind::Type) {
+ types.push_back(node);
+ } else {
+ return nullptr;
+ }
+ } else {
+ return nullptr;
+ }
+
+ while (auto node = popNode()) {
+ if (node->getKind() != Node::Kind::Type) {
+ return nullptr;
+ }
+ types.push_back(node);
+ }
+
+ NodePointer result = createNode(nodeKind);
+ for (auto i = types.rbegin(), e = types.rend(); i != e; ++i) {
+ result->addChild(*i, *this);
+ }
+ if (genericSig)
+ result->addChild(genericSig, *this);
+ return result;
}
case 'v': {
int Idx = demangleIndex();
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 1a617b3..7ed8fae 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -342,6 +342,8 @@
case Node::Kind::Initializer:
case Node::Kind::KeyPathGetterThunkHelper:
case Node::Kind::KeyPathSetterThunkHelper:
+ case Node::Kind::KeyPathEqualsThunkHelper:
+ case Node::Kind::KeyPathHashThunkHelper:
case Node::Kind::LazyProtocolWitnessTableAccessor:
case Node::Kind::LazyProtocolWitnessTableCacheVariable:
case Node::Kind::LocalDeclName:
@@ -1238,6 +1240,29 @@
print(Node->getChild(2));
}
return nullptr;
+ case Node::Kind::KeyPathEqualsThunkHelper:
+ case Node::Kind::KeyPathHashThunkHelper: {
+ Printer << "key path index "
+ << (Node->getKind() == Node::Kind::KeyPathEqualsThunkHelper
+ ? "equality" : "hash")
+ << " operator for ";
+
+ auto lastChild = Node->getChild(Node->getNumChildren() - 1);
+ auto lastType = Node->getNumChildren();
+ if (lastChild->getKind() == Node::Kind::DependentGenericSignature) {
+ print(lastChild);
+ lastType--;
+ }
+
+ Printer << "(";
+ for (unsigned i = 0; i < lastType; ++i) {
+ if (i != 0)
+ Printer << ", ";
+ print(Node->getChild(i));
+ }
+ Printer << ")";
+ return nullptr;
+ }
case Node::Kind::FieldOffset: {
print(Node->getChild(0)); // directness
Printer << "field offset for ";
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index 0f790ca..cb5e0d2 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -1716,6 +1716,16 @@
mangleChildNodes(node);
}
+void Remangler::mangleKeyPathEqualsThunkHelper(Node *node) {
+ Out << "TH";
+ mangleChildNodes(node);
+}
+
+void Remangler::mangleKeyPathHashThunkHelper(Node *node) {
+ Out << "Th";
+ mangleChildNodes(node);
+}
+
void Remangler::mangleProtocolListWithClass(Node *node) {
Out << "Xc";
mangleChildNode(node, 1);
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 13110e5..194fa1c 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -1517,6 +1517,16 @@
Buffer << "Tk";
}
+void Remangler::mangleKeyPathEqualsThunkHelper(Node *node) {
+ mangleChildNodes(node);
+ Buffer << "TH";
+}
+
+void Remangler::mangleKeyPathHashThunkHelper(Node *node) {
+ mangleChildNodes(node);
+ Buffer << "Th";
+}
+
void Remangler::mangleReturnType(Node *node) {
mangleArgumentTuple(node);
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 22bcded..eaff447 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -687,14 +687,6 @@
// serialized ASTs.
Arguments.push_back("-parse-as-library");
- // Merge serialized SIL from partial modules.
- Arguments.push_back("-sil-merge-partial-modules");
-
- // Disable SIL optimization passes; we've already optimized the code in each
- // partial mode.
- Arguments.push_back("-disable-diagnostic-passes");
- Arguments.push_back("-disable-sil-perf-optzns");
-
addCommonFrontendArgs(*this, context.OI, context.Output, context.Args,
Arguments);
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 40461ac..0a12441 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -957,9 +957,6 @@
Opts.EnableExperimentalPropertyBehaviors |=
Args.hasArg(OPT_enable_experimental_property_behaviors);
- Opts.EnableExperimentalKeyPathComponents |=
- Args.hasArg(OPT_enable_experimental_keypath_components);
-
Opts.EnableClassResilience |=
Args.hasArg(OPT_enable_class_resilience);
diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp
index c161dd0..d6465b0 100644
--- a/lib/IDE/SyntaxModel.cpp
+++ b/lib/IDE/SyntaxModel.cpp
@@ -165,6 +165,15 @@
break;
}
+ case tok::unknown: {
+ if (Tok.getRawText().startswith("\"")) {
+ // This is an invalid string literal
+ Kind = SyntaxNodeKind::String;
+ break;
+ }
+ continue;
+ }
+
default:
continue;
}
diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp
index 4558772..3f789d9 100644
--- a/lib/IRGen/GenHeap.cpp
+++ b/lib/IRGen/GenHeap.cpp
@@ -837,7 +837,7 @@
/// Emit a unary call to perform a ref-counting operation.
///
-/// \param fn - expected signature 'void (T)'
+/// \param fn - expected signature 'void (T)' or 'T (T)'
static void emitUnaryRefCountCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *value) {
@@ -847,9 +847,13 @@
// Instead of casting the input, we cast the function type.
// This tends to produce less IR, but might be evil.
- if (value->getType() != getTypeOfFunction(fn)->getParamType(0)) {
+ auto origFnType = getTypeOfFunction(fn);
+ if (value->getType() != origFnType->getParamType(0)) {
+ auto resultTy = origFnType->getReturnType() == IGF.IGM.VoidTy
+ ? IGF.IGM.VoidTy
+ : value->getType();
llvm::FunctionType *fnType =
- llvm::FunctionType::get(IGF.IGM.VoidTy, value->getType(), false);
+ llvm::FunctionType::get(resultTy, value->getType(), false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
}
@@ -861,7 +865,7 @@
/// Emit a copy-like call to perform a ref-counting operation.
///
-/// \param fn - expected signature 'void (T, T)'
+/// \param fn - expected signature 'void (T, T)' or 'T (T, T)'
static void emitCopyLikeCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *dest,
@@ -875,10 +879,14 @@
// Instead of casting the inputs, we cast the function type.
// This tends to produce less IR, but might be evil.
- if (dest->getType() != getTypeOfFunction(fn)->getParamType(0)) {
+ auto origFnType = getTypeOfFunction(fn);
+ if (dest->getType() != origFnType->getParamType(0)) {
llvm::Type *paramTypes[] = { dest->getType(), dest->getType() };
+ auto resultTy = origFnType->getReturnType() == IGF.IGM.VoidTy
+ ? IGF.IGM.VoidTy
+ : dest->getType();
llvm::FunctionType *fnType =
- llvm::FunctionType::get(IGF.IGM.VoidTy, paramTypes, false);
+ llvm::FunctionType::get(resultTy, paramTypes, false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
}
@@ -923,7 +931,7 @@
/// Emit a call to a function with a storeWeak-like signature.
///
-/// \param fn - expected signature 'void (Weak*, T)'
+/// \param fn - expected signature 'void (Weak*, T)' or 'Weak* (Weak*, T)'
static void emitStoreWeakLikeCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *addr,
@@ -938,10 +946,14 @@
// Instead of casting the inputs, we cast the function type.
// This tends to produce less IR, but might be evil.
- if (value->getType() != getTypeOfFunction(fn)->getParamType(1)) {
+ auto origFnType = getTypeOfFunction(fn);
+ if (value->getType() != origFnType->getParamType(1)) {
llvm::Type *paramTypes[] = { addr->getType(), value->getType() };
+ auto resultTy = origFnType->getReturnType() == IGF.IGM.VoidTy
+ ? IGF.IGM.VoidTy
+ : addr->getType();
llvm::FunctionType *fnType =
- llvm::FunctionType::get(IGF.IGM.VoidTy, paramTypes, false);
+ llvm::FunctionType::get(resultTy, paramTypes, false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
}
diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp
index d58f606..3ecaad2 100644
--- a/lib/IRGen/GenKeyPath.cpp
+++ b/lib/IRGen/GenKeyPath.cpp
@@ -30,6 +30,7 @@
#include "MetadataLayout.h"
#include "ProtocolInfo.h"
#include "StructLayout.h"
+#include "TypeInfo.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/IR/Module.h"
#include "swift/SIL/SILInstruction.h"
@@ -47,15 +48,46 @@
using namespace swift;
using namespace irgen;
-enum GetterOrSetter {
+enum KeyPathAccessor {
Getter,
Setter,
+ Equals,
+ Hash,
};
+static void
+bindPolymorphicArgumentsFromComponentIndices(IRGenFunction &IGF,
+ const KeyPathPatternComponent &component,
+ GenericEnvironment *genericEnv,
+ ArrayRef<GenericRequirement> requirements,
+ llvm::Value *args,
+ llvm::Value *size) {
+ if (!genericEnv)
+ return;
+
+ // The generic environment is marshaled into the end of the component
+ // argument area inside the instance. Bind the generic information out of
+ // the buffer.
+ if (!component.getComputedPropertyIndices().empty()) {
+ auto genericArgsSize = llvm::ConstantInt::get(IGF.IGM.SizeTy,
+ requirements.size() * IGF.IGM.getPointerSize().getValue());
+
+ auto genericArgsOffset = IGF.Builder.CreateSub(size, genericArgsSize);
+ args = IGF.Builder.CreateInBoundsGEP(args, genericArgsOffset);
+ }
+ bindFromGenericRequirementsBuffer(IGF, requirements,
+ Address(args, IGF.IGM.getPointerAlignment()),
+ [&](CanType t) {
+ if (!genericEnv)
+ return t;
+ return genericEnv->mapTypeIntoContext(t)->getCanonicalType();
+ });
+}
+
static llvm::Function *
getAccessorForComputedComponent(IRGenModule &IGM,
const KeyPathPatternComponent &component,
- GetterOrSetter whichAccessor,
+ KeyPathAccessor whichAccessor,
GenericEnvironment *genericEnv,
ArrayRef<GenericRequirement> requirements) {
SILFunction *accessor;
@@ -66,6 +98,12 @@
case Setter:
accessor = component.getComputedPropertySetter();
break;
+ case Equals:
+ accessor = component.getComputedPropertyIndexEquals();
+ break;
+ case Hash:
+ accessor = component.getComputedPropertyIndexHash();
+ break;
}
auto accessorFn = IGM.getAddrOfSILFunction(accessor, NotForDefinition);
@@ -80,37 +118,75 @@
// Otherwise, we need a thunk to unmarshal the generic environment from the
// argument area. It'd be nice to have a good way to represent this
// directly in SIL, of course...
- auto thunkType = llvm::FunctionType::get(
- IGM.VoidTy,
- { /*sret or newValue*/ accessorFnTy->getFunctionParamType(0),
- /*base*/ accessorFnTy->getFunctionParamType(1),
- /*arg*/ IGM.Int8PtrTy },
- /*vararg*/ false);
const char *thunkName;
- unsigned numArgsToForward = 2;
+ unsigned numArgsToForward;
+
switch (whichAccessor) {
case Getter:
thunkName = "keypath_get";
+ numArgsToForward = 2;
break;
case Setter:
thunkName = "keypath_set";
+ numArgsToForward = 2;
+ break;
+ case Equals:
+ thunkName = "keypath_equals";
+ numArgsToForward = 2;
+ break;
+ case Hash:
+ thunkName = "keypath_hash";
+ numArgsToForward = 1;
break;
}
+
+ SmallVector<llvm::Type *, 4> thunkParams;
+ for (unsigned i = 0; i < numArgsToForward; ++i)
+ thunkParams.push_back(accessorFnTy->getFunctionParamType(i));
+
+ switch (whichAccessor) {
+ case Getter:
+ case Setter:
+ thunkParams.push_back(IGM.Int8PtrTy);
+ break;
+ case Equals:
+ case Hash:
+ break;
+ }
+ thunkParams.push_back(IGM.SizeTy);
+
+ auto thunkType = llvm::FunctionType::get(IGM.VoidTy, thunkParams,
+ /*vararg*/ false);
auto accessorThunk = llvm::Function::Create(thunkType,
llvm::GlobalValue::PrivateLinkage, thunkName, IGM.getModule());
accessorThunk->setAttributes(IGM.constructInitialAttributes());
- // Original accessor's args should be @in or @out, meaning they won't be
- // captured or aliased.
- accessorThunk->addAttribute(1, llvm::Attribute::NoCapture);
- accessorThunk->addAttribute(1, llvm::Attribute::NoAlias);
- accessorThunk->addAttribute(2, llvm::Attribute::NoCapture);
- accessorThunk->addAttribute(2, llvm::Attribute::NoAlias);
- // Getter's output is sret.
- if (whichAccessor == Getter)
- accessorThunk->addAttribute(1, llvm::Attribute::StructRet);
accessorThunk->setCallingConv(IGM.SwiftCC);
-
+
+ switch (whichAccessor) {
+ case Getter:
+ // Original accessor's args should be @in or @out, meaning they won't be
+ // captured or aliased.
+ accessorThunk->addAttribute(1, llvm::Attribute::NoCapture);
+ accessorThunk->addAttribute(1, llvm::Attribute::NoAlias);
+ accessorThunk->addAttribute(2, llvm::Attribute::NoCapture);
+ accessorThunk->addAttribute(2, llvm::Attribute::NoAlias);
+ // Output is sret.
+ accessorThunk->addAttribute(1, llvm::Attribute::StructRet);
+ break;
+ case Setter:
+ // Original accessor's args should be @in or @out, meaning they won't be
+ // captured or aliased.
+ accessorThunk->addAttribute(1, llvm::Attribute::NoCapture);
+ accessorThunk->addAttribute(1, llvm::Attribute::NoAlias);
+ accessorThunk->addAttribute(2, llvm::Attribute::NoCapture);
+ accessorThunk->addAttribute(2, llvm::Attribute::NoAlias);
+ break;
+ case Equals:
+ case Hash:
+ break;
+ }
+
{
IRGenFunction IGF(IGM, accessorThunk);
if (IGM.DebugInfo)
@@ -120,29 +196,37 @@
Explosion forwardedArgs;
forwardedArgs.add(params.claim(numArgsToForward));
- // The generic environment is marshaled into the beginning of the component
- // argument area inside the instance. Bind the generic information out of
- // the buffer, and advance past it.
- auto componentArgsBuf = params.claimNext();
- bindFromGenericRequirementsBuffer(IGF, requirements,
- Address(componentArgsBuf, IGM.getPointerAlignment()),
- [&](CanType t) {
- if (!genericEnv)
- return t;
- return genericEnv->mapTypeIntoContext(t)->getCanonicalType();
- });
-
- /* TODO: If the underlying accessor wants index arguments, advance the
- * pointer past the generic requirements here to pass down. */
-
+ llvm::Value *componentArgsBuf;
+ switch (whichAccessor) {
+ case Getter:
+ case Setter:
+ // The component arguments are passed alongside the base being projected.
+ componentArgsBuf = params.claimNext();
+ // Pass the argument pointer down to the underlying function.
+ if (!component.getComputedPropertyIndices().empty()) {
+ forwardedArgs.add(componentArgsBuf);
+ }
+ break;
+ case Equals:
+ case Hash:
+ // We're operating directly on the component argument buffer.
+ componentArgsBuf = forwardedArgs.getAll()[0];
+ break;
+ }
+ auto componentArgsBufSize = params.claimNext();
+ bindPolymorphicArgumentsFromComponentIndices(IGF, component,
+ genericEnv, requirements,
+ componentArgsBuf,
+ componentArgsBufSize);
+
// Use the bound generic metadata to form a call to the original generic
// accessor.
- WitnessMetadata witnessMetadata;
+ WitnessMetadata ignoreWitnessMetadata;
auto forwardingSubs = genericEnv->getGenericSignature()->getSubstitutionMap(
genericEnv->getForwardingSubstitutions());
emitPolymorphicArguments(IGF, accessor->getLoweredFunctionType(),
forwardingSubs,
- &witnessMetadata,
+ &ignoreWitnessMetadata,
forwardedArgs);
auto fnPtr = FunctionPointer::forDirect(IGM, accessorFn,
accessor->getLoweredFunctionType());
@@ -171,19 +255,55 @@
{
IRGenFunction IGF(IGM, layoutFn);
- // TODO: We would need to unmarshal generic arguments to be able to
- // compute the layout of dependent subscript indexes.
- (void)IGF.collectParameters().claimNext();
+ // Unmarshal the generic environment from the argument buffer.
+ auto parameters = IGF.collectParameters();
+ auto args = parameters.claimNext();
- // Base size is one pointer for each generic requirement; base alignment
- // is pointer alignment.
- llvm::Value *size = llvm::ConstantInt::get(IGM.SizeTy,
- IGM.getPointerSize().getValue() * requirements.size());
- llvm::Value *alignMask = llvm::ConstantInt::get(IGM.SizeTy,
- IGM.getPointerAlignment().getValue() - 1);
+ if (genericEnv) {
+ bindFromGenericRequirementsBuffer(IGF, requirements,
+ Address(args, IGF.IGM.getPointerAlignment()),
+ [&](CanType t) {
+ if (!genericEnv)
+ return t;
+ return genericEnv->mapTypeIntoContext(t)->getCanonicalType();
+ });
+ }
+
+ // Run through the captured index types to determine the size and alignment
+ // needed. Start with pointer alignment for the generic environment.
+ llvm::Value *size = llvm::ConstantInt::get(IGM.SizeTy, 0);
+ llvm::Value *alignMask = llvm::ConstantInt::get(IGM.SizeTy, 0);
+
+ for (auto &index : component.getComputedPropertyIndices()) {
+ auto ty = genericEnv
+ ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), index.LoweredType)
+ : index.LoweredType;
+ auto &ti = IGM.getTypeInfo(ty);
+ auto indexSize = ti.getSize(IGF, ty);
+ auto indexAlign = ti.getAlignmentMask(IGF, ty);
- // TODO: Combine layout of captured index values
+ auto notIndexAlign = IGF.Builder.CreateNot(indexAlign);
+
+ size = IGF.Builder.CreateAdd(size, indexAlign);
+ size = IGF.Builder.CreateAnd(size, notIndexAlign);
+ size = IGF.Builder.CreateAdd(size, indexSize);
+
+ alignMask = IGF.Builder.CreateOr(alignMask, indexAlign);
+ }
+ // If there's generic environment to capture, then it's stored as a block
+ // of pointer-aligned words after the captured values.
+
+ auto genericsSize = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerSize().getValue() * requirements.size());
+ auto genericsAlign = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerAlignment().getValue() - 1);
+ auto notGenericsAlign = llvm::ConstantExpr::getNot(genericsAlign);
+ size = IGF.Builder.CreateAdd(size, genericsAlign);
+ size = IGF.Builder.CreateAnd(size, notGenericsAlign);
+ size = IGF.Builder.CreateAdd(size, genericsSize);
+ alignMask = IGF.Builder.CreateOr(alignMask, genericsAlign);
+
llvm::Value *retValue = IGF.Builder.CreateInsertValue(
llvm::UndefValue::get(retTy), size, 0);
retValue = IGF.Builder.CreateInsertValue(
@@ -202,27 +322,184 @@
ArrayRef<GenericRequirement> requirements) {
// If the only thing we're capturing is generic environment, then we can
// use a prefab witness table from the runtime.
- // TODO: If there were subscript indexes, we'd need to generate something.
- if (auto existing =
- IGM.Module.getNamedGlobal("swift_keyPathGenericWitnessTable"))
- return existing;
+ if (component.getComputedPropertyIndices().empty()) {
+ if (auto existing =
+ IGM.Module.getNamedGlobal("swift_keyPathGenericWitnessTable"))
+ return existing;
+
+ auto linkInfo = LinkInfo::get(IGM, "swift_keyPathGenericWitnessTable",
+ SILLinkage::PublicExternal,
+ /*fragile*/ false,
+ /*sil only*/ false,
+ NotForDefinition,
+ /*weak imported*/ false);
+
+ return createVariable(IGM, linkInfo,
+ IGM.Int8PtrTy, IGM.getPointerAlignment());
+ }
- auto linkInfo = LinkInfo::get(IGM, "swift_keyPathGenericWitnessTable",
- SILLinkage::PublicExternal,
- /*fragile*/ false,
- /*sil only*/ false,
- NotForDefinition,
- /*weak imported*/ false);
+ // Are the index values trivial?
+ bool isTrivial = true;
+ for (auto &component : component.getComputedPropertyIndices()) {
+ auto ty = genericEnv
+ ? genericEnv->mapTypeIntoContext(IGM.getSILModule(), component.LoweredType)
+ : component.LoweredType;
+ auto &ti = IGM.getTypeInfo(ty);
+ isTrivial &= ti.isPOD(ResilienceExpansion::Minimal);
+ }
- return createVariable(IGM, linkInfo,
- IGM.Int8PtrTy, IGM.getPointerAlignment());
+ llvm::Constant *destroy;
+ llvm::Constant *copy;
+ if (isTrivial) {
+ // We can use prefab witnesses for handling trivial copying and destruction.
+ // A null destructor witness signals that the payload is trivial.
+ destroy = llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
+ copy = IGM.getCopyKeyPathTrivialIndicesFn();
+ } else {
+ // Generate a destructor for this set of indices.
+ {
+ auto destroyType = llvm::FunctionType::get(IGM.VoidTy,
+ {IGM.Int8PtrTy, IGM.SizeTy},
+ /*vararg*/ false);
+ auto destroyFn = llvm::Function::Create(destroyType,
+ llvm::GlobalValue::PrivateLinkage, "keypath_destroy", IGM.getModule());
+ destroy = destroyFn;
+
+ IRGenFunction IGF(IGM, destroyFn);
+ if (IGM.DebugInfo)
+ IGM.DebugInfo->emitArtificialFunction(IGF, destroyFn);
+
+ auto params = IGF.collectParameters();
+ auto componentArgsBuf = params.claimNext();
+ auto componentArgsBufSize = params.claimNext();
+ bindPolymorphicArgumentsFromComponentIndices(IGF, component,
+ genericEnv, requirements,
+ componentArgsBuf,
+ componentArgsBufSize);
+
+ llvm::Value *offset = nullptr;
+ for (auto &component : component.getComputedPropertyIndices()) {
+ auto ty = genericEnv
+ ? genericEnv->mapTypeIntoContext(IGM.getSILModule(),
+ component.LoweredType)
+ : component.LoweredType;
+ auto &ti = IGM.getTypeInfo(ty);
+ if (offset) {
+ auto align = ti.getAlignmentMask(IGF, ty);
+ auto notAlign = IGF.Builder.CreateNot(align);
+ offset = IGF.Builder.CreateAdd(offset, align);
+ offset = IGF.Builder.CreateAnd(offset, notAlign);
+ } else {
+ offset = llvm::ConstantInt::get(IGM.SizeTy, 0);
+ }
+ auto elt = IGF.Builder.CreateInBoundsGEP(componentArgsBuf, offset);
+ auto eltAddr = ti.getAddressForPointer(
+ IGF.Builder.CreateBitCast(elt, ti.getStorageType()->getPointerTo()));
+ ti.destroy(IGF, eltAddr, ty);
+ auto size = ti.getSize(IGF, ty);
+ offset = IGF.Builder.CreateAdd(offset, size);
+ }
+ IGF.Builder.CreateRetVoid();
+ }
+ // Generate a copier for this set of indices.
+ {
+ auto copyType = llvm::FunctionType::get(IGM.VoidTy,
+ {IGM.Int8PtrTy, IGM.Int8PtrTy,
+ IGM.SizeTy},
+ /*vararg*/ false);
+ auto copyFn = llvm::Function::Create(copyType,
+ llvm::GlobalValue::PrivateLinkage, "keypath_copy", IGM.getModule());
+ copy = copyFn;
+
+ IRGenFunction IGF(IGM, copyFn);
+ if (IGM.DebugInfo)
+ IGM.DebugInfo->emitArtificialFunction(IGF, copyFn);
+
+ auto params = IGF.collectParameters();
+ auto sourceArgsBuf = params.claimNext();
+ auto destArgsBuf = params.claimNext();
+ auto componentArgsBufSize = params.claimNext();
+ bindPolymorphicArgumentsFromComponentIndices(IGF, component,
+ genericEnv, requirements,
+ sourceArgsBuf,
+ componentArgsBufSize);
+
+ // Copy over the index values.
+ llvm::Value *offset = nullptr;
+ for (auto &component : component.getComputedPropertyIndices()) {
+ auto ty = genericEnv
+ ? genericEnv->mapTypeIntoContext(IGM.getSILModule(),
+ component.LoweredType)
+ : component.LoweredType;
+ auto &ti = IGM.getTypeInfo(ty);
+ if (offset) {
+ auto align = ti.getAlignmentMask(IGF, ty);
+ auto notAlign = IGF.Builder.CreateNot(align);
+ offset = IGF.Builder.CreateAdd(offset, align);
+ offset = IGF.Builder.CreateAnd(offset, notAlign);
+ } else {
+ offset = llvm::ConstantInt::get(IGM.SizeTy, 0);
+ }
+ auto sourceElt = IGF.Builder.CreateInBoundsGEP(sourceArgsBuf, offset);
+ auto destElt = IGF.Builder.CreateInBoundsGEP(destArgsBuf, offset);
+ auto sourceEltAddr = ti.getAddressForPointer(
+ IGF.Builder.CreateBitCast(sourceElt,
+ ti.getStorageType()->getPointerTo()));
+ auto destEltAddr = ti.getAddressForPointer(
+ IGF.Builder.CreateBitCast(destElt,
+ ti.getStorageType()->getPointerTo()));
+
+ ti.initializeWithCopy(IGF, destEltAddr, sourceEltAddr, ty);
+ auto size = ti.getSize(IGF, ty);
+ offset = IGF.Builder.CreateAdd(offset, size);
+ }
+
+ // Copy over the generic environment.
+ if (genericEnv) {
+ auto envAlignMask = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerAlignment().getMaskValue());
+ auto notAlignMask = IGF.Builder.CreateNot(envAlignMask);
+ offset = IGF.Builder.CreateAdd(offset, envAlignMask);
+ offset = IGF.Builder.CreateAnd(offset, notAlignMask);
+
+ auto sourceEnv = IGF.Builder.CreateInBoundsGEP(sourceArgsBuf, offset);
+ auto destEnv = IGF.Builder.CreateInBoundsGEP(destArgsBuf, offset);
+
+ IGF.Builder.CreateMemCpy(destEnv, sourceEnv,
+ IGM.getPointerSize().getValue() * requirements.size(),
+ IGM.getPointerAlignment().getValue());
+ }
+
+ IGF.Builder.CreateRetVoid();
+ }
+ }
+
+ auto equals = getAccessorForComputedComponent(IGM, component, Equals,
+ genericEnv, requirements);
+ auto hash = getAccessorForComputedComponent(IGM, component, Hash,
+ genericEnv, requirements);
+
+ auto witnesses = llvm::ConstantStruct::getAnon({destroy, copy, equals, hash});
+ return new llvm::GlobalVariable(IGM.Module, witnesses->getType(),
+ /*constant*/ true,
+ llvm::GlobalValue::PrivateLinkage,
+ witnesses,
+ "keypath_witnesses");
}
+/// Information about each index operand for a key path pattern that is used
+/// to lay out and consume the argument packet.
+struct KeyPathIndexOperand {
+ SILType LoweredType;
+ const KeyPathPatternComponent *LastUser;
+};
+
static llvm::Constant *
getInitializerForComputedComponent(IRGenModule &IGM,
- const KeyPathPatternComponent &component,
- GenericEnvironment *genericEnv,
- ArrayRef<GenericRequirement> requirements) {
+ const KeyPathPatternComponent &component,
+ ArrayRef<KeyPathIndexOperand> operands,
+ GenericEnvironment *genericEnv,
+ ArrayRef<GenericRequirement> requirements) {
auto fnTy = llvm::FunctionType::get(IGM.VoidTy,
{ /*src*/ IGM.Int8PtrTy,
/*dest*/ IGM.Int8PtrTy }, /*vararg*/ false);
@@ -233,16 +510,113 @@
{
IRGenFunction IGF(IGM, initFn);
auto params = IGF.collectParameters();
+ // Pointer to the argument packet passed into swift_getKeyPath
auto src = params.claimNext();
+ // Pointer to the destination component's argument buffer
auto dest = params.claimNext();
- // Transfer all of the requirements into the destination instance.
- IGF.Builder.CreateMemCpy(dest, src,
- IGM.getPointerSize().getValue() * requirements.size(),
- IGM.getPointerAlignment().getValue());
+ SmallVector<Address, 4> srcAddresses;
+ int lastOperandNeeded = -1;
+ for (auto &index : component.getComputedPropertyIndices()) {
+ lastOperandNeeded = std::max(lastOperandNeeded, (int)index.Operand);
+ }
- // TODO: Copy over subscript index values.
+ llvm::Value *offset;
+ if (genericEnv) {
+ // We'll copy over the generic environment after we copy in the indexes.
+ offset = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerSize().getValue() * requirements.size());
+
+ // Bind the generic environment from the argument buffer.
+ bindFromGenericRequirementsBuffer(IGF, requirements,
+ Address(src, IGF.IGM.getPointerAlignment()),
+ [&](CanType t) {
+ if (!genericEnv)
+ return t;
+ return genericEnv->mapTypeIntoContext(t)->getCanonicalType();
+ });
+
+ } else {
+ offset = llvm::ConstantInt::get(IGM.SizeTy, 0);
+ }
+
+ // Figure out the offsets of the operands in the source buffer.
+ for (int i = 0; i <= lastOperandNeeded; ++i) {
+ auto ty = genericEnv
+ ? genericEnv->mapTypeIntoContext(IGM.getSILModule(),
+ operands[i].LoweredType)
+ : operands[i].LoweredType;
+
+ auto &ti = IGM.getTypeInfo(ty);
+
+ if (i != 0 || genericEnv) {
+ auto alignMask = ti.getAlignmentMask(IGF, ty);
+ auto notAlignMask = IGF.Builder.CreateNot(alignMask);
+ offset = IGF.Builder.CreateAdd(offset, alignMask);
+ offset = IGF.Builder.CreateAnd(offset, notAlignMask);
+ }
+
+ auto ptr = IGF.Builder.CreateInBoundsGEP(src, offset);
+ auto addr = ti.getAddressForPointer(IGF.Builder.CreateBitCast(
+ ptr, ti.getStorageType()->getPointerTo()));
+ srcAddresses.push_back(addr);
+
+ auto size = ti.getSize(IGF, ty);
+ offset = IGF.Builder.CreateAdd(offset, size);
+ }
+
+ offset = llvm::ConstantInt::get(IGM.SizeTy, 0);
+
+ // Transfer the operands we want into the destination buffer.
+ for (unsigned i : indices(component.getComputedPropertyIndices())) {
+ auto &index = component.getComputedPropertyIndices()[i];
+
+ auto ty = genericEnv
+ ? genericEnv->mapTypeIntoContext(IGM.getSILModule(),
+ index.LoweredType)
+ : index.LoweredType;
+
+ auto &ti = IGM.getTypeInfo(ty);
+
+ if (i != 0) {
+ auto alignMask = ti.getAlignmentMask(IGF, ty);
+ auto notAlignMask = IGF.Builder.CreateNot(alignMask);
+ offset = IGF.Builder.CreateAdd(offset, alignMask);
+ offset = IGF.Builder.CreateAnd(offset, notAlignMask);
+ }
+
+ auto ptr = IGF.Builder.CreateInBoundsGEP(dest, offset);
+ auto destAddr = ti.getAddressForPointer(IGF.Builder.CreateBitCast(
+ ptr, ti.getStorageType()->getPointerTo()));
+
+ // The last component using an operand can move the value out of the
+ // buffer.
+ if (&component == operands[index.Operand].LastUser) {
+ ti.initializeWithTake(IGF, destAddr, srcAddresses[index.Operand], ty);
+ } else {
+ ti.initializeWithCopy(IGF, destAddr, srcAddresses[index.Operand], ty);
+ }
+ auto size = ti.getSize(IGF, ty);
+ offset = IGF.Builder.CreateAdd(offset, size);
+ }
+
+ // Transfer the generic environment.
+ if (genericEnv) {
+ auto destGenericEnv = dest;
+ if (!component.getComputedPropertyIndices().empty()) {
+ auto genericEnvAlignMask = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerAlignment().getMaskValue());
+ auto notGenericEnvAlignMask = IGF.Builder.CreateNot(genericEnvAlignMask);
+ offset = IGF.Builder.CreateAdd(offset, genericEnvAlignMask);
+ offset = IGF.Builder.CreateAnd(offset, notGenericEnvAlignMask);
+ destGenericEnv = IGF.Builder.CreateInBoundsGEP(dest, offset);
+ }
+
+ IGF.Builder.CreateMemCpy(destGenericEnv, src,
+ IGM.getPointerSize().getValue() * requirements.size(),
+ IGM.getPointerAlignment().getValue());
+ }
IGF.Builder.CreateRetVoid();
}
return initFn;
@@ -374,6 +748,28 @@
&& "must be pointer-aligned here");
};
+ // Collect the order and types of any captured index operands, which will
+ // determine the layout of the buffer that gets passed to the initializer
+ // for each component.
+ SmallVector<KeyPathIndexOperand, 4> operands;
+ operands.resize(pattern->getNumOperands());
+ for (auto &component : pattern->getComponents()) {
+ switch (component.getKind()) {
+ case KeyPathPatternComponent::Kind::GettableProperty:
+ case KeyPathPatternComponent::Kind::SettableProperty:
+ for (auto &index : component.getComputedPropertyIndices()) {
+ operands[index.Operand].LoweredType = index.LoweredType;
+ operands[index.Operand].LastUser = &component;
+ }
+ break;
+ case KeyPathPatternComponent::Kind::StoredProperty:
+ case KeyPathPatternComponent::Kind::OptionalChain:
+ case KeyPathPatternComponent::Kind::OptionalForce:
+ case KeyPathPatternComponent::Kind::OptionalWrap:
+ break;
+ }
+ }
+
for (unsigned i : indices(pattern->getComponents())) {
assertPointerAlignment();
SILType loweredBaseTy;
@@ -585,7 +981,7 @@
fields.add(getAddrOfSILFunction(component.getComputedPropertySetter(),
NotForDefinition));
} else {
- // If there's generic context (TODO: or subscript indexes), embed as
+ // If there's generic context or subscript indexes, embed as
// arguments in the component. Thunk the SIL-level accessors to give the
// runtime implementation a polymorphically-callable interface.
@@ -611,7 +1007,7 @@
// Add an initializer function that copies generic arguments out of the
// pattern argument buffer into the instantiated object.
- fields.add(getInitializerForComputedComponent(*this, component,
+ fields.add(getInitializerForComputedComponent(*this, component, operands,
genericEnv, requirements));
}
break;
@@ -657,4 +1053,3 @@
KeyPathPatterns.insert({pattern, patternVar});
return patternVar;
}
-
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index 33e2b70..9252938 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -4597,25 +4597,76 @@
auto pattern = IGM.getAddrOfKeyPathPattern(I->getPattern(), I->getLoc());
// Build up the argument vector to instantiate the pattern here.
llvm::Value *args;
- if (!I->getSubstitutions().empty()) {
+ if (!I->getSubstitutions().empty() || !I->getAllOperands().empty()) {
auto sig = I->getPattern()->getGenericSignature();
- auto subs = sig->getSubstitutionMap(I->getSubstitutions());
+ SubstitutionMap subs;
+ if (sig)
+ subs = sig->getSubstitutionMap(I->getSubstitutions());
SmallVector<GenericRequirement, 4> requirements;
enumerateGenericSignatureRequirements(sig,
[&](GenericRequirement reqt) { requirements.push_back(reqt); });
- auto argsBufTy = llvm::ArrayType::get(IGM.TypeMetadataPtrTy,
- requirements.size());
- auto argsBuf = createAlloca(argsBufTy, IGM.getPointerAlignment(),
- "keypath_args");
- emitInitOfGenericRequirementsBuffer(*this, requirements, argsBuf,
- [&](GenericRequirement reqt) -> llvm::Value * {
- return emitGenericRequirementFromSubstitutions(*this, sig,
- *IGM.getSwiftModule(),
- reqt, subs);
- });
- args = Builder.CreateBitCast(argsBuf.getAddress(), IGM.Int8PtrTy);
+ llvm::Value *argsBufSize;
+ llvm::Value *argsBufAlign;
+
+ if (!I->getSubstitutions().empty()) {
+ argsBufSize = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerSize().getValue() * requirements.size());
+ argsBufAlign = llvm::ConstantInt::get(IGM.SizeTy,
+ IGM.getPointerAlignment().getMaskValue());
+ } else {
+ argsBufSize = llvm::ConstantInt::get(IGM.SizeTy, 0);
+ argsBufAlign = llvm::ConstantInt::get(IGM.SizeTy, 0);
+ }
+
+ SmallVector<llvm::Value *, 4> operandOffsets;
+ for (unsigned i : indices(I->getAllOperands())) {
+ auto operand = I->getAllOperands()[i].get();
+ auto &ti = getTypeInfo(operand->getType());
+ auto ty = operand->getType();
+ auto alignMask = ti.getAlignmentMask(*this, ty);
+ if (i != 0) {
+ auto notAlignMask = Builder.CreateNot(alignMask);
+ argsBufSize = Builder.CreateAdd(argsBufSize, alignMask);
+ argsBufSize = Builder.CreateAnd(argsBufSize, notAlignMask);
+ }
+ operandOffsets.push_back(argsBufSize);
+ auto size = ti.getSize(*this, ty);
+ argsBufSize = Builder.CreateAdd(argsBufSize, size);
+ argsBufAlign = Builder.CreateOr(argsBufAlign, alignMask);
+ }
+
+ auto argsBufInst = Builder.CreateAlloca(IGM.Int8Ty, argsBufSize);
+ // TODO: over-alignment?
+ argsBufInst->setAlignment(16);
+
+ Address argsBuf(argsBufInst, Alignment(16));
+
+ if (!I->getSubstitutions().empty()) {
+ emitInitOfGenericRequirementsBuffer(*this, requirements, argsBuf,
+ [&](GenericRequirement reqt) -> llvm::Value * {
+ return emitGenericRequirementFromSubstitutions(*this, sig,
+ *IGM.getSwiftModule(),
+ reqt, subs);
+ });
+ }
+
+ for (unsigned i : indices(I->getAllOperands())) {
+ auto operand = I->getAllOperands()[i].get();
+ auto &ti = getTypeInfo(operand->getType());
+ auto ptr = Builder.CreateInBoundsGEP(argsBufInst, operandOffsets[i]);
+ auto addr = ti.getAddressForPointer(
+ Builder.CreateBitCast(ptr, ti.getStorageType()->getPointerTo()));
+ if (operand->getType().isAddress()) {
+ ti.initializeWithTake(*this, addr, getLoweredAddress(operand),
+ operand->getType());
+ } else {
+ Explosion operandValue = getLoweredExplosion(operand);
+ cast<LoadableTypeInfo>(ti).initialize(*this, operandValue, addr);
+ }
+ }
+ args = argsBufInst;
} else {
// No arguments necessary, so the argument ought to be ignored by any
// callbacks in the pattern.
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index fae55b8..0e1526f 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -27,6 +27,7 @@
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
+#include "swift/SIL/TypeLowering.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -139,7 +140,7 @@
SILModule &SILMod;
SILParserTUState &TUState;
SILFunction *F = nullptr;
- GenericEnvironment *GenericEnv = nullptr;
+ GenericEnvironment *ContextGenericEnv = nullptr;
FunctionOwnershipEvaluator OwnershipEvaluator;
private:
@@ -281,6 +282,12 @@
TypeLoc = P.Tok.getLoc();
return parseASTType(result);
}
+ bool parseASTType(CanType &result,
+ SourceLoc &TypeLoc,
+ GenericEnvironment *env) {
+ TypeLoc = P.Tok.getLoc();
+ return parseASTType(result, env);
+ }
bool parseSILOwnership(ValueOwnershipKind &OwnershipKind) {
// We parse here @ <identifier>.
if (!P.consumeIf(tok::at_sign)) {
@@ -294,8 +301,9 @@
diag::expected_sil_value_ownership_kind);
}
bool parseSILType(SILType &Result,
- GenericEnvironment *&genericEnv,
- bool IsFuncDecl = false);
+ GenericEnvironment *&parsedGenericEnv,
+ bool IsFuncDecl = false,
+ GenericEnvironment *parentGenericEnv = nullptr);
bool parseSILType(SILType &Result) {
GenericEnvironment *IgnoredEnv;
return parseSILType(Result, IgnoredEnv);
@@ -305,9 +313,10 @@
return parseSILType(Result);
}
bool parseSILType(SILType &Result, SourceLoc &TypeLoc,
- GenericEnvironment *&GenericEnv) {
+ GenericEnvironment *&parsedGenericEnv,
+ GenericEnvironment *parentGenericEnv = nullptr) {
TypeLoc = P.Tok.getLoc();
- return parseSILType(Result, GenericEnv);
+ return parseSILType(Result, parsedGenericEnv, false, parentGenericEnv);
}
/// @}
@@ -971,7 +980,7 @@
"Unexpected stage during parsing!");
if (GenericEnv == nullptr)
- GenericEnv = this->GenericEnv;
+ GenericEnv = ContextGenericEnv;
if (!DC)
DC = &P.SF;
@@ -1041,9 +1050,10 @@
/// '$' '*'? attribute-list (generic-params)? type
///
bool SILParser::parseSILType(SILType &Result,
- GenericEnvironment *&GenericEnv,
- bool IsFuncDecl){
- GenericEnv = nullptr;
+ GenericEnvironment *&ParsedGenericEnv,
+ bool IsFuncDecl,
+ GenericEnvironment *OuterGenericEnv) {
+ ParsedGenericEnv = nullptr;
if (P.parseToken(tok::sil_dollar, diag::expected_sil_type))
return true;
@@ -1108,12 +1118,12 @@
// Save the top-level function generic environment if there was one.
if (auto fnType = dyn_cast<FunctionTypeRepr>(TyR.get()))
if (auto env = fnType->getGenericEnvironment())
- GenericEnv = env;
+ ParsedGenericEnv = env;
// Apply attributes to the type.
TypeLoc Ty = P.applyAttributeToType(TyR.get(), attrs, specifier, specifierLoc);
- if (performTypeLocChecking(Ty, /*IsSILType=*/true, nullptr))
+ if (performTypeLocChecking(Ty, /*IsSILType=*/true, OuterGenericEnv))
return true;
Result = SILType::getPrimitiveType(Ty.getType()->getCanonicalType(),
@@ -2417,6 +2427,7 @@
GenericEnvironment *patternEnv = nullptr;
CanType rootType;
StringRef objcString;
+ SmallVector<SILType, 4> operandTypes;
{
Scope genericsScope(&P, ScopeKind::Generics);
generics = P.maybeParseGenericParams().getPtrOrNull();
@@ -2472,6 +2483,9 @@
VarDecl *idProperty = nullptr;
SILFunction *getter = nullptr;
SILFunction *setter = nullptr;
+ SILFunction *equals = nullptr;
+ SILFunction *hash = nullptr;
+ SmallVector<KeyPathPatternComponent::Index, 4> indexes;
while (true) {
Identifier subKind;
SourceLoc subKindLoc;
@@ -2505,6 +2519,88 @@
bool isSetter = subKind.str()[0] == 's';
if (parseSILFunctionRef(InstLoc, isSetter ? setter : getter))
return true;
+ } else if (subKind.str() == "indices") {
+ if (P.parseToken(tok::l_square,
+ diag::expected_tok_in_sil_instr, "["))
+ return true;
+
+ while (true) {
+ unsigned index;
+ CanType formalTy;
+ SILType loweredTy;
+ if (P.parseToken(tok::oper_prefix,
+ diag::expected_tok_in_sil_instr, "%")
+ || P.parseToken(tok::sil_dollar,
+ diag::expected_tok_in_sil_instr, "$"))
+ return true;
+
+ if (!P.Tok.is(tok::integer_literal)
+ || P.Tok.getText().getAsInteger(0, index))
+ return true;
+
+ P.consumeToken(tok::integer_literal);
+
+ SourceLoc formalTyLoc;
+ SourceLoc loweredTyLoc;
+ GenericEnvironment *ignoredParsedEnv;
+ if (P.parseToken(tok::colon,
+ diag::expected_tok_in_sil_instr, ":")
+ || P.parseToken(tok::sil_dollar,
+ diag::expected_tok_in_sil_instr, "$")
+ || parseASTType(formalTy, formalTyLoc, patternEnv)
+ || P.parseToken(tok::colon,
+ diag::expected_tok_in_sil_instr, ":")
+ || parseSILType(loweredTy, loweredTyLoc,
+ ignoredParsedEnv, patternEnv))
+ return true;
+
+ if (patternEnv)
+ loweredTy = SILType::getPrimitiveType(
+ patternEnv
+ ->mapTypeOutOfContext(loweredTy.getSwiftRValueType())
+ ->getCanonicalType(),
+ loweredTy.getCategory());
+
+ // Formal type must be hashable.
+ auto proto = P.Context.getProtocol(KnownProtocolKind::Hashable);
+ Type contextFormalTy = formalTy;
+ if (patternEnv)
+ contextFormalTy = patternEnv->mapTypeIntoContext(formalTy);
+ auto lookup = P.SF.getParentModule()->lookupConformance(
+ contextFormalTy, proto);
+ if (!lookup) {
+ P.diagnose(formalTyLoc,
+ diag::sil_keypath_index_not_hashable,
+ formalTy);
+ return true;
+ }
+ auto conformance = ProtocolConformanceRef(*lookup);
+
+ indexes.push_back({index, formalTy, loweredTy, conformance});
+
+ operandTypes.resize(index+1);
+ if (operandTypes[index] && operandTypes[index] != loweredTy) {
+ P.diagnose(loweredTyLoc,
+ diag::sil_keypath_index_operand_type_conflict,
+ index,
+ operandTypes[index].getSwiftRValueType(),
+ loweredTy.getSwiftRValueType());
+ return true;
+ }
+ operandTypes[index] = loweredTy;
+
+ if (P.consumeIf(tok::comma))
+ continue;
+ if (P.consumeIf(tok::r_square))
+ break;
+ return true;
+ }
+ } else if (subKind.str() == "indices_equals") {
+ if (parseSILFunctionRef(InstLoc, equals))
+ return true;
+ } else if (subKind.str() == "indices_hash") {
+ if (parseSILFunctionRef(InstLoc, hash))
+ return true;
} else {
P.diagnose(subKindLoc, diag::sil_keypath_unknown_component_kind,
subKind);
@@ -2542,15 +2638,24 @@
else
llvm_unreachable("no id?!");
- // TODO: indexes
+ auto indexesCopy = P.Context.AllocateCopy(indexes);
+
+ if (!indexes.empty() && (!equals || !hash)) {
+ P.diagnose(componentLoc,
+ diag::sil_keypath_computed_property_missing_part,
+ isSettable);
+ }
+
if (isSettable) {
components.push_back(
KeyPathPatternComponent::forComputedSettableProperty(
- id, getter, setter, {}, componentTy));
+ id, getter, setter,
+ indexesCopy, equals, hash, componentTy));
} else {
components.push_back(
KeyPathPatternComponent::forComputedGettableProperty(
- id, getter, {}, componentTy));
+ id, getter,
+ indexesCopy, equals, hash, componentTy));
}
} else if (componentKind.str() == "optional_wrap"
|| componentKind.str() == "optional_chain"
@@ -2595,7 +2700,7 @@
SmallVector<ParsedSubstitution, 4> parsedSubs;
SmallVector<Substitution, 4> subs;
- if (parseSubstitutions(parsedSubs, GenericEnv))
+ if (parseSubstitutions(parsedSubs, ContextGenericEnv))
return true;
if (!parsedSubs.empty()) {
@@ -2608,6 +2713,40 @@
return true;
}
+ SubstitutionMap subMap;
+ if (patternEnv && patternEnv->getGenericSignature())
+ subMap = patternEnv->getGenericSignature()->getSubstitutionMap(subs);
+
+ SmallVector<SILValue, 4> operands;
+
+ if (P.consumeIf(tok::l_paren)) {
+ Lowering::GenericContextScope scope(SILMod.Types,
+ patternEnv ? patternEnv->getGenericSignature()->getCanonicalSignature()
+ : nullptr);
+ while (true) {
+ SILValue v;
+
+ if (operands.size() >= operandTypes.size()
+ || !operandTypes[operands.size()]) {
+ P.diagnose(P.Tok, diag::sil_keypath_no_use_of_operand_in_pattern,
+ operands.size());
+ return true;
+ }
+
+ auto ty = operandTypes[operands.size()].subst(SILMod, subMap);
+
+ if (parseValueRef(v, ty, RegularLocation(P.Tok.getLoc()), B))
+ return true;
+ operands.push_back(v);
+
+ if (P.consumeIf(tok::comma))
+ continue;
+ if (P.consumeIf(tok::r_paren))
+ break;
+ return true;
+ }
+ }
+
if (parseSILDebugLocation(InstLoc, B))
return true;
@@ -2618,7 +2757,7 @@
rootType, components.back().getComponentType(),
components, objcString);
- ResultVal = B.createKeyPath(InstLoc, pattern, subs, Ty);
+ ResultVal = B.createKeyPath(InstLoc, pattern, subs, operands, Ty);
break;
}
@@ -4793,7 +4932,7 @@
if (P.consumeIf(tok::l_brace)) {
isDefinition = true;
- FunctionState.GenericEnv = GenericEnv;
+ FunctionState.ContextGenericEnv = GenericEnv;
FunctionState.F->setGenericEnvironment(GenericEnv);
if (GenericEnv && !SpecAttrs.empty()) {
@@ -5309,7 +5448,7 @@
auto conf = WitnessState.parseProtocolConformance(proto,
witnessEnv,
false/*localScope*/);
- WitnessState.GenericEnv = witnessEnv;
+ WitnessState.ContextGenericEnv = witnessEnv;
NormalProtocolConformance *theConformance = conf ?
dyn_cast<NormalProtocolConformance>(conf) : nullptr;
diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp
index 416ffb6..1e2cc87 100644
--- a/lib/SIL/LoopInfo.cpp
+++ b/lib/SIL/LoopInfo.cpp
@@ -60,10 +60,11 @@
}
// We can't have a phi of two openexistential instructions of different UUID.
- SILInstruction *OEI = dyn_cast<OpenExistentialAddrInst>(I);
- if (OEI || (OEI = dyn_cast<OpenExistentialRefInst>(I)) ||
- (OEI = dyn_cast<OpenExistentialMetatypeInst>(I))) {
- for (auto *UI : OEI->getUses())
+ if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
+ isa<OpenExistentialMetatypeInst>(I) ||
+ isa<OpenExistentialValueInst>(I) || isa<OpenExistentialBoxInst>(I) ||
+ isa<OpenExistentialBoxValueInst>(I)) {
+ for (auto *UI : I->getUses())
if (!contains(UI->getUser()))
return false;
return true;
diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp
index 6fc3285..1acb152 100644
--- a/lib/SIL/SILDeclRef.cpp
+++ b/lib/SIL/SILDeclRef.cpp
@@ -15,6 +15,8 @@
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
+#include "swift/AST/Initializer.h"
+#include "swift/AST/ParameterList.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/SIL/SILLinkage.h"
@@ -538,6 +540,19 @@
dc = closure->getLocalContext();
else {
auto *d = getDecl();
+
+ // Default argument generators are serialized if the function was
+ // type-checked in Swift 4 mode.
+ if (kind == SILDeclRef::Kind::DefaultArgGenerator) {
+ auto *afd = cast<AbstractFunctionDecl>(d);
+ switch (afd->getDefaultArgumentResilienceExpansion()) {
+ case ResilienceExpansion::Minimal:
+ return IsSerialized;
+ case ResilienceExpansion::Maximal:
+ return IsNotSerialized;
+ }
+ }
+
dc = getDecl()->getInnermostDeclContext();
// Enum element constructors are serialized if the enum is
diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp
index 72e37d2..90fc0f3 100644
--- a/lib/SIL/SILInstruction.cpp
+++ b/lib/SIL/SILInstruction.cpp
@@ -928,6 +928,7 @@
return true;
case ValueKind::UnconditionalCheckedCastAddrInst:
+ case ValueKind::UnconditionalCheckedCastValueInst:
return true;
case ValueKind::CheckedCastAddrBranchInst: {
diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp
index 6c51e50..1f4fc47 100644
--- a/lib/SIL/SILInstructions.cpp
+++ b/lib/SIL/SILInstructions.cpp
@@ -2052,6 +2052,11 @@
case KeyPathPatternComponent::ComputedPropertyId::Property:
return;
}
+
+ if (auto equals = component.getComputedPropertyIndexEquals())
+ forFunction(equals);
+ if (auto hash = component.getComputedPropertyIndexHash())
+ forFunction(hash);
}
}
@@ -2078,6 +2083,7 @@
return existing;
// Determine the number of operands.
+ int maxOperandNo = -1;
for (auto component : components) {
switch (component.getKind()) {
case KeyPathPatternComponent::Kind::StoredProperty:
@@ -2088,14 +2094,15 @@
case KeyPathPatternComponent::Kind::GettableProperty:
case KeyPathPatternComponent::Kind::SettableProperty:
- assert(component.getComputedPropertyIndices().empty()
- && "todo");
+ for (auto &index : component.getComputedPropertyIndices()) {
+ maxOperandNo = std::max(maxOperandNo, (int)index.Operand);
+ }
}
}
auto newPattern = KeyPathPattern::create(M, signature, rootType, valueType,
components, objcString,
- 0 /*todo: num operands*/);
+ maxOperandNo + 1);
M.KeyPathPatterns.InsertNode(newPattern, insertPos);
return newPattern;
}
@@ -2183,8 +2190,12 @@
break;
}
}
- assert(component.getComputedPropertyIndices().empty()
- && "todo");
+ for (auto &index : component.getComputedPropertyIndices()) {
+ ID.AddInteger(index.Operand);
+ ID.AddPointer(index.FormalType.getPointer());
+ ID.AddPointer(index.LoweredType.getOpaqueValue());
+ ID.AddPointer(index.Hashable.getOpaqueValue());
+ }
break;
}
}
@@ -2194,23 +2205,35 @@
KeyPathInst::create(SILDebugLocation Loc,
KeyPathPattern *Pattern,
SubstitutionList Subs,
+ ArrayRef<SILValue> Args,
SILType Ty,
SILFunction &F) {
- auto totalSize = totalSizeToAlloc<Substitution>(Subs.size());
+ assert(Args.size() == Pattern->getNumOperands()
+ && "number of key path args doesn't match pattern");
+
+ auto totalSize = totalSizeToAlloc<Substitution, Operand>
+ (Subs.size(), Args.size());
void *mem = F.getModule().allocateInst(totalSize, alignof(Substitution));
- return ::new (mem) KeyPathInst(Loc, Pattern, Subs, Ty);
+ return ::new (mem) KeyPathInst(Loc, Pattern, Subs, Args, Ty);
}
KeyPathInst::KeyPathInst(SILDebugLocation Loc,
KeyPathPattern *Pattern,
SubstitutionList Subs,
+ ArrayRef<SILValue> Args,
SILType Ty)
: SILInstruction(ValueKind::KeyPathInst, Loc, Ty),
- Pattern(Pattern), NumSubstitutions(Subs.size())
+ Pattern(Pattern), NumSubstitutions(Subs.size()),
+ NumOperands(Pattern->getNumOperands())
{
auto *subsBuf = getTrailingObjects<Substitution>();
std::uninitialized_copy(Subs.begin(), Subs.end(), subsBuf);
+ auto *operandsBuf = getTrailingObjects<Operand>();
+ for (unsigned i = 0; i < Args.size(); ++i) {
+ ::new ((void*)&operandsBuf[i]) Operand(this, Args[i]);
+ }
+
// Increment the use of any functions referenced from the keypath pattern.
for (auto component : Pattern->getComponents()) {
component.incrementRefCounts();
@@ -2224,8 +2247,7 @@
MutableArrayRef<Operand>
KeyPathInst::getAllOperands() {
- // TODO: subscript indexes
- return {};
+ return {getTrailingObjects<Operand>(), NumOperands};
}
KeyPathInst::~KeyPathInst() {
@@ -2236,7 +2258,9 @@
for (auto component : Pattern->getComponents()) {
component.decrementRefCounts();
}
- // TODO: destroy operands
+ // Destroy operands.
+ for (auto &operand : getAllOperands())
+ operand.~Operand();
}
KeyPathPattern *KeyPathInst::getPattern() const {
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index 914d589..7a01698 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -449,8 +449,6 @@
NO_OPERAND_INST(StrongRetainUnowned)
NO_OPERAND_INST(UnownedRetain)
NO_OPERAND_INST(Unreachable)
-// TODO: Some key path components will have operands
-NO_OPERAND_INST(KeyPath)
#undef NO_OPERAND_INST
/// Instructions whose arguments are always compatible with one convention.
@@ -1144,6 +1142,18 @@
return {true, UseLifetimeConstraint::MustBeLive};
}
+OwnershipUseCheckerResult
+OwnershipCompatibilityUseChecker::visitKeyPathInst(KeyPathInst *I) {
+ // KeyPath moves the value in memory out of address operands, but the
+ // ownership checker doesn't reason about that yet.
+ if (isAddressOrTrivialType()) {
+ return {compatibleWithOwnership(ValueOwnershipKind::Trivial),
+ UseLifetimeConstraint::MustBeLive};
+ }
+ return {compatibleWithOwnership(ValueOwnershipKind::Owned),
+ UseLifetimeConstraint::MustBeInvalidated};
+}
+
//===----------------------------------------------------------------------===//
// Builtin Use Checker
//===----------------------------------------------------------------------===//
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 3ff1f37..586da8c 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1907,8 +1907,26 @@
*this << " : "
<< component.getComputedPropertySetter()->getLoweredType();
}
- assert(component.getComputedPropertyIndices().empty()
- && "todo");
+
+ if (!component.getComputedPropertyIndices().empty()) {
+ *this << ", indices [";
+ interleave(component.getComputedPropertyIndices(),
+ [&](const KeyPathPatternComponent::Index &i) {
+ *this << "%$" << i.Operand << " : $"
+ << i.FormalType << " : "
+ << i.LoweredType;
+ }, [&]{
+ *this << ", ";
+ });
+ *this << "], indices_equals ";
+ component.getComputedPropertyIndexEquals()->printName(PrintState.OS);
+ *this << " : "
+ << component.getComputedPropertyIndexEquals()->getLoweredType();
+ *this << ", indices_hash ";
+ component.getComputedPropertyIndexHash()->printName(PrintState.OS);
+ *this << " : "
+ << component.getComputedPropertyIndexHash()->getLoweredType();
+ }
break;
}
case KeyPathPatternComponent::Kind::OptionalWrap:
@@ -1938,6 +1956,18 @@
*this << ' ';
printSubstitutions(KPI->getSubstitutions());
}
+ if (!KPI->getAllOperands().empty()) {
+ *this << " (";
+
+ interleave(KPI->getAllOperands(),
+ [&](const Operand &operand) {
+ *this << Ctx.getID(operand.get());
+ }, [&]{
+ *this << ", ";
+ });
+
+ *this << ")";
+ }
}
};
} // end anonymous namespace
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 7fd2e1f..9da7a7b 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -3748,8 +3748,7 @@
case KeyPathPatternComponent::Kind::GettableProperty:
case KeyPathPatternComponent::Kind::SettableProperty: {
- require(component.getComputedPropertyIndices().empty(),
- "subscripts not implemented");
+ bool hasIndices = !component.getComputedPropertyIndices().empty();
// Getter should be <Sig...> @convention(thin) (@in Base) -> @out Result
{
@@ -3760,14 +3759,25 @@
SILFunctionTypeRepresentation::Thin,
"getter should be a thin function");
- // TODO: indexes
- require(substGetterType->getNumParameters() == 1,
+ require(substGetterType->getNumParameters() == 1 + hasIndices,
"getter should have one parameter");
- auto baseParam = substGetterType->getSelfParameter();
- require(baseParam.getConvention() == ParameterConvention::Indirect_In,
+ auto baseParam = substGetterType->getParameters()[0];
+ require(baseParam.getConvention() ==
+ ParameterConvention::Indirect_In,
"getter base parameter should be @in");
require(baseParam.getType() == loweredBaseTy.getSwiftRValueType(),
"getter base parameter should match base of component");
+
+ if (hasIndices) {
+ auto indicesParam = substGetterType->getParameters()[1];
+ require(indicesParam.getConvention()
+ == ParameterConvention::Direct_Unowned,
+ "indices pointer should be trivial");
+ require(indicesParam.getType()->getAnyNominal()
+ == C.getUnsafeRawPointerDecl(),
+ "indices pointer should be an UnsafeRawPointer");
+ }
+
require(substGetterType->getNumResults() == 1,
"getter should have one result");
auto result = substGetterType->getResults()[0];
@@ -3788,22 +3798,33 @@
require(substSetterType->getRepresentation() ==
SILFunctionTypeRepresentation::Thin,
- "getter should be a thin function");
+ "setter should be a thin function");
- // TODO: indexes
- require(substSetterType->getNumParameters() == 2,
+ require(substSetterType->getNumParameters() == 2 + hasIndices,
"setter should have two parameters");
- auto baseParam = substSetterType->getSelfParameter();
+
+ auto newValueParam = substSetterType->getParameters()[0];
+ require(newValueParam.getConvention() ==
+ ParameterConvention::Indirect_In,
+ "setter value parameter should be @in");
+
+ auto baseParam = substSetterType->getParameters()[1];
require(baseParam.getConvention() ==
ParameterConvention::Indirect_In
|| baseParam.getConvention() ==
ParameterConvention::Indirect_Inout,
"setter base parameter should be @in or @inout");
- auto newValueParam = substSetterType->getParameters()[0];
- require(newValueParam.getConvention() ==
- ParameterConvention::Indirect_In,
- "setter value parameter should be @in");
+ if (hasIndices) {
+ auto indicesParam = substSetterType->getParameters()[2];
+ require(indicesParam.getConvention()
+ == ParameterConvention::Direct_Unowned,
+ "indices pointer should be trivial");
+ require(indicesParam.getType()->getAnyNominal()
+ == C.getUnsafeRawPointerDecl(),
+ "indices pointer should be an UnsafeRawPointer");
+ }
+
require(newValueParam.getType() ==
loweredComponentTy.getSwiftRValueType(),
"setter value should match the maximal abstraction of the "
@@ -3812,6 +3833,86 @@
require(substSetterType->getNumResults() == 0,
"setter should have no results");
}
+
+ for (auto &index : component.getComputedPropertyIndices()) {
+ auto opIndex = index.Operand;
+ auto contextType =
+ index.LoweredType.subst(F.getModule(), patternSubs);
+ requireSameType(contextType,
+ KPI->getAllOperands()[opIndex].get()->getType(),
+ "operand must match type required by pattern");
+ require(isLoweringOf(index.LoweredType, index.FormalType),
+ "pattern index formal type doesn't match lowered type");
+ }
+
+ if (!component.getComputedPropertyIndices().empty()) {
+ // Equals should be
+ // <Sig...> @convention(thin) (RawPointer, RawPointer) -> Bool
+ {
+ auto equals = component.getComputedPropertyIndexEquals();
+ require(equals, "key path pattern with indexes must have equals "
+ "operator");
+
+ auto substEqualsType = equals->getLoweredFunctionType()
+ ->substGenericArgs(F.getModule(), KPI->getSubstitutions());
+
+ require(substEqualsType->getParameters().size() == 2,
+ "must have two arguments");
+ for (unsigned i = 0; i < 2; ++i) {
+ auto param = substEqualsType->getParameters()[i];
+ require(param.getConvention()
+ == ParameterConvention::Direct_Unowned,
+ "indices pointer should be trivial");
+ require(param.getType()->getAnyNominal()
+ == C.getUnsafeRawPointerDecl(),
+ "indices pointer should be an UnsafeRawPointer");
+ }
+
+ require(substEqualsType->getResults().size() == 1,
+ "must have one result");
+
+ require(substEqualsType->getResults()[0].getConvention()
+ == ResultConvention::Unowned,
+ "result should be unowned");
+ require(substEqualsType->getResults()[0].getType()->getAnyNominal()
+ == C.getBoolDecl(),
+ "result should be Bool");
+ }
+ {
+ // Hash should be
+ // <Sig...> @convention(thin) (RawPointer) -> Int
+ auto hash = component.getComputedPropertyIndexHash();
+ require(hash, "key path pattern with indexes must have hash "
+ "operator");
+
+ auto substHashType = hash->getLoweredFunctionType()
+ ->substGenericArgs(F.getModule(), KPI->getSubstitutions());
+
+ require(substHashType->getParameters().size() == 1,
+ "must have two arguments");
+ auto param = substHashType->getParameters()[0];
+ require(param.getConvention()
+ == ParameterConvention::Direct_Unowned,
+ "indices pointer should be trivial");
+ require(param.getType()->getAnyNominal()
+ == C.getUnsafeRawPointerDecl(),
+ "indices pointer should be an UnsafeRawPointer");
+
+ require(substHashType->getResults().size() == 1,
+ "must have one result");
+
+ require(substHashType->getResults()[0].getConvention()
+ == ResultConvention::Unowned,
+ "result should be unowned");
+ require(substHashType->getResults()[0].getType()->getAnyNominal()
+ == C.getIntDecl(),
+ "result should be Int");
+ }
+ } else {
+ require(!component.getComputedPropertyIndexEquals()
+ && !component.getComputedPropertyIndexHash(),
+ "component without indexes must not have equals/hash");
+ }
break;
}
diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp
index a698928..b9207d0 100644
--- a/lib/SIL/TypeLowering.cpp
+++ b/lib/SIL/TypeLowering.cpp
@@ -1116,7 +1116,7 @@
class OpaqueValueTypeLowering : public LeafLoadableTypeLowering {
public:
OpaqueValueTypeLowering(SILType type)
- : LeafLoadableTypeLowering(type, IsAddressOnly, IsReferenceCounted) {}
+ : LeafLoadableTypeLowering(type, IsAddressOnly, IsNotReferenceCounted) {}
void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index fd15d36..5dfc2e1 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -649,11 +649,10 @@
void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) {
// Emit any default argument generators.
- {
- auto paramLists = AFD->getParameterLists();
- if (AFD->getDeclContext()->isTypeContext())
- paramLists = paramLists.slice(1);
- emitDefaultArgGenerators(AFD, paramLists);
+ if (!isa<DestructorDecl>(AFD)) {
+ unsigned paramListIndex = AFD->getDeclContext()->isTypeContext() ? 1 : 0;
+ auto *paramList = AFD->getParameterLists()[paramListIndex];
+ emitDefaultArgGenerators(AFD, paramList);
}
// If this is a function at global scope, it may close over a global variable.
@@ -1015,15 +1014,13 @@
}
void SILGenModule::emitDefaultArgGenerators(SILDeclRef::Loc decl,
- ArrayRef<ParameterList*> paramLists) {
+ ParameterList *paramList) {
unsigned index = 0;
- for (auto paramList : paramLists) {
- for (auto param : *paramList) {
- if (auto defaultArg = param->getDefaultValue())
- emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl, index),
- defaultArg, param->getDefaultArgumentKind());
- ++index;
- }
+ for (auto param : *paramList) {
+ if (auto defaultArg = param->getDefaultValue())
+ emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl, index),
+ defaultArg, param->getDefaultArgumentKind());
+ ++index;
}
}
diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h
index ed0f26f..5f41b31 100644
--- a/lib/SILGen/SILGen.h
+++ b/lib/SILGen/SILGen.h
@@ -271,9 +271,9 @@
/// Emits the stored property initializer for the given pattern.
void emitStoredPropertyInitialization(PatternBindingDecl *pd, unsigned i);
- /// Emits the default argument generator for the given function.
+ /// Emits default argument generators for the given parameter list.
void emitDefaultArgGenerators(SILDeclRef::Loc decl,
- ArrayRef<ParameterList*> paramLists);
+ ParameterList *paramList);
/// Emits the curry thunk between two uncurry levels of a function.
void emitCurryThunk(SILDeclRef thunk);
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index c370c88..38d9033 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -577,9 +577,9 @@
FormalEvaluationScope writebackScope(*this);
ManagedValue nsError =
- emitRValueForPropertyLoad(
+ emitRValueForStorageLoad(
loc, nativeError, concreteFormalType,
- /*super*/ false, nsErrorVar, nsErrorVarSubstitutions,
+ /*super*/ false, nsErrorVar, RValue(), nsErrorVarSubstitutions,
AccessSemantics::Ordinary, nsErrorType, SGFContext())
.getAsSingleValue(*this, loc);
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 3be283f..b482405 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -31,6 +31,7 @@
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ASTMangler.h"
+#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Types.h"
#include "swift/Basic/SourceManager.h"
@@ -1050,9 +1051,13 @@
}
static AbstractionPattern
-getOrigFormalRValueType(SILGenFunction &SGF, VarDecl *field) {
- auto origType = SGF.SGM.Types.getAbstractionPattern(field);
- return origType.getReferenceStorageReferentType();
+getFormalStorageAbstractionPattern(SILGenFunction &SGF, AbstractStorageDecl *field) {
+ if (auto var = dyn_cast<VarDecl>(field)) {
+ auto origType = SGF.SGM.Types.getAbstractionPattern(var);
+ return origType.getReferenceStorageReferentType();
+ }
+ auto sub = cast<SubscriptDecl>(field);
+ return SGF.SGM.Types.getAbstractionPattern(sub);
}
static SILDeclRef getRValueAccessorDeclRef(SILGenFunction &SGF,
@@ -1153,31 +1158,33 @@
/// Produce a singular RValue for a load from the specified property. This is
/// designed to work with RValue ManagedValue bases that are either +0 or +1.
-RValue SILGenFunction::emitRValueForPropertyLoad(
+RValue SILGenFunction::emitRValueForStorageLoad(
SILLocation loc, ManagedValue base, CanType baseFormalType,
- bool isSuper, VarDecl *field, SubstitutionList substitutions,
+ bool isSuper, AbstractStorageDecl *storage, RValue indexes,
+ SubstitutionList substitutions,
AccessSemantics semantics, Type propTy, SGFContext C,
bool isBaseGuaranteed) {
AccessStrategy strategy =
- field->getAccessStrategy(semantics, AccessKind::Read);
+ storage->getAccessStrategy(semantics, AccessKind::Read);
// If we should call an accessor of some kind, do so.
if (strategy != AccessStrategy::Storage) {
- auto accessor = getRValueAccessorDeclRef(*this, field, strategy);
+ auto accessor = getRValueAccessorDeclRef(*this, storage, strategy);
ArgumentSource baseRV = prepareAccessorBaseArg(loc, base,
baseFormalType,
accessor);
AbstractionPattern origFormalType =
- getOrigFormalRValueType(*this, field);
+ getFormalStorageAbstractionPattern(*this, storage);
auto substFormalType = propTy->getCanonicalType();
- return emitRValueWithAccessor(*this, loc, field, substitutions,
- std::move(baseRV), RValue(),
+ return emitRValueWithAccessor(*this, loc, storage, substitutions,
+ std::move(baseRV), std::move(indexes),
isSuper, strategy, accessor,
origFormalType, substFormalType, C);
}
-
+ assert(isa<VarDecl>(storage) && "only properties should have storage");
+ auto field = cast<VarDecl>(storage);
assert(field->hasStorage() &&
"Cannot directly access value without storage");
@@ -1211,7 +1218,7 @@
auto &lowering = getTypeLowering(substFormalType);
// Check for an abstraction difference.
- AbstractionPattern origFormalType = getOrigFormalRValueType(*this, field);
+ AbstractionPattern origFormalType = getFormalStorageAbstractionPattern(*this, field);
bool hasAbstractionChange = false;
auto &abstractedTL = getTypeLowering(origFormalType, substFormalType);
if (!origFormalType.isExactType(substFormalType)) {
@@ -2392,12 +2399,12 @@
assert(baseFormalType->isMaterializable());
RValue result =
- SGF.emitRValueForPropertyLoad(Expr, base, baseFormalType,
- Expr->isSuper(),
- Field,
- Expr->getMember().getSubstitutions(),
- Expr->getAccessSemantics(),
- Expr->getType(), Context);
+ SGF.emitRValueForStorageLoad(Expr, base, baseFormalType,
+ Expr->isSuper(),
+ Field, {},
+ Expr->getMember().getSubstitutions(),
+ Expr->getAccessSemantics(),
+ Expr->getType(), Context);
return result;
}
@@ -2434,13 +2441,13 @@
// And then emit our property using whether or not base is at +0 to
// discriminate whether or not the base was guaranteed.
RValue result =
- SGF.emitRValueForPropertyLoad(Expr, base, baseFormalType,
- Expr->isSuper(),
- Field,
- Expr->getMember().getSubstitutions(),
- Expr->getAccessSemantics(),
- Expr->getType(), Context,
- base.isPlusZeroRValueOrTrivial());
+ SGF.emitRValueForStorageLoad(Expr, base, baseFormalType,
+ Expr->isSuper(),
+ Field, {},
+ Expr->getMember().getSubstitutions(),
+ Expr->getAccessSemantics(),
+ Expr->getType(), Context,
+ base.isPlusZeroRValueOrTrivial());
return std::move(result);
}
};
@@ -2887,17 +2894,19 @@
static ManagedValue
emitKeyPathRValueBase(SILGenFunction &subSGF,
- VarDecl *property,
- SILLocation loc,
- SILValue paramArg,
- CanType &baseType) {
+ AbstractStorageDecl *storage,
+ SILLocation loc,
+ SILValue paramArg,
+ CanType &baseType,
+ SubstitutionList &subs,
+ SmallVectorImpl<Substitution> &subsBuf) {
auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
AbstractionPattern::getOpaque(),
baseType);
// Upcast a class instance to the property's declared type if necessary.
- if (auto propertyClass = dyn_cast<ClassDecl>(property->getDeclContext())) {
+ if (auto propertyClass = dyn_cast<ClassDecl>(storage->getDeclContext())) {
if (baseType->getClassOrBoundGenericClass() != propertyClass) {
baseType = baseType->getSuperclassForDecl(propertyClass)
->getCanonicalType();
@@ -2907,8 +2916,10 @@
}
// …or pop open an existential container.
else if (baseType->isAnyExistentialType()) {
- ArchetypeType *opened;
- baseType = baseType->openAnyExistentialType(opened)->getCanonicalType();
+ auto opened = subs[0].getReplacement()->castTo<ArchetypeType>();
+ assert(opened->isOpenedExistential());
+
+ baseType = opened->getCanonicalType();
auto openedOpaqueValue = subSGF.emitOpenExistential(loc, paramSubstValue,
opened, subSGF.SGM.getLoweredType(baseType),
AccessKind::Read);
@@ -2923,13 +2934,57 @@
return paramSubstValue;
}
+/// Helper function to load the captured indexes out of a key path component
+/// in order to invoke the accessors on that key path. A component with captured
+/// indexes passes down a pointer to those captures to the accessor thunks,
+/// which we can copy out of to produce values we can pass to the real
+/// accessor functions.
+static RValue loadIndexValuesForKeyPathComponent(SILGenFunction &SGF,
+ SILLocation loc,
+ ArrayRef<KeyPathPatternComponent::Index> indexes,
+ SILValue pointer) {
+ // If no indexes, do nothing.
+ if (indexes.empty())
+ return RValue();
+
+ SmallVector<TupleTypeElt, 2> indexElts;
+ for (auto &elt : indexes) {
+ indexElts.push_back(SGF.F.mapTypeIntoContext(elt.FormalType));
+ }
+
+ auto indexTupleTy = TupleType::get(indexElts, SGF.getASTContext())
+ ->getCanonicalType();
+ RValue indexValue(indexTupleTy);
+
+ auto indexLoweredTy = SGF.getLoweredType(indexTupleTy);
+ auto addr = SGF.B.createPointerToAddress(loc, pointer,
+ indexLoweredTy.getAddressType(),
+ /*isStrict*/ false);
+
+ for (unsigned i : indices(indexes)) {
+ SILValue eltAddr = addr;
+ if (indexes.size() > 1) {
+ eltAddr = SGF.B.createTupleElementAddr(loc, eltAddr, i);
+ }
+ auto ty = SGF.F.mapTypeIntoContext(indexes[i].LoweredType);
+ auto value = SGF.emitLoad(loc, eltAddr,
+ SGF.getTypeLowering(ty),
+ SGFContext(), IsNotTake);
+ indexValue.addElement(SGF, value, indexes[i].FormalType, loc);
+ }
+
+ return indexValue;
+}
+
static SILFunction *getOrCreateKeyPathGetter(SILGenFunction &SGF,
- SILLocation loc,
- VarDecl *property,
- AccessStrategy strategy,
- GenericEnvironment *genericEnv,
- CanType baseType,
- CanType propertyType) {
+ SILLocation loc,
+ AbstractStorageDecl *property,
+ SubstitutionList subs,
+ AccessStrategy strategy,
+ GenericEnvironment *genericEnv,
+ ArrayRef<KeyPathPatternComponent::Index> indexes,
+ CanType baseType,
+ CanType propertyType) {
auto genericSig = genericEnv
? genericEnv->getGenericSignature()->getCanonicalSignature()
: nullptr;
@@ -2944,8 +2999,15 @@
propertyType);
}
- SILParameterInfo param(loweredBaseTy.getSwiftRValueType(),
- ParameterConvention::Indirect_In);
+ SmallVector<SILParameterInfo, 2> params;
+ params.push_back({loweredBaseTy.getSwiftRValueType(),
+ ParameterConvention::Indirect_In});
+ auto &C = SGF.getASTContext();
+ if (!indexes.empty())
+ params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredType()
+ ->getCanonicalType(),
+ ParameterConvention::Direct_Unowned});
+
SILResultInfo result(loweredPropTy.getSwiftRValueType(),
ResultConvention::Indirect);
@@ -2953,11 +3015,19 @@
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false),
ParameterConvention::Direct_Unowned,
- param, result, None, SGF.getASTContext());
+ params, result, None, SGF.getASTContext());
// Find the function and see if we already created it.
+ SmallVector<CanType, 2> interfaceSubs;
+ for (auto &sub : subs) {
+ interfaceSubs.push_back((genericEnv
+ ? genericEnv->mapTypeOutOfContext(sub.getReplacement())
+ : sub.getReplacement())
+ ->getCanonicalType());
+ }
auto name = Mangle::ASTMangler()
- .mangleKeyPathGetterThunkHelper(property, genericSig, baseType);
+ .mangleKeyPathGetterThunkHelper(property, genericSig, baseType,
+ interfaceSubs);
auto thunk = SGF.SGM.M.getOrCreateSharedFunction(loc, name,
signature,
IsBare,
@@ -2980,28 +3050,35 @@
SILGenFunction subSGF(SGM, *thunk);
auto entry = thunk->begin();
auto resultArgTy = result.getSILStorageType();
- auto paramArgTy = param.getSILStorageType();
+ auto baseArgTy = params[0].getSILStorageType();
if (genericEnv) {
resultArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, resultArgTy);
- paramArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, paramArgTy);
+ baseArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, baseArgTy);
}
auto resultArg = entry->createFunctionArgument(resultArgTy);
- auto paramArg = entry->createFunctionArgument(paramArgTy);
+ auto baseArg = entry->createFunctionArgument(baseArgTy);
+ SILValue indexPtrArg;
+ if (!indexes.empty()) {
+ auto indexArgTy = params[1].getSILStorageType();
+ indexPtrArg = entry->createFunctionArgument(indexArgTy);
+ }
Scope scope(subSGF, loc);
+ SmallVector<Substitution, 2> subsBuf;
+
auto paramSubstValue = emitKeyPathRValueBase(subSGF, property,
- loc, paramArg,
- baseType);
-
- auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
- property->getInnermostDeclContext()->getInnermostTypeContext());
- SmallVector<Substitution, 4> subsList;
- if (subs.getGenericSignature())
- subs.getGenericSignature()->getSubstitutions(subs, subsList);
- auto resultSubst = subSGF.emitRValueForPropertyLoad(loc, paramSubstValue,
- baseType, /*super*/false, property,
- subsList, AccessSemantics::Ordinary,
+ loc, baseArg,
+ baseType, subs, subsBuf);
+
+ RValue indexValue = loadIndexValuesForKeyPathComponent(subSGF, loc,
+ indexes,
+ indexPtrArg);
+
+ auto resultSubst = subSGF.emitRValueForStorageLoad(loc, paramSubstValue,
+ baseType, /*super*/false,
+ property, std::move(indexValue),
+ subs, AccessSemantics::Ordinary,
propertyType, SGFContext())
.getAsSingleValue(subSGF, loc);
if (resultSubst.getType().getAddressType() != resultArg->getType())
@@ -3018,12 +3095,14 @@
}
SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
- SILLocation loc,
- VarDecl *property,
- AccessStrategy strategy,
- GenericEnvironment *genericEnv,
- CanType baseType,
- CanType propertyType) {
+ SILLocation loc,
+ AbstractStorageDecl *property,
+ SubstitutionList subs,
+ AccessStrategy strategy,
+ GenericEnvironment *genericEnv,
+ ArrayRef<KeyPathPatternComponent::Index> indexes,
+ CanType baseType,
+ CanType propertyType) {
auto genericSig = genericEnv
? genericEnv->getGenericSignature()->getCanonicalSignature()
: nullptr;
@@ -3038,27 +3117,43 @@
propertyType);
}
- SILParameterInfo propParam(loweredPropTy.getSwiftRValueType(),
- ParameterConvention::Indirect_In);
+ auto &C = SGF.getASTContext();
- SILParameterInfo baseParam(loweredBaseTy.getSwiftRValueType(),
- property->isSetterMutating()
- ? ParameterConvention::Indirect_Inout
- : ParameterConvention::Indirect_In);
+ SmallVector<SILParameterInfo, 3> params;
+ // property value
+ params.push_back({loweredPropTy.getSwiftRValueType(),
+ ParameterConvention::Indirect_In});
+ // base
+ params.push_back({loweredBaseTy.getSwiftRValueType(),
+ property->isSetterMutating()
+ ? ParameterConvention::Indirect_Inout
+ : ParameterConvention::Indirect_In});
+ // indexes
+ if (!indexes.empty())
+ params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredType()
+ ->getCanonicalType(),
+ ParameterConvention::Direct_Unowned});
auto signature = SILFunctionType::get(genericSig,
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false),
ParameterConvention::Direct_Unowned,
- {propParam, baseParam}, {}, None, SGF.getASTContext());
+ params, {}, None, SGF.getASTContext());
// Mangle the name of the thunk to see if we already created it.
SmallString<64> nameBuf;
- // Find the function and see if we already created it.
+ SmallVector<CanType, 2> interfaceSubs;
+ for (auto &sub : subs) {
+ interfaceSubs.push_back((genericEnv
+ ? genericEnv->mapTypeOutOfContext(sub.getReplacement())
+ : sub.getReplacement())
+ ->getCanonicalType());
+ }
auto name = Mangle::ASTMangler().mangleKeyPathSetterThunkHelper(property,
- genericSig,
- baseType);
+ genericSig,
+ baseType,
+ interfaceSubs);
auto thunk = SGF.SGM.M.getOrCreateSharedFunction(loc, name,
signature,
IsBare,
@@ -3080,16 +3175,26 @@
SILGenFunction subSGF(SGM, *thunk);
auto entry = thunk->begin();
- auto valueArgTy = propParam.getSILStorageType();
- auto baseArgTy = baseParam.getSILStorageType();
+ auto valueArgTy = params[0].getSILStorageType();
+ auto baseArgTy = params[1].getSILStorageType();
if (genericEnv) {
valueArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, valueArgTy);
baseArgTy = genericEnv->mapTypeIntoContext(subSGF.SGM.M, baseArgTy);
}
auto valueArg = entry->createFunctionArgument(valueArgTy);
auto baseArg = entry->createFunctionArgument(baseArgTy);
+ SILValue indexPtrArg;
+ if (!indexes.empty()) {
+ auto indexArgTy = params[2].getSILStorageType();
+ indexPtrArg = entry->createFunctionArgument(indexArgTy);
+ }
+
Scope scope(subSGF, loc);
+
+ RValue indexValue = loadIndexValuesForKeyPathComponent(subSGF, loc,
+ indexes,
+ indexPtrArg);
auto valueOrig = subSGF.emitManagedRValueWithCleanup(valueArg);
auto valueSubst = subSGF.emitOrigToSubstValue(loc, valueOrig,
@@ -3097,10 +3202,12 @@
propertyType);
LValue lv;
+ SmallVector<Substitution, 2> subsBuf;
+
if (!property->isSetterMutating()) {
auto baseSubst = emitKeyPathRValueBase(subSGF, property,
loc, baseArg,
- baseType);
+ baseType, subs, subsBuf);
lv = LValue::forValue(baseSubst, baseType);
} else {
@@ -3111,8 +3218,9 @@
// Open an existential lvalue, if necessary.
if (baseType->isAnyExistentialType()) {
- ArchetypeType *opened;
- baseType = baseType->openAnyExistentialType(opened)->getCanonicalType();
+ auto opened = subs[0].getReplacement()->castTo<ArchetypeType>();
+ assert(opened->isOpenedExistential());
+ baseType = opened->getCanonicalType();
lv = subSGF.emitOpenExistentialLValue(loc, std::move(lv),
CanArchetypeType(opened),
baseType,
@@ -3120,16 +3228,18 @@
}
}
- auto subs = baseType->getContextSubstitutionMap(subSGF.SGM.M.getSwiftModule(),
- property->getInnermostDeclContext()->getInnermostTypeContext());
- SmallVector<Substitution, 4> subsList;
- if (subs.getGenericSignature())
- subs.getGenericSignature()->getSubstitutions(subs, subsList);
-
LValueOptions lvOptions;
- lv.addMemberVarComponent(subSGF, loc, property, subsList, lvOptions,
- /*super*/ false, AccessKind::Write,
- AccessSemantics::Ordinary, strategy, propertyType);
+ if (auto var = dyn_cast<VarDecl>(property)) {
+ lv.addMemberVarComponent(subSGF, loc, var, subs, lvOptions,
+ /*super*/ false, AccessKind::Write,
+ AccessSemantics::Ordinary, strategy, propertyType);
+ } else {
+ auto sub = cast<SubscriptDecl>(property);
+ lv.addMemberSubscriptComponent(subSGF, loc, sub, subs, lvOptions,
+ /*super*/ false, AccessKind::Write,
+ AccessSemantics::Ordinary, strategy, propertyType,
+ std::move(indexValue));
+ }
subSGF.emitAssignToLValue(loc,
RValue(subSGF, loc, propertyType, valueSubst),
@@ -3141,14 +3251,341 @@
return thunk;
}
+static void
+getOrCreateKeyPathEqualsAndHash(SILGenFunction &SGF,
+ SILLocation loc,
+ GenericEnvironment *genericEnv,
+ ArrayRef<KeyPathPatternComponent::Index> indexes,
+ SILFunction *&equals,
+ SILFunction *&hash) {
+ if (indexes.empty()) {
+ equals = nullptr;
+ hash = nullptr;
+ return;
+ }
+
+ auto genericSig = genericEnv
+ ? genericEnv->getGenericSignature()->getCanonicalSignature()
+ : nullptr;
+
+ auto &C = SGF.getASTContext();
+ auto unsafeRawPointerTy = C.getUnsafeRawPointerDecl()->getDeclaredType()
+ ->getCanonicalType();
+ auto boolTy = C.getBoolDecl()->getDeclaredType()->getCanonicalType();
+ auto intTy = C.getIntDecl()->getDeclaredType()->getCanonicalType();
+
+ auto hashableProto = C.getProtocol(KnownProtocolKind::Hashable);
+
+ SmallVector<CanType, 4> indexTypes;
+ indexTypes.reserve(indexes.size());
+ for (auto &index : indexes)
+ indexTypes.push_back(index.FormalType);
+
+ SmallVector<TupleTypeElt, 2> indexElts;
+ for (auto &elt : indexes) {
+ indexElts.push_back(SGF.F.mapTypeIntoContext(elt.FormalType));
+ }
+
+ auto indexTupleTy = TupleType::get(indexElts, SGF.getASTContext())
+ ->getCanonicalType();
+ RValue indexValue(indexTupleTy);
+
+ auto indexLoweredTy = SGF.getLoweredType(indexTupleTy);
+ auto &SGM = SGF.SGM;
+ // Get or create the equals witness
+ [&unsafeRawPointerTy, &boolTy, &genericSig, &C, &indexTypes, &equals, &loc,
+ &SGM, &genericEnv, &indexLoweredTy, &hashableProto, &indexes]{
+ // (RawPointer, RawPointer) -> Bool
+ SmallVector<SILParameterInfo, 2> params;
+ params.push_back({unsafeRawPointerTy,
+ ParameterConvention::Direct_Unowned});
+ params.push_back({unsafeRawPointerTy,
+ ParameterConvention::Direct_Unowned});
+
+ SmallVector<SILResultInfo, 1> results;
+ results.push_back({boolTy, ResultConvention::Unowned});
+
+ auto signature = SILFunctionType::get(genericSig,
+ SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
+ /*pseudogeneric*/ false),
+ ParameterConvention::Direct_Unowned,
+ params, results, None, C);
+
+ // Mangle the name of the thunk to see if we already created it.
+ SmallString<64> nameBuf;
+
+ auto name = Mangle::ASTMangler().mangleKeyPathEqualsHelper(indexTypes,
+ genericSig);
+ equals = SGM.M.getOrCreateSharedFunction(loc, name,
+ signature,
+ IsBare,
+ IsNotTransparent,
+ IsNotSerialized,
+ IsThunk);
+ if (!equals->empty()) {
+ return;
+ }
+
+ SILGenFunction subSGF(SGM, *equals);
+ equals->setGenericEnvironment(genericEnv);
+ auto entry = equals->begin();
+ auto lhsPtr = entry->createFunctionArgument(params[0].getSILStorageType());
+ auto rhsPtr = entry->createFunctionArgument(params[1].getSILStorageType());
+
+ Scope scope(subSGF, loc);
+
+ auto lhsAddr = subSGF.B.createPointerToAddress(loc, lhsPtr,
+ indexLoweredTy.getAddressType(),
+ /*isStrict*/ false);
+ auto rhsAddr = subSGF.B.createPointerToAddress(loc, rhsPtr,
+ indexLoweredTy.getAddressType(),
+ /*isStrict*/ false);
+
+ // Compare each pair of index values using the == witness from the
+ // conformance.
+ auto equatableProtocol = C.getProtocol(KnownProtocolKind::Equatable);
+ auto equalsMethod = equatableProtocol->lookupDirect(C.Id_EqualsOperator)[0];
+ auto equalsRef = SILDeclRef(equalsMethod);
+ auto equalsTy = subSGF.SGM.Types.getConstantType(equalsRef);
+
+ auto hashableSig = C.getExistentialSignature(
+ hashableProto->getDeclaredType()->getCanonicalType(),
+ SGM.M.getSwiftModule());
+
+ auto isFalseBB = subSGF.createBasicBlock();
+ auto i1Ty = SILType::getBuiltinIntegerType(1, C);
+ for (unsigned i : indices(indexes)) {
+ auto &index = indexes[i];
+
+ auto formalTy = index.FormalType;
+ auto hashable = index.Hashable;
+ if (genericEnv) {
+ formalTy = genericEnv->mapTypeIntoContext(formalTy)->getCanonicalType();
+ hashable = hashable.subst(index.FormalType,
+ [&](Type t) -> Type { return genericEnv->mapTypeIntoContext(t); },
+ LookUpConformanceInSignature(*genericSig));
+ }
+
+ // Get the Equatable conformance from the Hashable conformance
+ auto subMap = hashableSig->getSubstitutionMap(
+ Substitution(formalTy, hashable));
+ auto equatable = *subMap
+ .lookupConformance(CanType(hashableSig->getGenericParams()[0]),
+ equatableProtocol);
+ auto equatableSub = Substitution(formalTy,
+ C.AllocateCopy(ArrayRef<ProtocolConformanceRef>(equatable)));
+
+ auto equalsWitness = subSGF.B.createWitnessMethod(loc,
+ formalTy, equatable,
+ equalsRef, equalsTy);
+
+ auto equalsSubstTy = equalsTy.castTo<SILFunctionType>()
+ ->substGenericArgs(SGM.M, equatableSub);
+ auto equalsInfo = CalleeTypeInfo(equalsSubstTy,
+ AbstractionPattern(boolTy), boolTy,
+ None,
+ ImportAsMemberStatus());
+
+ Scope branchScope(subSGF, loc);
+
+ SILValue lhsEltAddr = lhsAddr;
+ SILValue rhsEltAddr = rhsAddr;
+ if (indexes.size() > 1) {
+ lhsEltAddr = subSGF.B.createTupleElementAddr(loc, lhsEltAddr, i);
+ rhsEltAddr = subSGF.B.createTupleElementAddr(loc, rhsEltAddr, i);
+ }
+ auto lhsArg = subSGF.emitLoad(loc, lhsEltAddr,
+ subSGF.getTypeLowering(AbstractionPattern::getOpaque(), formalTy),
+ SGFContext(), IsNotTake);
+ auto rhsArg = subSGF.emitLoad(loc, rhsEltAddr,
+ subSGF.getTypeLowering(AbstractionPattern::getOpaque(), formalTy),
+ SGFContext(), IsNotTake);
+
+ if (!lhsArg.getType().isAddress()) {
+ auto lhsBuf = subSGF.emitTemporaryAllocation(loc, lhsArg.getType());
+ lhsArg.forwardInto(subSGF, loc, lhsBuf);
+ lhsArg = subSGF.emitManagedBufferWithCleanup(lhsBuf);
+
+ auto rhsBuf = subSGF.emitTemporaryAllocation(loc, rhsArg.getType());
+ rhsArg.forwardInto(subSGF, loc, rhsBuf);
+ rhsArg = subSGF.emitManagedBufferWithCleanup(rhsBuf);
+ }
+
+ auto metaty = CanMetatypeType::get(formalTy,
+ MetatypeRepresentation::Thick);
+ auto metatyValue = ManagedValue::forUnmanaged(subSGF.B.createMetatype(loc,
+ SILType::getPrimitiveObjectType(metaty)));
+ SILValue isEqual;
+ {
+ auto equalsResultPlan = ResultPlanBuilder::computeResultPlan(subSGF,
+ equalsInfo, loc, SGFContext());
+ ArgumentScope argScope(subSGF, loc);
+ isEqual = subSGF.emitApply(std::move(equalsResultPlan),
+ std::move(argScope),
+ loc,
+ ManagedValue::forUnmanaged(equalsWitness),
+ equatableSub,
+ {lhsArg, rhsArg, metatyValue},
+ equalsInfo,
+ ApplyOptions::None,
+ SGFContext())
+ .getUnmanagedSingleValue(subSGF, loc);
+ }
+
+ branchScope.pop();
+
+ auto isEqualI1 = subSGF.B.createStructExtract(loc, isEqual,
+ C.getBoolDecl()->getStoredProperties().front(), i1Ty);
+
+ auto isTrueBB = subSGF.createBasicBlock();
+
+ subSGF.B.createCondBranch(loc, isEqualI1, isTrueBB, isFalseBB);
+
+ subSGF.B.emitBlock(isTrueBB);
+ }
+
+ auto returnBB = subSGF.createBasicBlock(FunctionSection::Postmatter);
+
+ SILValue trueValue = subSGF.B.createIntegerLiteral(loc, i1Ty, 1);
+ subSGF.B.createBranch(loc, returnBB, trueValue);
+
+ subSGF.B.emitBlock(isFalseBB);
+ SILValue falseValue = subSGF.B.createIntegerLiteral(loc, i1Ty, 0);
+ subSGF.B.createBranch(loc, returnBB, falseValue);
+
+ subSGF.B.emitBlock(returnBB);
+ scope.pop();
+ SILValue returnVal = returnBB->createPHIArgument(i1Ty,
+ ValueOwnershipKind::Trivial);
+ auto returnBoolVal = subSGF.B.createStruct(loc,
+ SILType::getPrimitiveObjectType(boolTy), returnVal);
+ subSGF.B.createReturn(loc, returnBoolVal);
+ }();
+
+ // Get or create the hash witness
+ [&unsafeRawPointerTy, &intTy, &genericSig, &C, &indexTypes, &hash, &loc,
+ &SGM, &genericEnv, &indexLoweredTy, &hashableProto, &indexes]{
+ // (RawPointer) -> Int
+ SmallVector<SILParameterInfo, 1> params;
+ params.push_back({unsafeRawPointerTy,
+ ParameterConvention::Direct_Unowned});
+
+ SmallVector<SILResultInfo, 1> results;
+ results.push_back({intTy, ResultConvention::Unowned});
+
+ auto signature = SILFunctionType::get(genericSig,
+ SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
+ /*pseudogeneric*/ false),
+ ParameterConvention::Direct_Unowned,
+ params, results, None, C);
+
+ // Mangle the name of the thunk to see if we already created it.
+ SmallString<64> nameBuf;
+
+ auto name = Mangle::ASTMangler().mangleKeyPathHashHelper(indexTypes,
+ genericSig);
+ hash = SGM.M.getOrCreateSharedFunction(loc, name,
+ signature,
+ IsBare,
+ IsNotTransparent,
+ IsNotSerialized,
+ IsThunk);
+ if (!hash->empty()) {
+ return;
+ }
+
+ SILGenFunction subSGF(SGM, *hash);
+ hash->setGenericEnvironment(genericEnv);
+ auto entry = hash->begin();
+ auto indexPtr = entry->createFunctionArgument(params[0].getSILStorageType());
+
+ Scope scope(subSGF, loc);
+
+ auto hashMethod = cast<VarDecl>(
+ hashableProto->lookupDirect(C.Id_hashValue)[0])
+ ->getGetter();
+ auto hashRef = SILDeclRef(hashMethod);
+ auto hashTy = subSGF.SGM.Types.getConstantType(hashRef);
+
+ SILValue hashCode;
+
+ // TODO: Combine hashes of the indexes. There isn't a great hash combining
+ // interface in the standard library to do this yet.
+ {
+ auto &index = indexes[0];
+
+ SILValue indexAddr = subSGF.B.createPointerToAddress(loc, indexPtr,
+ indexLoweredTy.getAddressType(),
+ /*isStrict*/ false);
+ if (indexes.size() > 1) {
+ indexAddr = subSGF.B.createTupleElementAddr(loc, indexAddr, 0);
+ }
+
+ auto formalTy = index.FormalType;
+ auto hashable = index.Hashable;
+ if (genericEnv) {
+ formalTy = genericEnv->mapTypeIntoContext(formalTy)->getCanonicalType();
+ hashable = hashable.subst(index.FormalType,
+ [&](Type t) -> Type { return genericEnv->mapTypeIntoContext(t); },
+ LookUpConformanceInSignature(*genericSig));
+ }
+
+ // Get the Equatable conformance from the Hashable conformance
+ auto hashableSub = Substitution(formalTy,
+ C.AllocateCopy(ArrayRef<ProtocolConformanceRef>(hashable)));
+
+ auto hashWitness = subSGF.B.createWitnessMethod(loc,
+ formalTy, hashable,
+ hashRef, hashTy);
+
+ auto hashSubstTy = hashTy.castTo<SILFunctionType>()
+ ->substGenericArgs(SGM.M, hashableSub);
+ auto hashInfo = CalleeTypeInfo(hashSubstTy,
+ AbstractionPattern(intTy), intTy,
+ None,
+ ImportAsMemberStatus());
+
+ auto arg = subSGF.emitLoad(loc, indexAddr,
+ subSGF.getTypeLowering(AbstractionPattern::getOpaque(), formalTy),
+ SGFContext(), IsNotTake);
+
+ if (!arg.getType().isAddress()) {
+ auto buf = subSGF.emitTemporaryAllocation(loc, arg.getType());
+ arg.forwardInto(subSGF, loc, buf);
+ arg = subSGF.emitManagedBufferWithCleanup(buf);
+ }
+
+ {
+ auto hashResultPlan = ResultPlanBuilder::computeResultPlan(subSGF,
+ hashInfo, loc, SGFContext());
+ ArgumentScope argScope(subSGF, loc);
+ hashCode = subSGF.emitApply(std::move(hashResultPlan),
+ std::move(argScope),
+ loc,
+ ManagedValue::forUnmanaged(hashWitness),
+ hashableSub,
+ {arg},
+ hashInfo,
+ ApplyOptions::None,
+ SGFContext())
+ .getUnmanagedSingleValue(subSGF, loc);
+ }
+ }
+ scope.pop();
+ subSGF.B.createReturn(loc, hashCode);
+ }();
+
+ return;
+}
+
static KeyPathPatternComponent::ComputedPropertyId
getIdForKeyPathComponentComputedProperty(SILGenFunction &SGF,
- VarDecl *property,
+ AbstractStorageDecl *storage,
AccessStrategy strategy) {
switch (strategy) {
case AccessStrategy::Storage:
// Identify reabstracted stored properties by the property itself.
- return property;
+ return cast<VarDecl>(storage);
case AccessStrategy::Addressor:
case AccessStrategy::DirectToAccessor: {
// Identify the property using its (unthunked) getter. For a
@@ -3157,17 +3594,17 @@
// TODO: If the getter has shared linkage (say it's synthesized for a
// Clang-imported thing), we'll need some other sort of
// stable identifier.
- auto getterRef = SILDeclRef(property->getGetter(), SILDeclRef::Kind::Func);
+ auto getterRef = SILDeclRef(storage->getGetter(), SILDeclRef::Kind::Func);
return SGF.SGM.getFunction(getterRef, NotForDefinition);
}
case AccessStrategy::DispatchToAccessor: {
// Identify the property by its vtable or wtable slot.
// Use the foreign selector if the decl is ObjC-imported, dynamic, or
// otherwise requires objc_msgSend for its ABI.
- return SILDeclRef(property->getGetter(), SILDeclRef::Kind::Func,
+ return SILDeclRef(storage->getGetter(), SILDeclRef::Kind::Func,
ResilienceExpansion::Minimal,
/*curried*/ false,
- /*foreign*/ property->requiresForeignGetterAndSetter());
+ /*foreign*/ storage->requiresForeignGetterAndSetter());
}
case AccessStrategy::BehaviorStorage:
llvm_unreachable("unpossible");
@@ -3184,14 +3621,7 @@
// subscript indexes.
SmallVector<KeyPathPatternComponent, 4> loweredComponents;
auto loweredTy = SGF.getLoweredType(E->getType());
-
- auto unsupported = [&](StringRef message) -> RValue {
- SGF.SGM.diagnose(E->getLoc(), diag::not_implemented, message);
-
- auto undef = SILUndef::get(loweredTy, SGF.SGM.M);
- return RValue(SGF, E, ManagedValue::forUnmanaged(undef));
- };
-
+
CanType rootTy = E->getType()->castTo<BoundGenericType>()->getGenericArgs()[0]
->getCanonicalType();
@@ -3202,6 +3632,7 @@
}
auto baseTy = rootTy;
+ SmallVector<SILValue, 4> operands;
for (auto &component : E->getComponents()) {
switch (auto kind = component.getKind()) {
@@ -3239,24 +3670,26 @@
auto id = getIdForKeyPathComponentComputedProperty(SGF, decl,
strategy);
auto getter = getOrCreateKeyPathGetter(SGF, SILLocation(E),
- decl, strategy,
+ decl, component.getDeclRef().getSubstitutions(),
+ strategy,
needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
+ {},
oldBaseTy, baseTy);
if (decl->isSettable(decl->getDeclContext())) {
auto setter = getOrCreateKeyPathSetter(SGF, SILLocation(E),
- decl, strategy,
+ decl, component.getDeclRef().getSubstitutions(),
+ strategy,
needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
+ {},
oldBaseTy, baseTy);
loweredComponents.push_back(
KeyPathPatternComponent::forComputedSettableProperty(id,
- getter, setter,
- {}, baseTy));
+ getter, setter, {}, nullptr, nullptr, baseTy));
} else {
loweredComponents.push_back(
KeyPathPatternComponent::forComputedGettableProperty(id,
- getter,
- {}, baseTy));
+ getter, {}, nullptr, nullptr, baseTy));
}
break;
}
@@ -3292,8 +3725,95 @@
break;
}
- case KeyPathExpr::Component::Kind::Subscript:
- return unsupported("subscript key path component");
+ case KeyPathExpr::Component::Kind::Subscript: {
+ auto decl = cast<SubscriptDecl>(component.getDeclRef().getDecl());
+ auto strategy = decl->getAccessStrategy(AccessSemantics::Ordinary,
+ AccessKind::ReadWrite);
+ auto oldBaseTy = baseTy;
+ auto baseSubscriptTy =
+ decl->getInterfaceType()->castTo<AnyFunctionType>();
+ if (auto genSubscriptTy = baseSubscriptTy->getAs<GenericFunctionType>())
+ baseSubscriptTy = genSubscriptTy
+ ->substGenericArgs(component.getDeclRef().getSubstitutions());
+ auto baseSubscriptInterfaceTy = cast<AnyFunctionType>(
+ SGF.F.mapTypeOutOfContext(baseSubscriptTy)->getCanonicalType());
+
+ baseTy = baseSubscriptInterfaceTy.getResult();
+
+ // Capturing an index value dependent on the generic context means we
+ // need the generic context captured in the key path.
+ needsGenericContext |=
+ component.getIndexExpr()->getType()->hasArchetype()
+ | baseTy->hasTypeParameter();
+
+ // Evaluate the index arguments.
+ SmallVector<RValue, 2> indexValues;
+ auto indexResult = visit(component.getIndexExpr(), SGFContext());
+ if (auto tup = indexResult.getType()->getAs<TupleType>()) {
+ std::move(indexResult).extractElements(indexValues);
+ } else {
+ indexValues.push_back(std::move(indexResult));
+ }
+
+ SmallVector<KeyPathPatternComponent::Index, 4> indexPatterns;
+ SILFunction *indexEquals = nullptr, *indexHash = nullptr;
+ for (unsigned i : indices(indexValues)) {
+ auto hashable = component.getSubscriptIndexHashableConformances()[i];
+ assert(hashable.isAbstract() ||
+ hashable.getConcrete()->getType()->isEqual(indexValues[i].getType()));
+ auto &value = indexValues[i];
+
+ auto indexTy = SGF.F.mapTypeOutOfContext(value.getType())->getCanonicalType();
+ auto indexLoweredTy = SGF.getLoweredType(value.getType());
+ indexLoweredTy = SILType::getPrimitiveType(
+ SGF.F.mapTypeOutOfContext(indexLoweredTy.getSwiftRValueType())
+ ->getCanonicalType(),
+ indexLoweredTy.getCategory());
+ indexPatterns.push_back({(unsigned)operands.size(),
+ indexTy, indexLoweredTy,
+ hashable});
+ operands.push_back(
+ std::move(indexValues[i]).forwardAsSingleValue(SGF, E));
+ }
+ getOrCreateKeyPathEqualsAndHash(SGF, SILLocation(E),
+ needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
+ indexPatterns,
+ indexEquals, indexHash);
+
+ auto id = getIdForKeyPathComponentComputedProperty(SGF, decl, strategy);
+ auto getter = getOrCreateKeyPathGetter(SGF, SILLocation(E),
+ decl, component.getDeclRef().getSubstitutions(),
+ strategy,
+ needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
+ indexPatterns,
+ oldBaseTy, baseTy);
+
+ auto indexPatternsCopy = SGF.getASTContext().AllocateCopy(indexPatterns);
+ if (decl->isSettable()) {
+ auto setter = getOrCreateKeyPathSetter(SGF, SILLocation(E),
+ decl, component.getDeclRef().getSubstitutions(),
+ strategy,
+ needsGenericContext ? SGF.F.getGenericEnvironment() : nullptr,
+ indexPatterns,
+ oldBaseTy, baseTy);
+ loweredComponents.push_back(
+ KeyPathPatternComponent::forComputedSettableProperty(id,
+ getter, setter,
+ indexPatternsCopy,
+ indexEquals,
+ indexHash,
+ baseTy));
+ } else {
+ loweredComponents.push_back(
+ KeyPathPatternComponent::forComputedGettableProperty(id,
+ getter,
+ indexPatternsCopy,
+ indexEquals,
+ indexHash,
+ baseTy));
+ }
+ break;
+ }
case KeyPathExpr::Component::Kind::Invalid:
case KeyPathExpr::Component::Kind::UnresolvedProperty:
@@ -3319,6 +3839,7 @@
needsGenericContext
? SGF.F.getForwardingSubstitutions()
: SubstitutionList(),
+ operands,
loweredTy);
auto value = SGF.emitManagedRValueWithCleanup(keyPath);
return RValue(SGF, E, value);
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 681d125..1c93cef 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -1057,14 +1057,15 @@
/// \arg isBaseGuaranteed This should /only/ be set to true if we know that
/// the base value will stay alive as long as the returned RValue implying
/// that it is safe to load/use values as +0.
- RValue emitRValueForPropertyLoad(SILLocation loc,
- ManagedValue base,
- CanType baseFormalType,
- bool isSuper, VarDecl *property,
- SubstitutionList substitutions,
- AccessSemantics semantics, Type propTy,
- SGFContext C,
- bool isBaseGuaranteed = false);
+ RValue emitRValueForStorageLoad(SILLocation loc,
+ ManagedValue base,
+ CanType baseFormalType,
+ bool isSuper, AbstractStorageDecl *storage,
+ RValue indexes,
+ SubstitutionList substitutions,
+ AccessSemantics semantics, Type propTy,
+ SGFContext C,
+ bool isBaseGuaranteed = false);
void emitCaptures(SILLocation loc,
AnyFunctionRef TheClosure,
diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
index 8715fc1..802c014 100644
--- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
@@ -49,9 +49,10 @@
/// that the release occurs in the epilog after any retains associated with
/// @owned return values.
///
-/// 3. We do not support specialization of closures with arguments passed using
-/// any indirect calling conventions besides @inout and @inout_aliasable.
-/// This is a temporary limitation.
+/// 3. In !useLoweredAddresses mode, we do not support specialization of closures
+/// with arguments passed using any indirect calling conventions besides
+/// @inout and @inout_aliasable. This is a temporary limitation that goes
+/// away with sil-opaque-values.
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "closure-specialization"
@@ -581,8 +582,9 @@
ParameterConvention ParamConv;
if (PInfo.isFormalIndirect()) {
ParamConv = PInfo.getConvention();
- assert(ParamConv == ParameterConvention::Indirect_Inout ||
- ParamConv == ParameterConvention::Indirect_InoutAliasable);
+ assert(!SILModuleConventions(M).useLoweredAddresses()
+ || ParamConv == ParameterConvention::Indirect_Inout
+ || ParamConv == ParameterConvention::Indirect_InoutAliasable);
} else {
ParamConv = ClosedOverFunConv.getSILType(PInfo).isTrivial(M)
? ParameterConvention::Direct_Unowned
diff --git a/lib/SILOptimizer/IPO/EagerSpecializer.cpp b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
index c549b0e..9df86d7 100644
--- a/lib/SILOptimizer/IPO/EagerSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
@@ -626,7 +626,9 @@
ReInfo.createSpecializedType(SubstitutedType, Builder.getModule());
}
- assert(OrigArgs.size() == ReInfo.getNumArguments() && "signature mismatch");
+ assert(!substConv.useLoweredAddresses()
+ || OrigArgs.size() == ReInfo.getNumArguments() &&
+ "signature mismatch");
CallArgs.reserve(OrigArgs.size());
SILValue StoreResultTo;
diff --git a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
index 9ee8f8f..70ba575 100644
--- a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
+++ b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
@@ -967,18 +967,17 @@
static void createArgumentRelease(SILBuilder &Builder, ArgumentDescriptor &AD) {
auto &F = Builder.getFunction();
- if (AD.PInfo->getConvention() == ParameterConvention::Direct_Owned) {
- Builder.createReleaseValue(RegularLocation(SourceLoc()),
- F.getArguments()[AD.Index],
- Builder.getDefaultAtomicity());
- return;
- }
- if (AD.PInfo->getConvention() == ParameterConvention::Indirect_In) {
+ SILArgument *Arg = F.getArguments()[AD.Index];
+ if (Arg->getType().isAddress()) {
+ assert(AD.PInfo->getConvention() == ParameterConvention::Indirect_In
+ && F.getConventions().useLoweredAddresses());
Builder.createDestroyAddr(RegularLocation(SourceLoc()),
F.getArguments()[AD.Index]);
return;
}
- llvm_unreachable("Parameter convention is not supported");
+ Builder.createReleaseValue(RegularLocation(SourceLoc()),
+ F.getArguments()[AD.Index],
+ Builder.getDefaultAtomicity());
}
/// Set up epilogue work for the thunk arguments based in the given argument.
diff --git a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp
index b5fd8c9..3d8267f 100644
--- a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp
+++ b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp
@@ -173,7 +173,8 @@
// If we have an address only type, do nothing.
SILType Type = Value->getType();
- assert(Type.isLoadable(Module) &&
+ assert(!SILModuleConventions(Module).useLoweredAddresses()
+ || Type.isLoadable(Module) &&
"release_value should never be called on a non-loadable type.");
if (!shouldExpand(Module, Type.getObjectType()))
@@ -199,8 +200,9 @@
// If we have an address only type, do nothing.
SILType Type = Value->getType();
- assert(Type.isLoadable(Module) && "Copy Value can only be called on loadable "
- "types.");
+ assert(!SILModuleConventions(Module).useLoweredAddresses()
+ || Type.isLoadable(Module) &&
+ "Copy Value can only be called on loadable types.");
if (!shouldExpand(Module, Type.getObjectType()))
return false;
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index d1e143d..2115aef 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -3919,7 +3919,12 @@
E->setMethod(method);
return E;
}
-
+
+ private:
+ // Key path components we need to
+ SmallVector<std::pair<KeyPathExpr *, unsigned>, 4>
+ KeyPathSubscriptComponents;
+ public:
Expr *visitKeyPathExpr(KeyPathExpr *E) {
if (E->isObjC()) {
cs.setType(E, cs.getType(E->getObjCStringLiteralExpr()));
@@ -4069,12 +4074,17 @@
resolvedTy = simplifyType(resolvedTy);
auto ref = ConcreteDeclRef(cs.getASTContext(), subscript, subs);
+
component = KeyPathExpr::Component
::forSubscriptWithPrebuiltIndexExpr(ref,
origComponent.getIndexExpr(),
origComponent.getSubscriptLabels(),
resolvedTy,
- origComponent.getLoc());
+ origComponent.getLoc(),
+ {});
+ // Save a reference to the component so we can do a post-pass to check
+ // the Hashable conformance of the indexes.
+ KeyPathSubscriptComponents.push_back({E, resolvedComponents.size()});
break;
}
case KeyPathExpr::Component::Kind::OptionalChain: {
@@ -4216,6 +4226,46 @@
.fixItInsert(cast->getStartLoc(), "(")
.fixItInsertAfter(cast->getEndLoc(), ")");
}
+
+ // Look at key path subscript components to verify that they're hashable.
+ for (auto componentRef : KeyPathSubscriptComponents) {
+ auto &component = componentRef.first
+ ->getMutableComponents()[componentRef.second];
+ // We need to be able to hash the captured index values in order for
+ // KeyPath itself to be hashable, so check that all of the subscript
+ // index components are hashable and collect their conformances here.
+ SmallVector<ProtocolConformanceRef, 2> hashables;
+ bool allIndexesHashable = true;
+ ArrayRef<TupleTypeElt> indexTypes;
+ TupleTypeElt singleIndexTypeBuf;
+ if (auto tup = component.getIndexExpr()->getType()
+ ->getAs<TupleType>()) {
+ indexTypes = tup->getElements();
+ } else {
+ singleIndexTypeBuf = component.getIndexExpr()->getType();
+ indexTypes = singleIndexTypeBuf;
+ }
+
+ auto hashable =
+ cs.getASTContext().getProtocol(KnownProtocolKind::Hashable);
+ for (auto indexType : indexTypes) {
+ auto conformance =
+ cs.TC.conformsToProtocol(indexType.getType(), hashable,
+ cs.DC, ConformanceCheckFlags::Used);
+ if (!conformance) {
+ cs.TC.diagnose(component.getIndexExpr()->getLoc(),
+ diag::expr_keypath_subscript_index_not_hashable,
+ indexType.getType());
+ allIndexesHashable = false;
+ continue;
+ }
+ hashables.push_back(*conformance);
+ }
+
+ if (allIndexesHashable) {
+ component.setSubscriptIndexHashableConformances(hashables);
+ }
+ }
// Set the final types on the expression.
cs.setExprTypes(result);
diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp
index 3b0a42a..30370f1 100644
--- a/lib/Sema/CSBindings.cpp
+++ b/lib/Sema/CSBindings.cpp
@@ -142,37 +142,6 @@
typeVar, constraints, ConstraintGraph::GatheringKind::EquivalenceClass);
PotentialBindings result;
- Optional<unsigned> lastSupertypeIndex;
-
- // Local function to add a potential binding to the list of bindings,
- // coalescing supertype bounds when we are able to compute the meet.
- auto addPotentialBinding = [&](PotentialBinding binding,
- bool allowJoinMeet = true) {
- assert(!binding.BindingType->is<ErrorType>());
- // If this is a non-defaulted supertype binding, check whether we can
- // combine it with another supertype binding by computing the 'join' of the
- // types.
- if (binding.Kind == AllowedBindingKind::Supertypes &&
- !binding.BindingType->hasTypeVariable() && !binding.DefaultedProtocol &&
- !binding.isDefaultableBinding() && allowJoinMeet) {
- if (lastSupertypeIndex) {
- // Can we compute a join?
- auto &lastBinding = result.Bindings[*lastSupertypeIndex];
- auto lastType = lastBinding.BindingType->getWithoutSpecifierType();
- auto bindingType = binding.BindingType->getWithoutSpecifierType();
- if (auto join = Type::join(lastType, bindingType)) {
- // Replace the last supertype binding with the join. We're done.
- lastBinding.BindingType = join;
- return;
- }
- }
-
- // Record this as the most recent supertype index.
- lastSupertypeIndex = result.Bindings.size();
- }
-
- result.Bindings.push_back(std::move(binding));
- };
// Consider each of the constraints related to this type variable.
llvm::SmallPtrSet<CanType, 4> exactTypes;
@@ -284,8 +253,8 @@
continue;
result.foundLiteralBinding(constraint->getProtocol());
- addPotentialBinding({defaultType, AllowedBindingKind::Subtypes,
- constraint->getProtocol()});
+ result.addPotentialBinding({defaultType, AllowedBindingKind::Subtypes,
+ constraint->getProtocol()});
continue;
}
@@ -311,8 +280,8 @@
if (!matched) {
result.foundLiteralBinding(constraint->getProtocol());
exactTypes.insert(defaultType->getCanonicalType());
- addPotentialBinding({defaultType, AllowedBindingKind::Subtypes,
- constraint->getProtocol()});
+ result.addPotentialBinding({defaultType, AllowedBindingKind::Subtypes,
+ constraint->getProtocol()});
}
continue;
@@ -484,10 +453,12 @@
}
if (exactTypes.insert(type->getCanonicalType()).second)
- addPotentialBinding({type, kind, None}, /*allowJoinMeet=*/!adjustedIUO);
+ result.addPotentialBinding({type, kind, None},
+ /*allowJoinMeet=*/!adjustedIUO);
if (alternateType &&
exactTypes.insert(alternateType->getCanonicalType()).second)
- addPotentialBinding({alternateType, kind, None}, /*allowJoinMeet=*/false);
+ result.addPotentialBinding({alternateType, kind, None},
+ /*allowJoinMeet=*/false);
}
// If we have any literal constraints, check whether there is already a
@@ -565,7 +536,7 @@
continue;
++result.NumDefaultableBindings;
- addPotentialBinding(
+ result.addPotentialBinding(
{type, AllowedBindingKind::Exact, None, constraint->getLocator()});
}
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index e1a82c7..ceae16c 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -2575,6 +2575,9 @@
/// Is this type variable on the RHS of a BindParam constraint?
bool IsRHSOfBindParam = false;
+ /// Tracks the position of the last known supertype in the group.
+ Optional<unsigned> lastSupertypeIndex;
+
/// Determine whether the set of bindings is non-empty.
explicit operator bool() const { return !Bindings.empty(); }
@@ -2619,6 +2622,38 @@
}
}
+ /// \brief Add a potential binding to the list of bindings,
+ /// coalescing supertype bounds when we are able to compute the meet.
+ void addPotentialBinding(PotentialBinding binding,
+ bool allowJoinMeet = true) {
+ assert(!binding.BindingType->is<ErrorType>());
+
+ // If this is a non-defaulted supertype binding,
+ // check whether we can combine it with another
+ // supertype binding by computing the 'join' of the types.
+ if (binding.Kind == AllowedBindingKind::Supertypes &&
+ !binding.BindingType->hasTypeVariable() &&
+ !binding.DefaultedProtocol && !binding.isDefaultableBinding() &&
+ allowJoinMeet) {
+ if (lastSupertypeIndex) {
+ // Can we compute a join?
+ auto &lastBinding = Bindings[*lastSupertypeIndex];
+ auto lastType = lastBinding.BindingType->getWithoutSpecifierType();
+ auto bindingType = binding.BindingType->getWithoutSpecifierType();
+ if (auto join = Type::join(lastType, bindingType)) {
+ // Replace the last supertype binding with the join. We're done.
+ lastBinding.BindingType = join;
+ return;
+ }
+ }
+
+ // Record this as the most recent supertype index.
+ lastSupertypeIndex = Bindings.size();
+ }
+
+ Bindings.push_back(std::move(binding));
+ }
+
void dump(llvm::raw_ostream &out,
unsigned indent = 0) const LLVM_ATTRIBUTE_USED {
out.indent(indent);
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 77b4566..162a3f9 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -1460,12 +1460,6 @@
expr = UDE->getBase();
} else if (auto SE = dyn_cast<SubscriptExpr>(expr)) {
- if (!TC.Context.LangOpts.EnableExperimentalKeyPathComponents) {
- TC.diagnose(SE->getLoc(),
- diag::expr_swift_keypath_unimplemented_component,
- "subscript");
- }
-
// .[0] or just plain [0]
components.push_back(
KeyPathExpr::Component::forUnresolvedSubscriptWithPrebuiltIndexExpr(
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index ecd7f5a..4d85138 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -1279,14 +1279,6 @@
ParameterList *params,
unsigned &nextArgIndex,
AbstractFunctionDecl *func) {
- // In Swift 4 mode, default argument bodies are inlined into the
- // caller.
- auto expansion = func->getResilienceExpansion();
- if (!tc.Context.isSwiftVersion3() &&
- func->getFormalAccessScope(/*useDC=*/nullptr,
- /*respectVersionedAttr=*/true).isPublic())
- expansion = ResilienceExpansion::Minimal;
-
for (auto ¶m : *params) {
++nextArgIndex;
if (!param->getDefaultValue() || !param->hasType() ||
@@ -1296,9 +1288,6 @@
Expr *e = param->getDefaultValue();
auto initContext = param->getDefaultArgumentInitContext();
- cast<DefaultArgumentInitializer>(initContext)
- ->changeResilienceExpansion(expansion);
-
// Type-check the initializer, then flag that we did so.
auto resultTy = tc.typeCheckExpression(
e, initContext, TypeLoc::withoutLoc(param->getType()),
@@ -1317,6 +1306,24 @@
}
}
+/// Check the default arguments that occur within this pattern.
+static void checkDefaultArguments(TypeChecker &tc,
+ AbstractFunctionDecl *func) {
+ // In Swift 4 mode, default argument bodies are inlined into the
+ // caller.
+ auto expansion = func->getResilienceExpansion();
+ if (!tc.Context.isSwiftVersion3() &&
+ func->getFormalAccessScope(/*useDC=*/nullptr,
+ /*respectVersionedAttr=*/true).isPublic())
+ expansion = ResilienceExpansion::Minimal;
+
+ func->setDefaultArgumentResilienceExpansion(expansion);
+
+ unsigned nextArgIndex = 0;
+ for (auto paramList : func->getParameterLists())
+ checkDefaultArguments(tc, paramList, nextArgIndex, func);
+}
+
bool TypeChecker::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
SourceLoc EndTypeCheckLoc) {
validateDecl(AFD);
@@ -1358,10 +1365,7 @@
// named function or an anonymous func expression.
bool TypeChecker::typeCheckFunctionBodyUntil(FuncDecl *FD,
SourceLoc EndTypeCheckLoc) {
- // Check the default argument definitions.
- unsigned nextArgIndex = 0;
- for (auto paramList : FD->getParameterLists())
- checkDefaultArguments(*this, paramList, nextArgIndex, FD);
+ checkDefaultArguments(*this, FD);
// Clang imported inline functions do not have a Swift body to
// typecheck.
@@ -1464,10 +1468,7 @@
bool TypeChecker::typeCheckConstructorBodyUntil(ConstructorDecl *ctor,
SourceLoc EndTypeCheckLoc) {
- // Check the default argument definitions.
- unsigned nextArgIndex = 0;
- for (auto paramList : ctor->getParameterLists())
- checkDefaultArguments(*this, paramList, nextArgIndex, ctor);
+ checkDefaultArguments(*this, ctor);
BraceStmt *body = ctor->getBody();
if (!body)
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 7003372..e8c1470 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1942,6 +1942,17 @@
return None;
}
+static
+Optional<swift::ResilienceExpansion> getActualResilienceExpansion(uint8_t raw) {
+ switch (serialization::ResilienceExpansion(raw)) {
+ case serialization::ResilienceExpansion::Minimal:
+ return swift::ResilienceExpansion::Minimal;
+ case serialization::ResilienceExpansion::Maximal:
+ return swift::ResilienceExpansion::Maximal;
+ }
+ return None;
+}
+
void ModuleFile::configureStorage(AbstractStorageDecl *decl,
unsigned rawStorageKind,
serialization::DeclID getter,
@@ -2570,6 +2581,7 @@
TypeID interfaceID;
DeclID overriddenID;
bool needsNewVTableEntry, firstTimeRequired;
+ uint8_t rawDefaultArgumentResilienceExpansion;
unsigned numArgNames;
ArrayRef<uint64_t> argNameAndDependencyIDs;
@@ -2581,6 +2593,7 @@
overriddenID,
rawAccessLevel,
needsNewVTableEntry,
+ rawDefaultArgumentResilienceExpansion,
firstTimeRequired,
numArgNames,
argNameAndDependencyIDs);
@@ -2687,6 +2700,16 @@
if (auto overriddenCtor = cast_or_null<ConstructorDecl>(overridden.get()))
ctor->setOverriddenDecl(overriddenCtor);
ctor->setNeedsNewVTableEntry(needsNewVTableEntry);
+
+ if (auto defaultArgumentResilienceExpansion = getActualResilienceExpansion(
+ rawDefaultArgumentResilienceExpansion)) {
+ ctor->setDefaultArgumentResilienceExpansion(
+ *defaultArgumentResilienceExpansion);
+ } else {
+ error();
+ return nullptr;
+ }
+
break;
}
@@ -2825,6 +2848,7 @@
DeclID overriddenID;
DeclID accessorStorageDeclID;
bool needsNewVTableEntry;
+ uint8_t rawDefaultArgumentResilienceExpansion;
ArrayRef<uint64_t> nameAndDependencyIDs;
decls_block::FuncLayout::readRecord(scratch, contextID, isImplicit,
@@ -2837,6 +2861,7 @@
numNameComponentsBiased,
rawAddressorKind, rawAccessLevel,
needsNewVTableEntry,
+ rawDefaultArgumentResilienceExpansion,
nameAndDependencyIDs);
// Resolve the name ids.
@@ -2974,6 +2999,16 @@
fn->setImplicit();
fn->setDynamicSelf(hasDynamicSelf);
fn->setNeedsNewVTableEntry(needsNewVTableEntry);
+
+ if (auto defaultArgumentResilienceExpansion = getActualResilienceExpansion(
+ rawDefaultArgumentResilienceExpansion)) {
+ fn->setDefaultArgumentResilienceExpansion(
+ *defaultArgumentResilienceExpansion);
+ } else {
+ error();
+ return nullptr;
+ }
+
break;
}
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index a2a9d23..4000929 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -707,7 +707,7 @@
"Expect 5 numbers for SILDeclRef");
SILDeclRef DRef(cast<ValueDecl>(MF->getDecl(ListOfValues[NextIdx])),
(SILDeclRef::Kind)ListOfValues[NextIdx+1],
- (ResilienceExpansion)ListOfValues[NextIdx+2],
+ (swift::ResilienceExpansion)ListOfValues[NextIdx+2],
/*isCurried=*/false, ListOfValues[NextIdx+4] > 0);
if (ListOfValues[NextIdx+3] < DRef.getUncurryLevel())
DRef = DRef.asCurried();
@@ -2106,7 +2106,6 @@
auto valueTy = MF->getType(ListOfValues[nextValue++]);
auto numComponents = ListOfValues[nextValue++];
auto numOperands = ListOfValues[nextValue++];
- assert(numOperands == 0 && "operands not implemented yet");
auto numSubstitutions = ListOfValues[nextValue++];
auto objcString = MF->getIdentifier(ListOfValues[nextValue++]).str();
auto numGenericParams = ListOfValues[nextValue++];
@@ -2118,6 +2117,7 @@
}
SmallVector<KeyPathPatternComponent, 4> components;
+ components.reserve(numComponents);
while (numComponents-- > 0) {
auto kind =
(KeyPathComponentKindEncoding)ListOfValues[nextValue++];
@@ -2142,6 +2142,36 @@
}
};
+ ArrayRef<KeyPathPatternComponent::Index> indices;
+ SILFunction *indicesEquals = nullptr;
+ SILFunction *indicesHash = nullptr;
+
+ auto handleComputedIndices = [&] {
+ SmallVector<KeyPathPatternComponent::Index, 4> indicesBuf;
+ auto numIndexes = ListOfValues[nextValue++];
+ indicesBuf.reserve(numIndexes);
+ while (numIndexes-- > 0) {
+ unsigned operand = ListOfValues[nextValue++];
+ auto formalType = MF->getType(ListOfValues[nextValue++]);
+ auto loweredType = MF->getType(ListOfValues[nextValue++]);
+ auto loweredCategory = (SILValueCategory)ListOfValues[nextValue++];
+ auto conformance = MF->readConformance(SILCursor);
+ indicesBuf.push_back({
+ operand, formalType->getCanonicalType(),
+ SILType::getPrimitiveType(loweredType->getCanonicalType(),
+ loweredCategory),
+ conformance});
+ }
+
+ indices = MF->getContext().AllocateCopy(indicesBuf);
+ if (!indices.empty()) {
+ auto indicesEqualsName = MF->getIdentifier(ListOfValues[nextValue++]);
+ auto indicesHashName = MF->getIdentifier(ListOfValues[nextValue++]);
+ indicesEquals = getFuncForReference(indicesEqualsName.str());
+ indicesHash = getFuncForReference(indicesHashName.str());
+ }
+ };
+
switch (kind) {
case KeyPathComponentKindEncoding::StoredProperty: {
auto decl = cast<VarDecl>(MF->getDecl(ListOfValues[nextValue++]));
@@ -2153,9 +2183,10 @@
auto id = handleComputedId();
auto getterName = MF->getIdentifier(ListOfValues[nextValue++]);
auto getter = getFuncForReference(getterName.str());
+ handleComputedIndices();
components.push_back(
- KeyPathPatternComponent::forComputedGettableProperty(id, getter, {},
- type));
+ KeyPathPatternComponent::forComputedGettableProperty(
+ id, getter, indices, indicesEquals, indicesHash, type));
break;
}
case KeyPathComponentKindEncoding::SettableProperty: {
@@ -2164,10 +2195,10 @@
auto getter = getFuncForReference(getterName.str());
auto setterName = MF->getIdentifier(ListOfValues[nextValue++]);
auto setter = getFuncForReference(setterName.str());
+ handleComputedIndices();
components.push_back(
- KeyPathPatternComponent::forComputedSettableProperty(id,
- getter, setter,
- {}, type));
+ KeyPathPatternComponent::forComputedSettableProperty(
+ id, getter, setter, indices, indicesEquals, indicesHash, type));
break;
}
case KeyPathComponentKindEncoding::OptionalChain:
@@ -2205,7 +2236,18 @@
components,
objcString);
- ResultVal = Builder.createKeyPath(Loc, pattern, substitutions, kpTy);
+ SmallVector<SILValue, 4> operands;
+
+ operands.reserve(numOperands);
+ while (numOperands-- > 0) {
+ auto opValue = ListOfValues[nextValue++];
+ auto opTy = MF->getType(ListOfValues[nextValue++]);
+ auto opCat = (SILValueCategory)ListOfValues[nextValue++];
+ operands.push_back(getLocalValue(opValue, getSILType(opTy, opCat)));
+ }
+
+ ResultVal = Builder.createKeyPath(Loc, pattern,
+ substitutions, operands, kpTy);
break;
}
case ValueKind::MarkUninitializedBehaviorInst:
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index dd008b0..0389a92 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1014,6 +1014,15 @@
llvm_unreachable("bad addressor kind");
}
+static uint8_t getRawStableResilienceExpansion(swift::ResilienceExpansion e) {
+ switch (e) {
+ case swift::ResilienceExpansion::Minimal:
+ return uint8_t(serialization::ResilienceExpansion::Minimal);
+ case swift::ResilienceExpansion::Maximal:
+ return uint8_t(serialization::ResilienceExpansion::Maximal);
+ }
+}
+
void Serializer::writeParameterList(const ParameterList *PL) {
using namespace decls_block;
@@ -2959,6 +2968,9 @@
uint8_t rawAccessLevel = getRawStableAccessLevel(fn->getFormalAccess());
uint8_t rawAddressorKind =
getRawStableAddressorKind(fn->getAddressorKind());
+ uint8_t rawDefaultArgumentResilienceExpansion =
+ getRawStableResilienceExpansion(
+ fn->getDefaultArgumentResilienceExpansion());
Type ty = fn->getInterfaceType();
for (auto dependency : collectDependenciesFromType(ty->getCanonicalType()))
@@ -2987,6 +2999,7 @@
rawAddressorKind,
rawAccessLevel,
fn->needsNewVTableEntry(),
+ rawDefaultArgumentResilienceExpansion,
nameComponentsAndDependencies);
writeGenericParams(fn->getGenericParams());
@@ -3099,6 +3112,9 @@
nameComponentsAndDependencies.push_back(addTypeRef(dependency));
uint8_t rawAccessLevel = getRawStableAccessLevel(ctor->getFormalAccess());
+ uint8_t rawDefaultArgumentResilienceExpansion =
+ getRawStableResilienceExpansion(
+ ctor->getDefaultArgumentResilienceExpansion());
bool firstTimeRequired = ctor->isRequired();
if (auto *overridden = ctor->getOverriddenDecl())
@@ -3122,6 +3138,7 @@
addDeclRef(ctor->getOverriddenDecl()),
rawAccessLevel,
ctor->needsNewVTableEntry(),
+ rawDefaultArgumentResilienceExpansion,
firstTimeRequired,
ctor->getFullName().getArgumentNames().size(),
nameComponentsAndDependencies);
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index b8e2ce4..b759524 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -1865,6 +1865,8 @@
ListOfValues.push_back(0);
}
+ SmallVector<ProtocolConformanceRef, 4> hashableConformances;
+
for (auto &component : pattern->getComponents()) {
auto handleComponentCommon = [&](KeyPathComponentKindEncoding kind) {
ListOfValues.push_back((unsigned)kind);
@@ -1889,6 +1891,25 @@
break;
}
};
+ auto handleComputedIndices
+ = [&](const KeyPathPatternComponent &component) {
+ auto indices = component.getComputedPropertyIndices();
+ ListOfValues.push_back(indices.size());
+ for (auto &index : indices) {
+ ListOfValues.push_back(index.Operand);
+ ListOfValues.push_back(S.addTypeRef(index.FormalType));
+ ListOfValues.push_back(
+ S.addTypeRef(index.LoweredType.getSwiftRValueType()));
+ ListOfValues.push_back((unsigned)index.LoweredType.getCategory());
+ hashableConformances.push_back(index.Hashable);
+ }
+ if (!indices.empty()) {
+ ListOfValues.push_back(
+ addSILFunctionRef(component.getComputedPropertyIndexEquals()));
+ ListOfValues.push_back(
+ addSILFunctionRef(component.getComputedPropertyIndexHash()));
+ }
+ };
switch (component.getKind()) {
case KeyPathPatternComponent::Kind::StoredProperty:
@@ -1900,8 +1921,7 @@
handleComputedId(component.getComputedPropertyId());
ListOfValues.push_back(
addSILFunctionRef(component.getComputedPropertyGetter()));
- assert(component.getComputedPropertyIndices().empty()
- && "indices not implemented");
+ handleComputedIndices(component);
break;
case KeyPathPatternComponent::Kind::SettableProperty:
handleComponentCommon(KeyPathComponentKindEncoding::SettableProperty);
@@ -1910,8 +1930,7 @@
addSILFunctionRef(component.getComputedPropertyGetter()));
ListOfValues.push_back(
addSILFunctionRef(component.getComputedPropertySetter()));
- assert(component.getComputedPropertyIndices().empty()
- && "indices not implemented");
+ handleComputedIndices(component);
break;
case KeyPathPatternComponent::Kind::OptionalChain:
handleComponentCommon(KeyPathComponentKindEncoding::OptionalChain);
@@ -1925,12 +1944,21 @@
}
}
- assert(KPI->getAllOperands().empty() && "operands not implemented yet");
+ for (auto &operand : KPI->getAllOperands()) {
+ auto value = operand.get();
+ ListOfValues.push_back(addValueRef(value));
+ ListOfValues.push_back(S.addTypeRef(value->getType().getSwiftRValueType()));
+ ListOfValues.push_back((unsigned)value->getType().getCategory());
+ }
+
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(KPI->getType().getSwiftRValueType()),
(unsigned)KPI->getType().getCategory(),
ListOfValues);
+ for (auto conformance : hashableConformances) {
+ S.writeConformance(conformance, SILAbbrCodes);
+ }
S.writeGenericRequirements(reqts, SILAbbrCodes);
S.writeSubstitutions(KPI->getSubstitutions(), SILAbbrCodes);
diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift
index 23c621f..61e0a4d 100644
--- a/stdlib/public/core/KeyPath.swift
+++ b/stdlib/public/core/KeyPath.swift
@@ -472,9 +472,6 @@
return false
}
if let arg1 = argument1, let arg2 = argument2 {
- // TODO: Sizes may differ if one key path was formed in a context
- // capturing generic arguments and one wasn't.
- _sanityCheck(arg1.data.count == arg2.data.count)
return arg1.witnesses.pointee.equals(
arg1.data.baseAddress.unsafelyUnwrapped,
arg2.data.baseAddress.unsafelyUnwrapped,
@@ -556,23 +553,26 @@
internal final class MutatingWritebackBuffer<CurValue, NewValue> {
let previous: AnyObject?
let base: UnsafeMutablePointer<CurValue>
- let set: @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer) -> ()
+ let set: @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer, Int) -> ()
let argument: UnsafeRawPointer
+ let argumentSize: Int
var value: NewValue
deinit {
- set(value, &base.pointee, argument)
+ set(value, &base.pointee, argument, argumentSize)
}
init(previous: AnyObject?,
base: UnsafeMutablePointer<CurValue>,
- set: @escaping @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer) -> (),
+ set: @escaping @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer, Int) -> (),
argument: UnsafeRawPointer,
+ argumentSize: Int,
value: NewValue) {
self.previous = previous
self.base = base
self.set = set
self.argument = argument
+ self.argumentSize = argumentSize
self.value = value
}
}
@@ -581,23 +581,26 @@
internal final class NonmutatingWritebackBuffer<CurValue, NewValue> {
let previous: AnyObject?
let base: CurValue
- let set: @convention(thin) (NewValue, CurValue, UnsafeRawPointer) -> ()
+ let set: @convention(thin) (NewValue, CurValue, UnsafeRawPointer, Int) -> ()
let argument: UnsafeRawPointer
+ let argumentSize: Int
var value: NewValue
deinit {
- set(value, base, argument)
+ set(value, base, argument, argumentSize)
}
init(previous: AnyObject?,
base: CurValue,
- set: @escaping @convention(thin) (NewValue, CurValue, UnsafeRawPointer) -> (),
+ set: @escaping @convention(thin) (NewValue, CurValue, UnsafeRawPointer, Int) -> (),
argument: UnsafeRawPointer,
+ argumentSize: Int,
value: NewValue) {
self.previous = previous
self.base = base
self.set = set
self.argument = argument
+ self.argumentSize = argumentSize
self.value = value
}
}
@@ -929,7 +932,6 @@
case .computed:
// Fields are pointer-aligned after the header
componentSize += Header.pointerAlignmentSkew
- // TODO: nontrivial arguments need to be copied by value witness
buffer.storeBytes(of: _computedIDValue,
toByteOffset: MemoryLayout<Int>.size,
as: Int.self)
@@ -1015,9 +1017,11 @@
.mutatingGetSet(id: _, get: let rawGet, set: _, argument: let argument),
.nonmutatingGetSet(id: _, get: let rawGet, set: _, argument: let argument):
typealias Getter
- = @convention(thin) (CurValue, UnsafeRawPointer) -> NewValue
+ = @convention(thin) (CurValue, UnsafeRawPointer, Int) -> NewValue
let get = unsafeBitCast(rawGet, to: Getter.self)
- return .continue(get(base, argument?.data.baseAddress ?? rawGet))
+ return .continue(get(base,
+ argument?.data.baseAddress ?? rawGet,
+ argument?.data.count ?? 0))
case .optionalChain:
// TODO: IUO shouldn't be a first class type
@@ -1079,9 +1083,9 @@
case .mutatingGetSet(id: _, get: let rawGet, set: let rawSet,
argument: let argument):
typealias Getter
- = @convention(thin) (CurValue, UnsafeRawPointer) -> NewValue
+ = @convention(thin) (CurValue, UnsafeRawPointer, Int) -> NewValue
typealias Setter
- = @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer) -> ()
+ = @convention(thin) (NewValue, inout CurValue, UnsafeRawPointer, Int) -> ()
let get = unsafeBitCast(rawGet, to: Getter.self)
let set = unsafeBitCast(rawSet, to: Setter.self)
@@ -1089,11 +1093,13 @@
mutating: base.assumingMemoryBound(to: CurValue.self))
let argValue = argument?.data.baseAddress ?? rawGet
+ let argSize = argument?.data.count ?? 0
let writeback = MutatingWritebackBuffer(previous: keepAlive,
- base: baseTyped,
- set: set,
- argument: argValue,
- value: get(baseTyped.pointee, argValue))
+ base: baseTyped,
+ set: set,
+ argument: argValue,
+ argumentSize: argSize,
+ value: get(baseTyped.pointee, argValue, argSize))
keepAlive = writeback
// A maximally-abstracted, final, stored class property should have
// a stable address.
@@ -1107,20 +1113,22 @@
"nonmutating component should not appear in the middle of mutation")
typealias Getter
- = @convention(thin) (CurValue, UnsafeRawPointer) -> NewValue
+ = @convention(thin) (CurValue, UnsafeRawPointer, Int) -> NewValue
typealias Setter
- = @convention(thin) (NewValue, CurValue, UnsafeRawPointer) -> ()
+ = @convention(thin) (NewValue, CurValue, UnsafeRawPointer, Int) -> ()
let get = unsafeBitCast(rawGet, to: Getter.self)
let set = unsafeBitCast(rawSet, to: Setter.self)
let baseValue = base.assumingMemoryBound(to: CurValue.self).pointee
let argValue = argument?.data.baseAddress ?? rawGet
+ let argSize = argument?.data.count ?? 0
let writeback = NonmutatingWritebackBuffer(previous: keepAlive,
- base: baseValue,
- set: set,
- argument: argValue,
- value: get(baseValue, argValue))
+ base: baseValue,
+ set: set,
+ argument: argValue,
+ argumentSize: argSize,
+ value: get(baseValue, argValue, argSize))
keepAlive = writeback
// A maximally-abstracted, final, stored class property should have
// a stable address.
diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm
index e87e0e1..1a0d38c 100644
--- a/stdlib/public/runtime/SwiftObject.mm
+++ b/stdlib/public/runtime/SwiftObject.mm
@@ -869,7 +869,8 @@
!objectUsesNativeSwiftReferenceCounting(value));
}
-void swift::swift_unknownUnownedInit(UnownedReference *dest, void *value) {
+UnownedReference *swift::swift_unknownUnownedInit(UnownedReference *dest,
+ void *value) {
if (!value) {
dest->Value = nullptr;
} else if (isObjCForUnownedReference(value)) {
@@ -877,9 +878,11 @@
} else {
swift_unownedInit(dest, (HeapObject*) value);
}
+ return dest;
}
-void swift::swift_unknownUnownedAssign(UnownedReference *dest, void *value) {
+UnownedReference *swift::swift_unknownUnownedAssign(UnownedReference *dest,
+ void *value) {
if (!value) {
swift_unknownUnownedDestroy(dest);
dest->Value = nullptr;
@@ -898,6 +901,7 @@
swift_unownedAssign(dest, (HeapObject*) value);
}
}
+ return dest;
}
void *swift::swift_unknownUnownedLoadStrong(UnownedReference *ref) {
@@ -941,8 +945,8 @@
}
}
-void swift::swift_unknownUnownedCopyInit(UnownedReference *dest,
- UnownedReference *src) {
+UnownedReference *swift::swift_unknownUnownedCopyInit(UnownedReference *dest,
+ UnownedReference *src) {
assert(dest != src);
if (!src->Value) {
dest->Value = nullptr;
@@ -951,17 +955,19 @@
} else {
swift_unownedCopyInit(dest, src);
}
+ return dest;
}
-void swift::swift_unknownUnownedTakeInit(UnownedReference *dest,
- UnownedReference *src) {
+UnownedReference *swift::swift_unknownUnownedTakeInit(UnownedReference *dest,
+ UnownedReference *src) {
assert(dest != src);
dest->Value = src->Value;
+ return dest;
}
-void swift::swift_unknownUnownedCopyAssign(UnownedReference *dest,
- UnownedReference *src) {
- if (dest == src) return;
+UnownedReference *swift::swift_unknownUnownedCopyAssign(UnownedReference *dest,
+ UnownedReference *src) {
+ if (dest == src) return dest;
if (auto objcSrc = dyn_cast<ObjCUnownedReference>(src)) {
if (auto objcDest = dyn_cast<ObjCUnownedReference>(dest)) {
@@ -969,7 +975,7 @@
objc_destroyWeak(&objcDest->storage()->WeakRef);
objc_copyWeak(&objcDest->storage()->WeakRef,
&objcSrc->storage()->WeakRef);
- return;
+ return dest;
}
swift_unownedDestroy(dest);
@@ -982,15 +988,17 @@
swift_unownedCopyAssign(dest, src);
}
}
+ return dest;
}
-void swift::swift_unknownUnownedTakeAssign(UnownedReference *dest,
- UnownedReference *src) {
+UnownedReference *swift::swift_unknownUnownedTakeAssign(UnownedReference *dest,
+ UnownedReference *src) {
assert(dest != src);
// There's not really anything more efficient to do here than this.
swift_unknownUnownedDestroy(dest);
dest->Value = src->Value;
+ return dest;
}
bool swift::swift_unknownUnownedIsEqual(UnownedReference *ref, void *value) {
@@ -1012,12 +1020,14 @@
/************************** UNKNOWN WEAK REFERENCES **************************/
/*****************************************************************************/
-void swift::swift_unknownWeakInit(WeakReference *ref, void *value) {
- return ref->unknownInit(value);
+WeakReference *swift::swift_unknownWeakInit(WeakReference *ref, void *value) {
+ ref->unknownInit(value);
+ return ref;
}
-void swift::swift_unknownWeakAssign(WeakReference *ref, void *value) {
- return ref->unknownAssign(value);
+WeakReference *swift::swift_unknownWeakAssign(WeakReference *ref, void *value) {
+ ref->unknownAssign(value);
+ return ref;
}
void *swift::swift_unknownWeakLoadStrong(WeakReference *ref) {
@@ -1032,19 +1042,25 @@
ref->unknownDestroy();
}
-void swift::swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src) {
+WeakReference *swift::swift_unknownWeakCopyInit(WeakReference *dest,
+ WeakReference *src) {
dest->unknownCopyInit(src);
+ return dest;
}
-void swift::swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src) {
+WeakReference *swift::swift_unknownWeakTakeInit(WeakReference *dest,
+ WeakReference *src) {
dest->unknownTakeInit(src);
+ return dest;
}
-void swift::swift_unknownWeakCopyAssign(WeakReference *dest,
- WeakReference *src) {
+WeakReference *swift::swift_unknownWeakCopyAssign(WeakReference *dest,
+ WeakReference *src) {
dest->unknownCopyAssign(src);
+ return dest;
}
-void swift::swift_unknownWeakTakeAssign(WeakReference *dest,
- WeakReference *src) {
+WeakReference *swift::swift_unknownWeakTakeAssign(WeakReference *dest,
+ WeakReference *src) {
dest->unknownTakeAssign(src);
+ return dest;
}
// SWIFT_OBJC_INTEROP
diff --git a/stdlib/public/stubs/KeyPaths.cpp b/stdlib/public/stubs/KeyPaths.cpp
index 889ec10..053dc20 100644
--- a/stdlib/public/stubs/KeyPaths.cpp
+++ b/stdlib/public/stubs/KeyPaths.cpp
@@ -15,8 +15,8 @@
#include <cstdint>
#include <cstring>
-SWIFT_CC(swift)
-static void copyGenericArguments(const void *src, void *dest, size_t bytes) {
+SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
+void swift_copyKeyPathTrivialIndices(const void *src, void *dest, size_t bytes) {
memcpy(dest, src, bytes);
}
@@ -42,7 +42,7 @@
SWIFT_RUNTIME_EXPORT
void *(swift_keyPathGenericWitnessTable[]) = {
nullptr, // no destructor necessary
- (void*)(uintptr_t)copyGenericArguments,
+ (void*)(uintptr_t)swift_copyKeyPathTrivialIndices,
(void*)(uintptr_t)equateGenericArguments,
(void*)(uintptr_t)hashGenericArguments,
};
diff --git a/stdlib/public/stubs/UnicodeNormalization.cpp b/stdlib/public/stubs/UnicodeNormalization.cpp
index 950f2e4..2c9fb2f 100644
--- a/stdlib/public/stubs/UnicodeNormalization.cpp
+++ b/stdlib/public/stubs/UnicodeNormalization.cpp
@@ -336,9 +336,9 @@
#if defined(__CYGWIN__) || defined( _MSC_VER) || defined(__linux__)
return ptr_cast<swift::__swift_stdlib_UBreakIterator>(
ubrk_open(static_cast<UBreakIteratorType>(type), locale,
- reinterpret_cast<const UChar*>(text), textLength,
+ reinterpret_cast<const UChar *>(text), textLength,
ptr_cast<UErrorCode>(status)));
-#else
+#else
return ptr_cast<swift::__swift_stdlib_UBreakIterator>(
ubrk_open(static_cast<UBreakIteratorType>(type), locale, text, textLength,
ptr_cast<UErrorCode>(status)));
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
index 6fd1676..af8b3b3 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes
@@ -65,6 +65,23 @@
Tags:
- Name: InnerInSwift4
SwiftName: Outer.Inner
+Globals:
+ - Name: multiVersionedGlobal34Notes
+ SwiftName: multiVersionedGlobal34Notes_NEW
+ - Name: multiVersionedGlobal34Both
+ SwiftName: multiVersionedGlobal34Both_NEW
+ - Name: multiVersionedGlobal345Notes
+ SwiftName: multiVersionedGlobal345Notes_NEW
+ - Name: multiVersionedGlobal345Both
+ SwiftName: multiVersionedGlobal345Both_NEW
+ - Name: multiVersionedGlobal4Notes
+ SwiftName: multiVersionedGlobal4Notes_NEW
+ - Name: multiVersionedGlobal4Both
+ SwiftName: multiVersionedGlobal4Both_NEW
+ - Name: multiVersionedGlobal45Notes
+ SwiftName: multiVersionedGlobal45Notes_NEW
+ - Name: multiVersionedGlobal45Both
+ SwiftName: multiVersionedGlobal45Both_NEW
SwiftVersions:
- Version: 3.0
Classes:
@@ -207,3 +224,72 @@
SwiftName: aliasRenamedSwift3
- Name: OptionyEnumRenamed
SwiftName: renamedSwift3
+ Globals:
+ - Name: multiVersionedGlobal34
+ SwiftName: multiVersionedGlobal34_3
+ - Name: multiVersionedGlobal34Header
+ SwiftName: multiVersionedGlobal34Header_3
+ - Name: multiVersionedGlobal34Notes
+ SwiftName: multiVersionedGlobal34Notes_3
+ - Name: multiVersionedGlobal34Both
+ SwiftName: multiVersionedGlobal34Both_3
+ - Name: multiVersionedGlobal345
+ SwiftName: multiVersionedGlobal345_3
+ - Name: multiVersionedGlobal345Header
+ SwiftName: multiVersionedGlobal345Header_3
+ - Name: multiVersionedGlobal345Notes
+ SwiftName: multiVersionedGlobal345Notes_3
+ - Name: multiVersionedGlobal345Both
+ SwiftName: multiVersionedGlobal345Both_3
+ - Version: 5
+ Globals:
+ - Name: multiVersionedGlobal345
+ SwiftName: multiVersionedGlobal345_5
+ - Name: multiVersionedGlobal345Header
+ SwiftName: multiVersionedGlobal345Header_5
+ - Name: multiVersionedGlobal345Notes
+ SwiftName: multiVersionedGlobal345Notes_5
+ - Name: multiVersionedGlobal345Both
+ SwiftName: multiVersionedGlobal345Both_5
+ - Name: multiVersionedGlobal45
+ SwiftName: multiVersionedGlobal45_5
+ - Name: multiVersionedGlobal45Header
+ SwiftName: multiVersionedGlobal45Header_5
+ - Name: multiVersionedGlobal45Notes
+ SwiftName: multiVersionedGlobal45Notes_5
+ - Name: multiVersionedGlobal45Both
+ SwiftName: multiVersionedGlobal45Both_5
+ - Version: 4 # Versions are deliberately ordered as "3, 5, 4" to catch bugs.
+ Globals:
+ - Name: multiVersionedGlobal34
+ SwiftName: multiVersionedGlobal34_4
+ - Name: multiVersionedGlobal34Header
+ SwiftName: multiVersionedGlobal34Header_4
+ - Name: multiVersionedGlobal34Notes
+ SwiftName: multiVersionedGlobal34Notes_4
+ - Name: multiVersionedGlobal34Both
+ SwiftName: multiVersionedGlobal34Both_4
+ - Name: multiVersionedGlobal345
+ SwiftName: multiVersionedGlobal345_4
+ - Name: multiVersionedGlobal345Header
+ SwiftName: multiVersionedGlobal345Header_4
+ - Name: multiVersionedGlobal345Notes
+ SwiftName: multiVersionedGlobal345Notes_4
+ - Name: multiVersionedGlobal345Both
+ SwiftName: multiVersionedGlobal345Both_4
+ - Name: multiVersionedGlobal4
+ SwiftName: multiVersionedGlobal4_4
+ - Name: multiVersionedGlobal4Header
+ SwiftName: multiVersionedGlobal4Header_4
+ - Name: multiVersionedGlobal4Notes
+ SwiftName: multiVersionedGlobal4Notes_4
+ - Name: multiVersionedGlobal4Both
+ SwiftName: multiVersionedGlobal4Both_4
+ - Name: multiVersionedGlobal45
+ SwiftName: multiVersionedGlobal45_4
+ - Name: multiVersionedGlobal45Header
+ SwiftName: multiVersionedGlobal45Header_4
+ - Name: multiVersionedGlobal45Notes
+ SwiftName: multiVersionedGlobal45Notes_4
+ - Name: multiVersionedGlobal45Both
+ SwiftName: multiVersionedGlobal45Both_4
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
index c3a23fd..43c932c 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
@@ -32,6 +32,7 @@
#import <APINotesFrameworkTest/Classes.h>
#import <APINotesFrameworkTest/Enums.h>
+#import <APINotesFrameworkTest/Globals.h>
#import <APINotesFrameworkTest/ImportAsMember.h>
#import <APINotesFrameworkTest/Properties.h>
#import <APINotesFrameworkTest/Protocols.h>
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Globals.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Globals.h
new file mode 100644
index 0000000..059ecd7
--- /dev/null
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Globals.h
@@ -0,0 +1,23 @@
+#pragma clang assume_nonnull begin
+
+int multiVersionedGlobal4;
+int multiVersionedGlobal4Notes;
+int multiVersionedGlobal4Header __attribute__((swift_name("multiVersionedGlobal4Header_NEW")));
+int multiVersionedGlobal4Both __attribute__((swift_name("multiVersionedGlobal4Both_OLD")));
+
+int multiVersionedGlobal34;
+int multiVersionedGlobal34Notes;
+int multiVersionedGlobal34Header __attribute__((swift_name("multiVersionedGlobal34Header_NEW")));
+int multiVersionedGlobal34Both __attribute__((swift_name("multiVersionedGlobal34Both_OLD")));
+
+int multiVersionedGlobal45;
+int multiVersionedGlobal45Notes;
+int multiVersionedGlobal45Header __attribute__((swift_name("multiVersionedGlobal45Header_NEW")));
+int multiVersionedGlobal45Both __attribute__((swift_name("multiVersionedGlobal45Both_OLD")));
+
+int multiVersionedGlobal345;
+int multiVersionedGlobal345Notes;
+int multiVersionedGlobal345Header __attribute__((swift_name("multiVersionedGlobal345Header_NEW")));
+int multiVersionedGlobal345Both __attribute__((swift_name("multiVersionedGlobal345Both_OLD")));
+
+#pragma clang assume_nonnull end
diff --git a/test/APINotes/versioned-multi.swift b/test/APINotes/versioned-multi.swift
new file mode 100644
index 0000000..d479c3c
--- /dev/null
+++ b/test/APINotes/versioned-multi.swift
@@ -0,0 +1,297 @@
+// RUN: %empty-directory(%t)
+
+// RUN: %target-swift-ide-test -F %S/Inputs/custom-frameworks -print-module -source-filename %s -module-to-print=APINotesFrameworkTest -function-definitions=false -print-regular-comments -swift-version 3 | %FileCheck -check-prefix=CHECK-SWIFT-3 %s
+
+// RUN: %target-swift-ide-test -F %S/Inputs/custom-frameworks -print-module -source-filename %s -module-to-print=APINotesFrameworkTest -function-definitions=false -swift-version 4 | %FileCheck -check-prefix=CHECK-SWIFT-4 %s
+
+// RUN: %target-swift-ide-test -F %S/Inputs/custom-frameworks -print-module -source-filename %s -module-to-print=APINotesFrameworkTest -function-definitions=false -swift-version 5 | %FileCheck -check-prefix=CHECK-SWIFT-5 %s
+
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal4_4: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Notes_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4Notes: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal4Notes_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal4Notes_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4Notes_NEW: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Header_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4Header: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal4Header_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal4Header_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4Header_NEW: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Both_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4Both: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal4Both_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal4Both_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal4Both_NEW: Int32
+
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal34_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal34_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34_4: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Notes_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Notes: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal34Notes_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal34Notes_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Notes_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal34Notes_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Notes_NEW: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Header_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Header: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal34Header_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal34Header_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Header_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal34Header_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Header_NEW: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Both_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Both: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal34Both_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal34Both_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Both_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal34Both_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal34Both_NEW: Int32
+
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal45_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45_5: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Notes_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45Notes: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal45Notes_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45Notes_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45Notes_5: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Header_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45Header: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal45Header_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45Header_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45Header_5: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Both_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45Both: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal45Both_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45Both_4")
+// CHECK-SWIFT-3: var multiVersionedGlobal45Both_5: Int32
+
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal345_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal345_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345_5: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Notes_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Notes: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal345Notes_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal345Notes_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Notes_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345Notes_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Notes_5: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Header_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Header: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal345Header_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal345Header_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Header_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345Header_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Header_5: Int32
+// CHECK-SWIFT-3: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Both_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Both: Int32
+// CHECK-SWIFT-3: var multiVersionedGlobal345Both_3: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 4, renamed: "multiVersionedGlobal345Both_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Both_4: Int32
+// CHECK-SWIFT-3: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345Both_3")
+// CHECK-SWIFT-3: var multiVersionedGlobal345Both_5: Int32
+
+
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal4_4: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4Notes: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal4Notes_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal4Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4Notes_NEW: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4Header: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal4Header_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal4Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4Header_NEW: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4Both: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal4Both_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal4Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal4Both_NEW: Int32
+
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal34_4: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Notes: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Notes_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal34Notes_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal34Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Notes_NEW: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Header: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Header_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal34Header_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal34Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Header_NEW: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Both: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Both_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal34Both_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal34Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal34Both_NEW: Int32
+
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal45_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45_5: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45Notes: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal45Notes_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45Notes_5: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45Header: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal45Header_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45Header_5: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45Both: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal45Both_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal45Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal45Both_5: Int32
+
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal345_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345_5: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Notes: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Notes_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal345Notes_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345Notes_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Notes_5: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Header: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Header_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal345Header_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345Header_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Header_5: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Both: Int32
+// CHECK-SWIFT-4: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Both_3: Int32
+// CHECK-SWIFT-4: var multiVersionedGlobal345Both_4: Int32
+// CHECK-SWIFT-4: @available(swift, introduced: 5, renamed: "multiVersionedGlobal345Both_4")
+// CHECK-SWIFT-4: var multiVersionedGlobal345Both_5: Int32
+
+
+// CHECK-SWIFT-5: var multiVersionedGlobal4: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal4")
+// CHECK-SWIFT-5: var multiVersionedGlobal4_4: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Notes_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal4Notes: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal4Notes_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal4Notes_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal4Notes_NEW: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Header_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal4Header: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal4Header_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal4Header_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal4Header_NEW: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal4Both_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal4Both: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal4Both_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal4Both_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal4Both_NEW: Int32
+
+// CHECK-SWIFT-5: var multiVersionedGlobal34: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34")
+// CHECK-SWIFT-5: var multiVersionedGlobal34_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal34")
+// CHECK-SWIFT-5: var multiVersionedGlobal34_4: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Notes_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Notes: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34Notes_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Notes_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal34Notes_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Notes_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal34Notes_NEW: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Header_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Header: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34Header_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Header_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal34Header_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Header_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal34Header_NEW: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal34Both_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Both: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal34Both_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Both_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal34Both_NEW")
+// CHECK-SWIFT-5: var multiVersionedGlobal34Both_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal34Both_NEW: Int32
+
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal45_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal45_5: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Notes_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45Notes: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal45Notes_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45Notes_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal45Notes_5: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Header_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45Header: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal45Header_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45Header_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal45Header_5: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal45Both_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45Both: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal45Both_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal45Both_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal45Both_5: Int32
+
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal345_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal345_5: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Notes_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Notes: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345Notes_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Notes_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal345Notes_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Notes_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal345Notes_5: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Header_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Header: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345Header_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Header_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal345Header_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Header_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal345Header_5: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 3, renamed: "multiVersionedGlobal345Both_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Both: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 4, renamed: "multiVersionedGlobal345Both_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Both_3: Int32
+// CHECK-SWIFT-5: @available(swift, obsoleted: 5, renamed: "multiVersionedGlobal345Both_5")
+// CHECK-SWIFT-5: var multiVersionedGlobal345Both_4: Int32
+// CHECK-SWIFT-5: var multiVersionedGlobal345Both_5: Int32
diff --git a/test/IDE/coloring.swift b/test/IDE/coloring.swift
index 24e915f..f9797b3 100644
--- a/test/IDE/coloring.swift
+++ b/test/IDE/coloring.swift
@@ -227,6 +227,15 @@
// CHECK: <str>"This is string </str>\<anchor>(</anchor>genFn({(a:<type>Int</type> -> <type>Int</type>) <kw>in</kw> a})<anchor>)</anchor><str> interpolation"</str>
"This is string \(genFn({(a:Int -> Int) in a})) interpolation"
+ // CHECK: <str>"This is unterminated</str>
+ "This is unterminated
+
+ // CHECK: <str>"This is unterminated with ignored \(interpolation) in it</str>
+ "This is unterminated with ignored \(interpolation) in it
+
+ // CHECK: <str>"This is terminated with invalid \(interpolation" + "in it"</str>
+ "This is terminated with invalid \(interpolation" + "in it"
+
// CHECK: <str>"""
// CHECK-NEXT: This is a multiline string.
// CHECK-NEXT: """</str>
@@ -236,9 +245,19 @@
// CHECK: <str>"""
// CHECK-NEXT: This is a multiline</str>\<anchor>(</anchor> <str>"interpolated"</str> <anchor>)</anchor><str>string
+ // CHECK-NEXT: </str>\<anchor>(</anchor>
+ // CHECK-NEXT: <str>"""
+ // CHECK-NEXT: inner
+ // CHECK-NEXT: """</str>
+ // CHECK-NEXT: <anchor>)</anchor><str>
// CHECK-NEXT: """</str>
"""
This is a multiline\( "interpolated" )string
+ \(
+ """
+ inner
+ """
+ )
"""
// CHECK: <str>"</str>\<anchor>(</anchor><int>1</int><anchor>)</anchor>\<anchor>(</anchor><int>1</int><anchor>)</anchor><str>"</str>
diff --git a/test/IDE/unterminated_multiline.swift b/test/IDE/unterminated_multiline.swift
new file mode 100644
index 0000000..4fd7a60
--- /dev/null
+++ b/test/IDE/unterminated_multiline.swift
@@ -0,0 +1,16 @@
+// RUN: %target-swift-ide-test -syntax-coloring -source-filename %s | %FileCheck %s
+// RUN: %target-swift-ide-test -syntax-coloring -typecheck -source-filename %s | %FileCheck %s
+
+// CHECK: <kw>let</kw> x = <str>"""
+// CHECK-NEXT: This is an unterminated
+// CHECK-NEXT: \( "multiline" )
+// CHECK-NEXT: string followed by code
+// CHECK-NEXT: ""
+// CHECK-NEXT: func foo() {}
+// CHECK-NEXT: </str>
+let x = """
+ This is an unterminated
+ \( "multiline" )
+ string followed by code
+ ""
+func foo() {}
diff --git a/test/IRGen/existentials_objc.sil b/test/IRGen/existentials_objc.sil
index 420bd81..746707c 100644
--- a/test/IRGen/existentials_objc.sil
+++ b/test/IRGen/existentials_objc.sil
@@ -80,7 +80,7 @@
// CHECK: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[U1]], i32 0, i32 1
// CHECK: store i8** %1, i8*** [[T0]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[U1]], i32 0, i32 0
- // CHECK: call void @swift_unknownUnownedInit(%swift.unowned* [[T0]], %objc_object* %0)
+ // CHECK: call %swift.unowned* @swift_unknownUnownedInit(%swift.unowned* [[T0]], %objc_object* %0)
// CHECK: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[U1]], i32 0, i32 0
// CHECK: [[T1:%.*]] = call %objc_object* @swift_unknownUnownedLoadStrong(%swift.unowned* [[T0]])
@@ -112,7 +112,7 @@
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: store i8** [[SRC_WITNESS]], i8*** [[DEST_WITNESS_ADDR]]
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
- // CHECK: call void @swift_unknownWeakInit(%swift.weak* [[DEST_REF_ADDR]], %objc_object* [[SRC_REF]])
+ // CHECK: call %swift.weak* @swift_unknownWeakInit(%swift.weak* [[DEST_REF_ADDR]], %objc_object* [[SRC_REF]])
store_weak %a to [initialization] %w : $*@sil_weak CP?
// CHECK: [[SRC_REF:%.*]] = inttoptr {{.*}} %objc_object*
@@ -120,7 +120,7 @@
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: store i8** [[SRC_WITNESS]], i8*** [[DEST_WITNESS_ADDR]]
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
- // CHECK: call void @swift_unknownWeakAssign(%swift.weak* [[DEST_REF_ADDR]], %objc_object* [[SRC_REF]])
+ // CHECK: call %swift.weak* @swift_unknownWeakAssign(%swift.weak* [[DEST_REF_ADDR]], %objc_object* [[SRC_REF]])
store_weak %a to %w : $*@sil_weak CP?
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
@@ -137,7 +137,7 @@
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 0
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
- // CHECK: call void @swift_unknownWeakTakeInit(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
+ // CHECK: call %swift.weak* @swift_unknownWeakTakeInit(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
// CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: [[WITNESS:%.*]] = load i8**, i8*** [[SRC_WITNESS_ADDR]], align 8
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 1
@@ -146,7 +146,7 @@
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 0
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
- // CHECK: call void @swift_unknownWeakTakeAssign(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
+ // CHECK: call %swift.weak* @swift_unknownWeakTakeAssign(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
// CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: [[WITNESS:%.*]] = load i8**, i8*** [[SRC_WITNESS_ADDR]], align 8
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 1
@@ -155,7 +155,7 @@
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 0
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
- // CHECK: call void @swift_unknownWeakCopyInit(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
+ // CHECK: call %swift.weak* @swift_unknownWeakCopyInit(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
// CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: [[WITNESS:%.*]] = load i8**, i8*** [[SRC_WITNESS_ADDR]], align 8
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 1
@@ -164,7 +164,7 @@
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 0
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
- // CHECK: call void @swift_unknownWeakCopyAssign(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
+ // CHECK: call %swift.weak* @swift_unknownWeakCopyAssign(%swift.weak* [[DEST_REF_ADDR]], %swift.weak* [[SRC_REF_ADDR]])
// CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: [[WITNESS:%.*]] = load i8**, i8*** [[SRC_WITNESS_ADDR]], align 8
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* [[V]], i32 0, i32 1
diff --git a/test/IRGen/keypaths.sil b/test/IRGen/keypaths.sil
index 4cb4074..b7dbb0e 100644
--- a/test/IRGen/keypaths.sil
+++ b/test/IRGen/keypaths.sil
@@ -6,19 +6,25 @@
sil_stage canonical
import Swift
-struct S {
+struct S: Hashable {
var x: Int
let y: String
var z: C
var reabstracted: () -> ()
+
+ var hashValue: Int { get }
+ static func ==(_: S, _: S) -> Bool
}
-class C {
+class C: Hashable {
final var x: Int
final let y: String
final var z: S
var w: Int { get set }
init()
+
+ var hashValue: Int { get }
+ static func ==(_: C, _: C) -> Bool
}
sil_vtable C {}
@@ -260,23 +266,20 @@
// CHECK-LABEL: define{{( protected)?}} swiftcc void @stored_property_generics(%swift.type* %T, %swift.type* %U)
sil @stored_property_generics : $@convention(thin) <T, U> () -> () {
entry:
- // CHECK: [[PTR:%.*]] = bitcast [1 x %swift.type*]* [[ARGS:%.*]] to
+ // CHECK: [[PTR:%.*]] = bitcast i8* [[ARGS:%.*]] to
// CHECK: store %swift.type* %T, %swift.type** [[PTR]]
- // CHECK: [[ARGS_I8:%.*]] = bitcast [1 x %swift.type*]* [[ARGS]] to
- // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_I]] to i8*), i8* [[ARGS_I8]])
+ // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_I]] to i8*), i8* [[ARGS]])
%i = keypath $KeyPath<Gen<T,T>, T>, <A> (root $Gen<A, A>; stored_property #Gen.x : $A) <T>
- // CHECK: [[PTR:%.*]] = bitcast [1 x %swift.type*]* [[ARGS:%.*]] to
+ // CHECK: [[PTR:%.*]] = bitcast i8* [[ARGS:%.*]] to
// CHECK: store %swift.type* %U, %swift.type** [[PTR]]
- // CHECK: [[ARGS_I8:%.*]] = bitcast [1 x %swift.type*]* [[ARGS]] to
- // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_J]] to i8*), i8* [[ARGS_I8]])
+ // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_J]] to i8*), i8* [[ARGS]])
%j = keypath $KeyPath<Gen<U,U>, U>, <A> (root $Gen<A, A>; stored_property #Gen.y : $A) <U>
- // CHECK: [[PTR:%.*]] = bitcast [1 x %swift.type*]* [[ARGS:%.*]] to
+ // CHECK: [[PTR:%.*]] = bitcast i8* [[ARGS:%.*]] to
// CHECK: [[FOO_T:%.*]] = call %swift.type* @_T08keypaths3FooVMa(%swift.type* %T)
// CHECK: store %swift.type* [[FOO_T]], %swift.type** [[PTR]]
- // CHECK: [[ARGS_I8:%.*]] = bitcast [1 x %swift.type*]* [[ARGS]] to
- // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_I]] to i8*), i8* [[ARGS_I8]])
+ // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_I]] to i8*), i8* [[ARGS]])
%i2 = keypath $KeyPath<Gen<Foo<T>,Foo<T>>, Foo<T>>, <A> (root $Gen<A, A>; stored_property #Gen.x : $A) <Foo<T>>
return undef : $()
@@ -304,3 +307,105 @@
sil @n_get : $@convention(thin) <UU, TT> (@in TT) -> @out UU
sil @n_set : $@convention(thin) <UU, TT> (@in UU, @in TT) -> ()
+
+sil @computed_property_indices : $@convention(thin) (C, S, C, S, C, S) -> () {
+entry(%0 : $C, %1 : $S, %2 : $C, %3 : $S, %4 : $C, %5 : $S):
+ %o = keypath $WritableKeyPath<S, C>, (
+ root $S;
+ settable_property $C,
+ id @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C,
+ getter @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C,
+ setter @o_set : $@convention(thin) (@in C, @in S, UnsafeRawPointer) -> (),
+ indices [%$0 : $C : $C],
+ indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+ ) (%0)
+ %p = keypath $WritableKeyPath<S, C>, (
+ root $S;
+ settable_property $C,
+ id @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C,
+ getter @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C,
+ setter @o_set : $@convention(thin) (@in C, @in S, UnsafeRawPointer) -> (),
+ indices [%$0 : $S : $S, %$1 : $C : $C],
+ indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+ ) (%1, %2)
+ %r = keypath $WritableKeyPath<S, S>, (
+ root $S;
+ settable_property $C,
+ id @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C,
+ getter @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C,
+ setter @o_set : $@convention(thin) (@in C, @in S, UnsafeRawPointer) -> (),
+ indices [%$0 : $S : $S, %$1 : $C : $C],
+ indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int;
+ settable_property $S,
+ id @r_get : $@convention(thin) (@in C, UnsafeRawPointer) -> @out S,
+ getter @r_get : $@convention(thin) (@in C, UnsafeRawPointer) -> @out S,
+ setter @r_set : $@convention(thin) (@in S, @in C, UnsafeRawPointer) -> (),
+ indices [%$2 : $S : $S],
+ indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+ ) (%3, %4, %5)
+
+ return undef : $()
+}
+
+sil @o_get : $@convention(thin) (@in S, UnsafeRawPointer) -> @out C
+sil @o_set : $@convention(thin) (@in C, @in S, UnsafeRawPointer) -> ()
+sil @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+
+sil @r_get : $@convention(thin) (@in C, UnsafeRawPointer) -> @out S
+sil @r_set : $@convention(thin) (@in S, @in C, UnsafeRawPointer) -> ()
+
+sil @generic_computed_property_indices : $@convention(thin) <A: Hashable, B: Hashable> (@in A, @in B, @in A, @in B, @in A, @in B) -> () {
+entry(%0 : $*A, %1 : $*B, %2 : $*A, %3 : $*B, %4 : $*A, %5 : $*B):
+ %s = keypath $WritableKeyPath<A, B>, <X: Hashable, Y: Hashable> (
+ root $X;
+ settable_property $Y,
+ id @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in T, UnsafeRawPointer) -> @out U,
+ getter @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in T, UnsafeRawPointer) -> @out U,
+ setter @s_set : $@convention(thin) <T: Hashable, U: Hashable> (@in U, @in T, UnsafeRawPointer) -> (),
+ indices [%$0 : $X : $*X],
+ indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int
+ ) <A, B> (%0)
+ %t = keypath $WritableKeyPath<A, B>, <X: Hashable, Y: Hashable> (
+ root $X;
+ settable_property $Y,
+ id @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in T, UnsafeRawPointer) -> @out U,
+ getter @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in T, UnsafeRawPointer) -> @out U,
+ setter @s_set : $@convention(thin) <T: Hashable, U: Hashable> (@in U, @in T, UnsafeRawPointer) -> (),
+ indices [%$0 : $Y : $*Y, %$1 : $X : $*X],
+ indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int
+ ) <A, B> (%1, %2)
+ %v = keypath $WritableKeyPath<A, A>, <X: Hashable, Y: Hashable> (
+ root $X;
+ settable_property $Y,
+ id @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in T, UnsafeRawPointer) -> @out U,
+ getter @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in T, UnsafeRawPointer) -> @out U,
+ setter @s_set : $@convention(thin) <T: Hashable, U: Hashable> (@in U, @in T, UnsafeRawPointer) -> (),
+ indices [%$0 : $Y : $*Y, %$1 : $X : $*X],
+ indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int;
+ settable_property $X,
+ id @v_get : $@convention(thin) <T: Hashable, U: Hashable> (@in U, UnsafeRawPointer) -> @out T,
+ getter @v_get : $@convention(thin) <T: Hashable, U: Hashable> (@in U, UnsafeRawPointer) -> @out T,
+ setter @v_set : $@convention(thin) <T: Hashable, U: Hashable> (@in T, @in U, UnsafeRawPointer) -> (),
+ indices [%$2 : $Y : $*Y],
+ indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+ indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int
+ ) <A, B> (%3, %4, %5)
+
+ return undef : $()
+}
+
+sil @s_get : $@convention(thin) <A: Hashable, B: Hashable> (@in A, UnsafeRawPointer) -> @out B
+sil @s_set : $@convention(thin) <A: Hashable, B: Hashable> (@in B, @in A, UnsafeRawPointer) -> ()
+sil @s_equals : $@convention(thin) <A: Hashable, B: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @s_hash : $@convention(thin) <A: Hashable, B: Hashable> (UnsafeRawPointer) -> Int
+
+sil @v_get : $@convention(thin) <A: Hashable, B: Hashable> (@in B, UnsafeRawPointer) -> @out A
+sil @v_set : $@convention(thin) <A: Hashable, B: Hashable> (@in A, @in B, UnsafeRawPointer) -> ()
diff --git a/test/IRGen/unowned_objc.sil b/test/IRGen/unowned_objc.sil
index 73ddf86..0d65eb5 100644
--- a/test/IRGen/unowned_objc.sil
+++ b/test/IRGen/unowned_objc.sil
@@ -58,12 +58,12 @@
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: store i8** [[PP:%1]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedInit(%swift.unowned* [[T0]], [[UNKNOWN]]* [[PV:%0]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedInit(%swift.unowned* [[T0]], [[UNKNOWN]]* [[PV:%0]])
store_unowned %p to [initialization] %x : $*@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedCopyInit(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedCopyInit(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: [[WT:%.*]] = load i8**, i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
@@ -81,7 +81,7 @@
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedCopyAssign(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedCopyAssign(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: [[WT:%.*]] = load i8**, i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
@@ -91,12 +91,12 @@
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
// CHECK-NEXT: store i8** [[QP:%3]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedAssign(%swift.unowned* [[T0]], [[UNKNOWN]]* [[QV:%2]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedAssign(%swift.unowned* [[T0]], [[UNKNOWN]]* [[QV:%2]])
store_unowned %q to %y : $*@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedTakeAssign(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedTakeAssign(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: [[WT:%.*]] = load i8**, i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
@@ -105,7 +105,7 @@
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedTakeInit(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedTakeInit(%swift.unowned* [[T0]], %swift.unowned* [[T1]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
// CHECK-NEXT: [[WT:%.*]] = load i8**, i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
@@ -121,7 +121,7 @@
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: store i8** [[TP]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
- // CHECK-NEXT: call void @swift_unknownUnownedInit(%swift.unowned* [[T0]], [[UNKNOWN]]* [[TV]])
+ // CHECK-NEXT: call %swift.unowned* @swift_unknownUnownedInit(%swift.unowned* [[T0]], [[UNKNOWN]]* [[TV]])
store_unowned %t1 to [initialization] %x : $*@sil_unowned P
// CHECK-NEXT: call void @swift_unknownRelease([[UNKNOWN]]* [[TV]])
diff --git a/test/IRGen/weak.sil b/test/IRGen/weak.sil
index f9ebfdf..b4270f2 100644
--- a/test/IRGen/weak.sil
+++ b/test/IRGen/weak.sil
@@ -47,9 +47,9 @@
// CHECK-NEXT: [[T0:%.*]] = call [[C]]* bitcast ([[REF]]* ([[WEAK]]*)* @swift_weakLoadStrong to [[C]]* ([[WEAK]]*)*)([[WEAK]]* [[X]])
// CHECK-NEXT: %3 = ptrtoint %T4weak1CC* %2 to i64
// CHECK-NEXT: %4 = inttoptr
-// CHECK-NEXT: call void bitcast ([[WEAK]]* ([[WEAK]]*, [[REF]]*)* @swift_weakAssign to void ([[WEAK]]*, [[C]]*)*)([[WEAK]]* [[X]], [[C]]* %4)
-// CHECK-NEXT: %5 = inttoptr i64 %3 to %swift.refcounted*
-// CHECK-NEXT: call void @swift_rt_swift_release([[REF]]* %5)
+// CHECK-NEXT: call [[WEAK]]* bitcast ([[WEAK]]* ([[WEAK]]*, [[REF]]*)* @swift_weakAssign to [[WEAK]]* ([[WEAK]]*, [[C]]*)*)([[WEAK]]* [[X]], [[C]]* %4)
+// CHECK-NEXT: %6 = inttoptr i64 %3 to %swift.refcounted*
+// CHECK-NEXT: call void @swift_rt_swift_release([[REF]]* %6)
// CHECK-NEXT: ret void
struct B {
@@ -76,7 +76,7 @@
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 1
// CHECK-NEXT: store i8** [[TMPTAB]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 0
-// CHECK-NEXT: call void @swift_unknownWeakAssign([[WEAK]]* [[T0]], [[UNKNOWN]]* [[TMPOBJ]])
+// CHECK-NEXT: call [[WEAK]]* @swift_unknownWeakAssign([[WEAK]]* [[T0]], [[UNKNOWN]]* [[TMPOBJ]])
// CHECK: call void @_T0SqWe
sil @test_weak_alloc_stack : $@convention(thin) (Optional<P>) -> () {
@@ -95,7 +95,7 @@
// CHECK: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 1
// CHECK-NEXT: store i8** [[TMPTAB:%.*]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 0
-// CHECK-NEXT: call void @swift_unknownWeakInit([[WEAK]]* [[T0]], [[UNKNOWN]]* [[TMPOBJ:%.*]])
+// CHECK-NEXT: call [[WEAK]]* @swift_unknownWeakInit([[WEAK]]* [[T0]], [[UNKNOWN]]* [[TMPOBJ:%.*]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 0
// CHECK-NEXT: call void @swift_unknownWeakDestroy([[WEAK]]* [[T0]])
// CHECK-NEXT: bitcast
diff --git a/test/IRGen/weak_class_protocol.sil b/test/IRGen/weak_class_protocol.sil
index ad60a85..75a1877 100644
--- a/test/IRGen/weak_class_protocol.sil
+++ b/test/IRGen/weak_class_protocol.sil
@@ -14,7 +14,7 @@
// CHECK: [[WTABLE_SLOT:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1
// CHECK: store i8** [[WTABLE]], i8*** [[WTABLE_SLOT]], align 8
// CHECK: [[INSTANCE_SLOT:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0
-// CHECK-objc: call void @swift_unknownWeakAssign(%swift.weak* [[INSTANCE_SLOT]], %objc_object* [[INSTANCE]]) {{#[0-9]+}}
+// CHECK-objc: call %swift.weak* @swift_unknownWeakAssign(%swift.weak* [[INSTANCE_SLOT]], %objc_object* [[INSTANCE]]) {{#[0-9]+}}
// CHECK-native: call %swift.weak* @swift_weakAssign(%swift.weak* [[INSTANCE_SLOT]], %swift.refcounted* [[INSTANCE]]) {{#[0-9]+}}
// CHECK: ret void
// CHECK: }
diff --git a/test/SIL/Parser/keypath.sil b/test/SIL/Parser/keypath.sil
index 6fb730a..a8b99ff 100644
--- a/test/SIL/Parser/keypath.sil
+++ b/test/SIL/Parser/keypath.sil
@@ -4,12 +4,15 @@
import Swift
-struct S {
+struct S: Hashable {
var x: Int
let y: String
var z: C
+
+ var hashValue: Int { get }
+ static func ==(x: S, y: S) -> Bool
}
-class C {
+class C: Hashable {
final var x: Int
final let y: String
final var z: S
@@ -18,6 +21,9 @@
var overridable: Int {
get set
}
+
+ var hashValue: Int { get }
+ static func ==(x: C, y: C) -> Bool
}
protocol P {}
@@ -63,6 +69,15 @@
sil @set_c_int : $@convention(thin) (@in Int, @in C) -> ()
sil @get_fns_fnc : $@convention(thin) (@in @callee_owned (@in S) -> @out S) -> @out @callee_owned (@in C) -> @out C
sil @set_fns_fnc : $@convention(thin) (@in @callee_owned (@in C) -> @out C, @in @callee_owned (@in S) -> @out S) -> ()
+sil @get_s_int_subs : $@convention(thin) (@in S, UnsafeRawPointer) -> @out Int
+sil @set_s_int_subs : $@convention(thin) (@in Int, @in S, UnsafeRawPointer) -> ()
+sil @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+sil @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in A, UnsafeRawPointer) -> @out C
+sil @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in C, @in A, UnsafeRawPointer) -> ()
+sil @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int
+
// CHECK-LABEL: sil shared @computed_properties
sil shared @computed_properties : $@convention(thin) () -> () {
@@ -101,3 +116,23 @@
return undef : $()
}
+
+// CHECK-LABEL: sil @indexes
+sil @indexes : $@convention(thin) (S, C) -> () {
+// CHECK: bb0([[S:%.*]] : $S, [[C:%.*]] : $C):
+entry(%s : $S, %c : $C):
+ // CHECK: keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in Int, @in S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) ([[S]], [[C]])
+ %a = keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in Int, @in S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) (%s, %c)
+ // CHECK: [[T:%.*]] = alloc_stack
+ %t = alloc_stack $S
+ // CHECK: [[D:%.*]] = alloc_stack
+ %d = alloc_stack $C
+ // CHECK: keypath $KeyPath<S, Int>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (root $τ_0_0; settable_property $τ_0_2, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in τ_0_0, UnsafeRawPointer) -> @out τ_0_2, setter @set_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in τ_0_2, @in τ_0_0, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $τ_0_1 : $*τ_0_1], indices_equals @gen_subs_eq : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> ([[T]], [[D]])
+ %b = keypath $KeyPath<S, Int>, <τ_0_0: Hashable, Y: Hashable, Z: Hashable> (root $τ_0_0; settable_property $Z, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in A, UnsafeRawPointer) -> @out C, setter @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in C, @in A, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $Y : $*Y], indices_equals @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> (%t, %d)
+
+ dealloc_stack %d : $*C
+ dealloc_stack %t : $*S
+
+ return undef : $()
+}
+
diff --git a/test/SIL/Serialization/keypath.sil b/test/SIL/Serialization/keypath.sil
index cfed287..53989c9 100644
--- a/test/SIL/Serialization/keypath.sil
+++ b/test/SIL/Serialization/keypath.sil
@@ -9,12 +9,15 @@
import Swift
-struct S {
+struct S: Hashable {
var x: Int
let y: String
var z: C
+
+ var hashValue: Int { get }
+ static func ==(x: S, y: S) -> Bool
}
-class C {
+class C: Hashable {
final var x: Int
final let y: String
final var z: S
@@ -23,6 +26,9 @@
var overridable: Int {
get set
}
+
+ var hashValue: Int { get }
+ static func ==(x: C, y: C) -> Bool
}
protocol P {}
@@ -68,6 +74,14 @@
sil @set_c_int : $@convention(thin) (@in Int, @in C) -> ()
sil @get_fns_fnc : $@convention(thin) (@in @callee_owned (@in S) -> @out S) -> @out @callee_owned (@in C) -> @out C
sil @set_fns_fnc : $@convention(thin) (@in @callee_owned (@in C) -> @out C, @in @callee_owned (@in S) -> @out S) -> ()
+sil @get_s_int_subs : $@convention(thin) (@in S, UnsafeRawPointer) -> @out Int
+sil @set_s_int_subs : $@convention(thin) (@in Int, @in S, UnsafeRawPointer) -> ()
+sil @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+sil @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in A, UnsafeRawPointer) -> @out C
+sil @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in C, @in A, UnsafeRawPointer) -> ()
+sil @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int
// CHECK-LABEL: sil shared @computed_properties
sil shared @computed_properties : $@convention(thin) () -> () {
@@ -107,6 +121,25 @@
return undef : $()
}
+// CHECK-LABEL: sil shared @indexes
+sil shared @indexes : $@convention(thin) (S, C) -> () {
+// CHECK: bb0([[S:%.*]] : $S, [[C:%.*]] : $C):
+entry(%s : $S, %c : $C):
+ // CHECK: keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in Int, @in S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) ([[S]], [[C]])
+ %a = keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in Int, @in S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) (%s, %c)
+ // CHECK: [[T:%.*]] = alloc_stack
+ %t = alloc_stack $S
+ // CHECK: [[D:%.*]] = alloc_stack
+ %d = alloc_stack $C
+ // CHECK: keypath $KeyPath<S, Int>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (root $τ_0_0; settable_property $τ_0_2, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in τ_0_0, UnsafeRawPointer) -> @out τ_0_2, setter @set_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in τ_0_2, @in τ_0_0, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $τ_0_1 : $*τ_0_1], indices_equals @gen_subs_eq : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> ([[T]], [[D]])
+ %b = keypath $KeyPath<S, Int>, <τ_0_0: Hashable, Y: Hashable, Z: Hashable> (root $τ_0_0; settable_property $Z, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in A, UnsafeRawPointer) -> @out C, setter @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in C, @in A, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $Y : $*Y], indices_equals @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> (%t, %d)
+
+ dealloc_stack %d : $*C
+ dealloc_stack %t : $*S
+
+ return undef : $()
+}
+
sil @serialize_all : $@convention(thin) () -> () {
entry:
%0 = function_ref @stored_properties : $@convention(thin) () -> ()
@@ -114,6 +147,7 @@
%2 = function_ref @computed_properties : $@convention(thin) () -> ()
%3 = function_ref @computed_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> ()
%4 = function_ref @optional : $@convention(thin) () -> ()
+ %5 = function_ref @indexes : $@convention(thin) (S, C) -> ()
unreachable
}
diff --git a/test/SILGen/Inputs/default_arguments_other.swift b/test/SILGen/Inputs/default_arguments_other.swift
new file mode 100644
index 0000000..a2a71e0
--- /dev/null
+++ b/test/SILGen/Inputs/default_arguments_other.swift
@@ -0,0 +1 @@
+public func otherDefaultArguments(x: Int = 0) {}
diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift
index f2ec010..75eb08a 100644
--- a/test/SILGen/default_arguments.swift
+++ b/test/SILGen/default_arguments.swift
@@ -1,5 +1,8 @@
-// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen %s | %FileCheck %s
-// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen %s | %FileCheck %s --check-prefix=NEGATIVE
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 %s | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 %s | %FileCheck %s --check-prefix=NEGATIVE
+
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 4 %s | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 4 %s | %FileCheck %s --check-prefix=NEGATIVE
// __FUNCTION__ used as top-level parameter produces the module name.
// CHECK-LABEL: sil @main
diff --git a/test/SILGen/default_arguments_serialized.swift b/test/SILGen/default_arguments_serialized.swift
new file mode 100644
index 0000000..3391474
--- /dev/null
+++ b/test/SILGen/default_arguments_serialized.swift
@@ -0,0 +1,60 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module-path %t/default_arguments_other.swiftmodule -emit-module -swift-version 4 -primary-file %S/Inputs/default_arguments_other.swift
+
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 -I %t %s | %FileCheck %s --check-prefix=SWIFT3 --check-prefix=CHECK
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 4 -I %t %s | %FileCheck %s --check-prefix=SWIFT4 --check-prefix=CHECK
+
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-sil -O -swift-version 3 -I %t %s | %FileCheck %s --check-prefix=OPT
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-sil -O -swift-version 4 -I %t %s | %FileCheck %s --check-prefix=OPT
+
+// Check that default arguments are serialized in Swift 4 mode.
+
+import default_arguments_other
+
+// CHECK-LABEL: sil @_T028default_arguments_serialized0A6StringSSyF : $@convention(thin) () -> @owned String
+public func defaultString() -> String { return "hi" }
+
+// SWIFT3-LABEL: sil @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytFfA_ : $@convention(thin) () -> Int
+// SWIFT4-LABEL: sil [serialized] @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytFfA_ : $@convention(thin) () -> Int
+
+// SWIFT3-LABEL: sil @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytFfA0_ : $@convention(thin) () -> @owned String
+// SWIFT4-LABEL: sil [serialized] @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytFfA0_ : $@convention(thin) () -> @owned String
+
+public func hasDefaultArguments(x: Int = 0, y: String = defaultString()) {}
+
+// CHECK-LABEL: sil @_T028default_arguments_serialized21callsDefaultArgumentsyyF : $@convention(thin) () -> ()
+// CHECK: function_ref @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytF : $@convention(thin) (Int, @owned String) -> ()
+// CHECK: function_ref @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytFfA_ : $@convention(thin) () -> Int
+// CHECK: function_ref @_T028default_arguments_serialized19hasDefaultArgumentsySi1x_SS1ytFfA0_ : $@convention(thin) () -> @owned String
+// CHECK: apply
+// CHECK: return
+public func callsDefaultArguments() {
+ hasDefaultArguments()
+}
+
+// When calling a default argument generator for a function in another module
+// that was built in Swift 4 mode, we should always treat it as serialized,
+// even if *this* module is built in Swift 3 mode.
+
+// CHECK-LABEL: sil @_T028default_arguments_serialized26callsOtherDefaultArgumentsyyF : $@convention(thin) () -> ()
+// CHECK: function_ref @_T023default_arguments_other0C16DefaultArgumentsySi1x_tF : $@convention(thin) (Int) -> ()
+// CHECK: function_ref @_T023default_arguments_other0C16DefaultArgumentsySi1x_tFfA_ : $@convention(thin) () -> Int
+// CHECK: apply
+// CHECK: return
+
+// Make sure the optimizer inlines the default argument generator from the
+// other module.
+
+// OPT-LABEL: sil @_T028default_arguments_serialized26callsOtherDefaultArgumentsyyF : $@convention(thin) () -> ()
+// OPT: [[FN:%.*]] = function_ref @_T023default_arguments_other0C16DefaultArgumentsySi1x_tF : $@convention(thin) (Int) -> () // user: %3
+// OPT: [[INT_VAL:%.*]] = integer_literal [[INT_TYPE:\$Builtin.Int(32|64)]], 0
+// OPT: [[INT:%.*]] = struct $Int ([[INT_VAL]] : [[INT_TYPE]]
+// OPT: apply [[FN]]([[INT]]) : $@convention(thin) (Int) -> ()
+// OPT: return
+public func callsOtherDefaultArguments() {
+ otherDefaultArguments()
+}
+
+// CHECK-LABEL: sil @_T023default_arguments_other0C16DefaultArgumentsySi1x_tF : $@convention(thin) (Int) -> ()
+
+// CHECK-LABEL: sil [serialized] @_T023default_arguments_other0C16DefaultArgumentsySi1x_tFfA_ : $@convention(thin) () -> Int
diff --git a/test/SILGen/keypath_application.swift b/test/SILGen/keypath_application.swift
index 4df7f8e..88cd272 100644
--- a/test/SILGen/keypath_application.swift
+++ b/test/SILGen/keypath_application.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -enable-experimental-keypath-components -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
class A {}
class B {}
diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift
index 8ba3f4f..4f7247b 100644
--- a/test/SILGen/keypaths.swift
+++ b/test/SILGen/keypaths.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -enable-experimental-keypath-components -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
struct S<T> {
var x: T
@@ -253,7 +253,7 @@
}
}
-// CHECK-LABEL: sil hidden @{{.*}}iuoKeyPaths
+// CHECK-LABEL: sil hidden @{{.*}}11iuoKeyPaths
func iuoKeyPaths() {
// CHECK: = keypath $WritableKeyPath<IUOProperty, Int>,
// CHECK-SAME: stored_property #IUOProperty.iuo
@@ -266,3 +266,59 @@
// CHECK-SAME: stored_property #IUOBlob.x
_ = \IUOProperty.iuo!.x
}
+
+struct Subscripts<T> {
+ subscript() -> T {
+ get { fatalError() }
+ set { fatalError() }
+ }
+ subscript(generic x: T) -> T {
+ get { fatalError() }
+ set { fatalError() }
+ }
+ subscript(concrete x: String) -> String {
+ get { fatalError() }
+ set { fatalError() }
+ }
+ subscript(x: String, y: String) -> String {
+ get { fatalError() }
+ set { fatalError() }
+ }
+ subscript<U>(subGeneric z: U) -> U {
+ get { fatalError() }
+ set { fatalError() }
+ }
+ subscript(mutable x: T) -> T {
+ get { fatalError() }
+ set { fatalError() }
+ }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}10subscripts
+func subscripts<T: Hashable, U: Hashable>(x: T, y: U, s: String) {
+ _ = \Subscripts<T>.[]
+ _ = \Subscripts<T>.[generic: x]
+ _ = \Subscripts<T>.[concrete: s]
+ _ = \Subscripts<T>.[s, s]
+ _ = \Subscripts<T>.[subGeneric: s]
+ _ = \Subscripts<T>.[subGeneric: x]
+ _ = \Subscripts<T>.[subGeneric: y]
+
+ _ = \Subscripts<U>.[]
+ _ = \Subscripts<U>.[generic: y]
+ _ = \Subscripts<U>.[concrete: s]
+ _ = \Subscripts<U>.[s, s]
+ _ = \Subscripts<U>.[subGeneric: s]
+ _ = \Subscripts<U>.[subGeneric: x]
+ _ = \Subscripts<U>.[subGeneric: y]
+
+ _ = \Subscripts<String>.[]
+ _ = \Subscripts<String>.[generic: s]
+ _ = \Subscripts<String>.[concrete: s]
+ _ = \Subscripts<String>.[s, s]
+ _ = \Subscripts<String>.[subGeneric: s]
+ _ = \Subscripts<String>.[subGeneric: x]
+ _ = \Subscripts<String>.[subGeneric: y]
+
+ _ = \Subscripts<T>.[s, s].count
+}
diff --git a/test/SILGen/keypaths_objc.swift b/test/SILGen/keypaths_objc.swift
index 8bbaf94..90b29fc 100644
--- a/test/SILGen/keypaths_objc.swift
+++ b/test/SILGen/keypaths_objc.swift
@@ -1,5 +1,5 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-keypath-components -emit-silgen -import-objc-header %S/Inputs/keypaths_objc.h %s | %FileCheck %s
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-keypath-components -emit-ir -import-objc-header %S/Inputs/keypaths_objc.h %s
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -import-objc-header %S/Inputs/keypaths_objc.h %s | %FileCheck %s
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir -import-objc-header %S/Inputs/keypaths_objc.h %s
// REQUIRES: objc_interop
import Foundation
diff --git a/test/SILOptimizer/closure_specialize_opaque.sil b/test/SILOptimizer/closure_specialize_opaque.sil
new file mode 100644
index 0000000..840a9d6
--- /dev/null
+++ b/test/SILOptimizer/closure_specialize_opaque.sil
@@ -0,0 +1,42 @@
+// RUN: %target-sil-opt -enable-sil-opaque-values -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -closure-specialize %s | %FileCheck %s
+
+struct TestView {}
+struct TestRange {}
+struct TestSlice {}
+
+// helper
+sil @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () {
+bb0(%0 : $*TestView, %1 : $TestRange, %2 : $TestSlice):
+ %1284 = tuple ()
+ return %1284 : $()
+}
+
+// helper
+sil @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out () {
+bb0(%0 : $*TestView, %1 : $@callee_owned (@inout TestView) ->()):
+ %call = apply %1(%0) : $@callee_owned (@inout TestView) -> ()
+ %1284 = tuple ()
+ return %1284 : $()
+}
+
+// Test that ClosureSpecializer can handle captured @in args, in addition to direct args.
+//
+// CHECK-LABEL: sil @testSpecializeThunk : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () {
+// CHECK: bb0(%0 : $*TestView, %1 : $TestRange, %2 : $TestSlice):
+// CHECK: [[CLOSURE:%.*]] = function_ref @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> ()
+// CHECK: [[SPECIALIZED:%.*]] = function_ref @_T05thunk7closure4main9TestRangeVAC0D5SliceVTf1nc_n : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> @out () // user: %6
+// CHECK: [[THUNK:%.*]] = function_ref @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out ()
+// CHECK: [[CALL:%.*]] = apply [[SPECIALIZED]](%0, %1, %2) : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> @out ()
+// CHECK: %{{.*}} = tuple ()
+// CHECK: return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function 'testSpecializeThunk'
+sil @testSpecializeThunk : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () {
+bb0(%0 : $*TestView, %1 : $TestRange, %2 : $TestSlice):
+ %closurefn = function_ref @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> ()
+ %pa = partial_apply %closurefn(%1, %2) : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> ()
+ %thunk = function_ref @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out ()
+ strong_retain %pa : $@callee_owned (@inout TestView) -> ()
+ %call = apply %thunk(%0, %pa) : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out ()
+ %1284 = tuple ()
+ return %1284 : $()
+}
diff --git a/test/SILOptimizer/funcsig_opaque.sil b/test/SILOptimizer/funcsig_opaque.sil
new file mode 100644
index 0000000..bcd8f47
--- /dev/null
+++ b/test/SILOptimizer/funcsig_opaque.sil
@@ -0,0 +1,44 @@
+// RUN: %target-sil-opt -enable-sil-opaque-values -assume-parsing-unqualified-ownership-sil -function-signature-opts %s | %FileCheck %s
+
+import Builtin
+
+struct R<T> {
+ var base: T
+}
+
+struct S {
+ var val: Builtin.Int32
+}
+
+sil @testAggregateArgHelper : $@convention(thin) (@owned R<S>) -> ()
+
+// Test owned-to-guaranteed transformation of opaque arguments.
+//
+// CHECK-LABEL: sil [thunk] [always_inline] @testAggregateArg : $@convention(thin) (@in R<S>) -> @out () {
+// CHECK: bb0(%0 : $R<S>):
+// CHECK: [[F:%.*]] = function_ref @_T016testAggregateArgTf4g_n : $@convention(thin) (@in_guaranteed R<S>) -> @out ()
+// CHECK: [[CALL:%.*]] = apply [[F]](%0) : $@convention(thin) (@in_guaranteed R<S>) -> @out ()
+// CHECK: release_value %0 : $R<S>
+// CHECK: return [[CALL]] : $()
+// CHECK-LABEL: } // end sil function 'testAggregateArg'
+//
+// CHECK-LABEL: sil shared @_T016testAggregateArgTf4g_n : $@convention(thin) (@in_guaranteed R<S>) -> @out () {
+// CHECK: bb0(%0 : $R<S>):
+// CHECK: [[COPY:%.*]] = copy_value %0 : $R<S>
+// CHECK: retain_value %0 : $R<S>
+// CHECK: [[F:%.*]] = function_ref @testAggregateArgHelper : $@convention(thin) (@owned R<S>) -> ()
+// CHECK: [[CALL:%.*]] = apply [[F]]([[COPY]]) : $@convention(thin) (@owned R<S>) -> ()
+// CHECK: destroy_value %0 : $R<S>
+// CHECK: return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '_T016testAggregateArgTf4g_n'
+sil @testAggregateArg : $@convention(thin) (@in R<S>) -> @out () {
+bb0(%0 : $R<S>):
+ %9 = copy_value %0 : $R<S>
+ retain_value %0 : $R<S>
+ %10 = function_ref @testAggregateArgHelper : $@convention(thin) (@owned R<S>) -> ()
+ %12 = apply %10(%9) : $@convention(thin) (@owned R<S>) -> ()
+ destroy_value %0 : $R<S>
+ release_value %0 : $R<S>
+ %1284 = tuple ()
+ return %1284 : $()
+}
diff --git a/test/SILOptimizer/sil_combine_opaque.sil b/test/SILOptimizer/sil_combine_opaque.sil
new file mode 100644
index 0000000..e99bbf9
--- /dev/null
+++ b/test/SILOptimizer/sil_combine_opaque.sil
@@ -0,0 +1,25 @@
+// RUN: %target-sil-opt -enable-sil-opaque-values -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -sil-combine %s | %FileCheck %s
+
+struct S<T> {
+ var t : T
+}
+
+// Test SIL combine's handling of retain_value/release_value.
+//
+// CHECK-LABEL: sil @testSpecializeOpaque : $@convention(thin) <T> (@in S<T>) -> () {
+// CHECK-LABEL: bb0(%0 : $S<T>):
+// CHECK: retain_value %0 : $S<T>
+// CHECK: [[F:%.*]] = function_ref @testSpecializeOpaque : $@convention(thin) <τ_0_0> (@in S<τ_0_0>) -> ()
+// CHECK: [[CALL:%.*]] = apply [[F]]<T>(%0) : $@convention(thin) <τ_0_0> (@in S<τ_0_0>) -> ()
+// CHECK: release_value %0 : $S<T>
+// CHECK: return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function 'testSpecializeOpaque'
+sil @testSpecializeOpaque : $@convention(thin) <T> (@in S<T>) -> () {
+bb0(%0 : $S<T>):
+ %retain = retain_value %0 : $S<T>
+ %f = function_ref @testSpecializeOpaque : $@convention(thin) <T> (@in S<T>) -> ()
+ %call = apply %f<T>(%0) : $@convention(thin) <τ_0_0> (@in S<τ_0_0>) -> ()
+ %release = release_value %0 : $S<T>
+ %999 = tuple ()
+ return %999 : $()
+}
diff --git a/test/SourceKit/DocumentStructure/mark_edit.swift.response b/test/SourceKit/DocumentStructure/mark_edit.swift.response
index 62e0e85..de19dc3 100644
--- a/test/SourceKit/DocumentStructure/mark_edit.swift.response
+++ b/test/SourceKit/DocumentStructure/mark_edit.swift.response
@@ -13,8 +13,6 @@
]
}
{
- key.offset: 0,
- key.length: 3,
key.diagnostic_stage: source.diagnostic.stage.swift.parse,
key.substructure: [
{
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-block-comment.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-block-comment.swift
new file mode 100644
index 0000000..d3fe128
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-block-comment.swift
@@ -0,0 +1,5 @@
+
+let x = /*
+
+*/ 2
+func foo() {}
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-chained-comment.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-chained-comment.swift
new file mode 100644
index 0000000..42a1b54
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-chained-comment.swift
@@ -0,0 +1,5 @@
+let y = /*
+
+*// /*
+
+*/ 2
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-disjoint-effect.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-disjoint-effect.swift
new file mode 100644
index 0000000..b6e9f63
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-disjoint-effect.swift
@@ -0,0 +1,6 @@
+func getIt
+struct MyStruct {
+ func getChildStruct() -> String {
+ return ""
+ }
+}
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-multiline-string.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-multiline-string.swift
new file mode 100644
index 0000000..85143bd
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-multiline-string.swift
@@ -0,0 +1,12 @@
+let a = "value"
+let x = """
+
+\(
+a
+)
+
+
+
+func foo () -> String {
+ return "foo"
+}
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-nested-token.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-nested-token.swift
new file mode 100644
index 0000000..69c1432
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-nested-token.swift
@@ -0,0 +1,19 @@
+/// This function does stuff
+///
+/// - parameter first: The first parameter
+///
+/// - returns: The return value
+func foo(first: Int) -> String {
+ return ""
+}
+
+let x = "Changing this string should only affect this line"
+
+/// This function does other stuff
+///
+/// - parameter first: The first parameter
+///
+/// - returns: The return value
+func bar(first: Int) -> String {
+ return ""
+}
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-remove.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-remove.swift
new file mode 100644
index 0000000..b4ac2a5
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-edit-remove.swift
@@ -0,0 +1,4 @@
+let l = 2
+l
+\( 56
+)
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-multiple-edits.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-multiple-edits.swift
new file mode 100644
index 0000000..6c18bdc
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-multiple-edits.swift
@@ -0,0 +1,14 @@
+
+/// A comment
+/// - Note: important things
+let x = 42
+
+struct Point {
+ let x: Int = x
+ let y: Int = x
+
+ func mag2() {
+ return x*x + y*y;
+ }
+}
+
diff --git a/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-partial-delete.swift b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-partial-delete.swift
new file mode 100644
index 0000000..def3663
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/Inputs/syntaxmap-partial-delete.swift
@@ -0,0 +1,2 @@
+
+let x = 421
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-block-comment.swift b/test/SourceKit/SyntaxMapData/syntaxmap-edit-block-comment.swift
new file mode 100644
index 0000000..2304819
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-block-comment.swift
@@ -0,0 +1,98 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-edit-block-comment.swift == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-block-comment.swift -pos=4:2 -replace=" " -length=1 == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-block-comment.swift -pos=4:2 -replace="/" -length=1 == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-block-comment.swift -pos=1:1 -replace="//" -length=2 | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Initial state
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 34,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 3,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 7,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 11,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 18,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 20,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 25,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After removing the '/' from the comment close
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 11,
+// CHECK-NEXT: key.length: 23,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 11,
+// CHECK-NEXT: key.length: 23
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After adding the '/' back to the comment close
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 11,
+// CHECK-NEXT: key.length: 23,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 11,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 18,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 20,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 25,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// after adding a single-line comment on the line above
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 3,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-chained-comment.swift b/test/SourceKit/SyntaxMapData/syntaxmap-edit-chained-comment.swift
new file mode 100644
index 0000000..2718461
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-chained-comment.swift
@@ -0,0 +1,70 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-edit-chained-comment.swift == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-chained-comment.swift -pos=1:9 -replace=" " -length=1 == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-chained-comment.swift -pos=1:9 -replace="/" -length=1 | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Initial state
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 25,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 4,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 8,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 16,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 23,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+
+// After replacing the '/' from the comment open with ' '
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 8,
+// CHECK-NEXT: key.length: 14,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 13,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After adding the '/' back to the comment open
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 8,
+// CHECK-NEXT: key.length: 14,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 8,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.comment,
+// CHECK-NEXT: key.offset: 16,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response b/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response
index bc86f00..d0497be 100644
--- a/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response
@@ -29,7 +29,7 @@
}
{
key.offset: 1,
- key.length: 36,
+ key.length: 33,
key.diagnostic_stage: source.diagnostic.stage.swift.parse,
key.syntaxmap: [
{
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response2 b/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response2
index ae9b915..4d92f16 100644
--- a/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response2
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-del.swift.response2
@@ -28,8 +28,6 @@
]
}
{
- key.offset: 36,
- key.length: 0,
key.diagnostic_stage: source.diagnostic.stage.swift.parse,
key.syntaxmap: [
]
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-disjoint-effect.swift b/test/SourceKit/SyntaxMapData/syntaxmap-edit-disjoint-effect.swift
new file mode 100644
index 0000000..5eccc0e
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-disjoint-effect.swift
@@ -0,0 +1,70 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-edit-disjoint-effect.swift == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-disjoint-effect.swift -pos=1:11 -replace='(' -length=1 | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Original contents
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 86,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 5,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 12,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 19,
+// CHECK-NEXT: key.length: 8
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 32,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 37,
+// CHECK-NEXT: key.length: 14
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 57,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 70,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 77,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After opening the parameter list (without closing it)
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 12,
+// CHECK-NEXT: key.length: 51,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 12,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: }
+
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-multiline-string.swift b/test/SourceKit/SyntaxMapData/syntaxmap-edit-multiline-string.swift
new file mode 100644
index 0000000..e75fb30
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-multiline-string.swift
@@ -0,0 +1,137 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-edit-multiline-string.swift == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-multiline-string.swift -pos=8:1 -replace='"""' -length=3 == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-multiline-string.swift -pos=6:2 -replace=')' -length=1 == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-multiline-string.swift -pos=2:10 -replace=' ' -length=1 | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Original file contents
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 84,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 4,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 8,
+// CHECK-NEXT: key.length: 7
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 16,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 20,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 24,
+// CHECK-NEXT: key.length: 60
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After terminating the multiline string
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 24,
+// CHECK-NEXT: key.length: 60,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 24,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string_interpolation_anchor,
+// CHECK-NEXT: key.offset: 30,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 32,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string_interpolation_anchor,
+// CHECK-NEXT: key.offset: 34,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 35,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 43,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 48,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 58,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 69,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 76,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After adding a character after the interpolation
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 35,
+// CHECK-NEXT: key.length: 6,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 35,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After replacing the middle opening quote with a space
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 24,
+// CHECK-NEXT: key.length: 60,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 24,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 32,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 38,
+// CHECK-NEXT: key.length: 46
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-nested-token.swift b/test/SourceKit/SyntaxMapData/syntaxmap-edit-nested-token.swift
new file mode 100644
index 0000000..f266bff
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-nested-token.swift
@@ -0,0 +1,200 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-edit-nested-token.swift == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-nested-token.swift -pos=10:43 -replace='impact' -length=6 | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Original file contents
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 386,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 29
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 29,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 33,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment.field,
+// CHECK-NEXT: key.offset: 39,
+// CHECK-NEXT: key.length: 9
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 48,
+// CHECK-NEXT: key.length: 28
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 76,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 80,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment.field,
+// CHECK-NEXT: key.offset: 86,
+// CHECK-NEXT: key.length: 7
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 93,
+// CHECK-NEXT: key.length: 19
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 112,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 117,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 121,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 128,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 136,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 147,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 154,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 160,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 164,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 168,
+// CHECK-NEXT: key.length: 51
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 221,
+// CHECK-NEXT: key.length: 35
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 256,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 260,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment.field,
+// CHECK-NEXT: key.offset: 266,
+// CHECK-NEXT: key.length: 9
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 275,
+// CHECK-NEXT: key.length: 28
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 303,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 307,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment.field,
+// CHECK-NEXT: key.offset: 313,
+// CHECK-NEXT: key.length: 7
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 320,
+// CHECK-NEXT: key.length: 19
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 339,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 344,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 348,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 355,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 363,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 374,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 381,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After editing a string in between nested comments
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 168,
+// CHECK-NEXT: key.length: 51,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.string,
+// CHECK-NEXT: key.offset: 168,
+// CHECK-NEXT: key.length: 51
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit-remove.swift b/test/SourceKit/SyntaxMapData/syntaxmap-edit-remove.swift
new file mode 100644
index 0000000..b6314c2
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit-remove.swift
@@ -0,0 +1,57 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-edit-remove.swift == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-remove.swift -pos=3:3 -length=1 -replace='' == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-remove.swift -pos=2:1 -replace='' -length=1 == -req=edit -print-raw-response %S/Inputs/syntaxmap-edit-remove.swift -pos=1:9 -length=1 -replace='' | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Initial state
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 20,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 4,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 8,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 10,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 15,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After removing the space before the '56'
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: ],
+
+// After deleting the identifier 'l'
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: ],
+
+// After deleting the last token on the first line
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: ],
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-edit.swift.response b/test/SourceKit/SyntaxMapData/syntaxmap-edit.swift.response
index 39c0de8..0f55ca4 100644
--- a/test/SourceKit/SyntaxMapData/syntaxmap-edit.swift.response
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-edit.swift.response
@@ -41,16 +41,11 @@
]
}
{
- key.offset: 81,
- key.length: 15,
+ key.offset: 87,
+ key.length: 6,
key.diagnostic_stage: source.diagnostic.stage.swift.parse,
key.syntaxmap: [
{
- key.kind: source.lang.swift.syntaxtype.keyword,
- key.offset: 81,
- key.length: 5
- },
- {
key.kind: source.lang.swift.syntaxtype.identifier,
key.offset: 87,
key.length: 6
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-multiple-edits.swift b/test/SourceKit/SyntaxMapData/syntaxmap-multiple-edits.swift
new file mode 100644
index 0000000..cf14f45
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-multiple-edits.swift
@@ -0,0 +1,251 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-multiple-edits.swift == -req=edit -print-raw-response -pos=6:13 -length=1 -replace=" " %S/Inputs/syntaxmap-multiple-edits.swift == -req="edit" -pos=14:1 -length=0 -replace="let y = 2" -print-raw-response %S/Inputs/syntaxmap-multiple-edits.swift == -req="edit" -pos=8:10 -length=7 -replace='Int64 = 3; let z = 2' -print-raw-response %S/Inputs/syntaxmap-multiple-edits.swift == -req="edit" -pos=4:9 -length=2 -replace='50 * 95 - 100' -print-raw-response %S/Inputs/syntaxmap-multiple-edits.swift == -req="edit" -pos=1:1 -length=0 -replace='func firstFunc(x: Int) {}' -print-raw-response %S/Inputs/syntaxmap-multiple-edits.swift | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// Initial syntax map
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 152,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 2,
+// CHECK-NEXT: key.length: 14
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 16,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment.field,
+// CHECK-NEXT: key.offset: 22,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.doccomment,
+// CHECK-NEXT: key.offset: 26,
+// CHECK-NEXT: key.length: 19
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 45,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 49,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 53,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 57,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 64,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 74,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 78,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 81,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 87,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 91,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 95,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 98,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 104,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 109,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 114,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 127,
+// CHECK-NEXT: key.length: 6
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 134,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 136,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 140,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 142,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After replacing a space with a space
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: ],
+
+// After adding code at the end of the file
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 151,
+// CHECK-NEXT: key.length: 9,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 151,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 155,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 159,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+
+// After inserting more than we removed
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 98,
+// CHECK-NEXT: key.length: 20,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 98,
+// CHECK-NEXT: key.length: 5
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 106,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 109,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 113,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 117,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After inserting less than we removed
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 53,
+// CHECK-NEXT: key.length: 13,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 53,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 58,
+// CHECK-NEXT: key.length: 2
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 63,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+// After adding code at the start of the file
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 21,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 4
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 5,
+// CHECK-NEXT: key.length: 9
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 15,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.typeidentifier,
+// CHECK-NEXT: key.offset: 18,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-partial-delete.swift b/test/SourceKit/SyntaxMapData/syntaxmap-partial-delete.swift
new file mode 100644
index 0000000..3f065ea
--- /dev/null
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-partial-delete.swift
@@ -0,0 +1,39 @@
+// RUN: %sourcekitd-test -req=open -print-raw-response %S/Inputs/syntaxmap-partial-delete.swift == -req=edit -print-raw-response -pos=2:10 -length=2 -replace='' %S/Inputs/syntaxmap-partial-delete.swift | %sed_clean > %t.response
+// RUN: %FileCheck -input-file=%t.response %s
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 0,
+// CHECK-NEXT: key.length: 13,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.keyword,
+// CHECK-NEXT: key.offset: 1,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.identifier,
+// CHECK-NEXT: key.offset: 5,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 9,
+// CHECK-NEXT: key.length: 3
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+
+
+// After removing 2 chars from number literal
+
+// CHECK: {{^}}{
+// CHECK-NEXT: key.offset: 9,
+// CHECK-NEXT: key.length: 1,
+// CHECK-NEXT: key.diagnostic_stage: source.diagnostic.stage.swift.parse,
+// CHECK-NEXT: key.syntaxmap: [
+// CHECK-NEXT: {
+// CHECK-NEXT: key.kind: source.lang.swift.syntaxtype.number,
+// CHECK-NEXT: key.offset: 9,
+// CHECK-NEXT: key.length: 1
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
diff --git a/test/expr/unary/keypath/keypath-unimplemented.swift b/test/expr/unary/keypath/keypath-unimplemented.swift
index b4fdaa3..4791e87 100644
--- a/test/expr/unary/keypath/keypath-unimplemented.swift
+++ b/test/expr/unary/keypath/keypath-unimplemented.swift
@@ -9,10 +9,6 @@
var i = 0
}
-func unsupportedComponents() {
- _ = \A.[0] // expected-error{{key path support for subscript components is not implemented}}
-}
-
// rdar://problem/32209039 - Improve diagnostic when unsupported tuple element references are used in key path literals
let _ = \(Int, String).0 // expected-error {{key path cannot reference tuple elements}}
let _ = \(a: Int, b: String).b // expected-error {{key path cannot reference tuple elements}}
diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift
index fdbb755..f45b9b4 100644
--- a/test/expr/unary/keypath/keypath.swift
+++ b/test/expr/unary/keypath/keypath.swift
@@ -1,10 +1,21 @@
-// RUN: %target-swift-frontend -typecheck -parse-as-library -enable-experimental-keypath-components %s -verify
+// RUN: %target-swift-frontend -typecheck -parse-as-library %s -verify
-struct Sub {}
-struct OptSub {}
+struct Sub: Hashable {
+ static func ==(_: Sub, _: Sub) -> Bool { return true }
+ var hashValue: Int { return 0 }
+}
+struct OptSub: Hashable {
+ static func ==(_: OptSub, _: OptSub) -> Bool { return true }
+ var hashValue: Int { return 0 }
+}
+struct NonHashableSub {}
+
struct Prop {
subscript(sub: Sub) -> A { get { return A() } set { } }
subscript(optSub: OptSub) -> A? { get { return A() } set { } }
+ subscript(nonHashableSub: NonHashableSub) -> A { get { return A() } set { } }
+ subscript(a: Sub, b: Sub) -> A { get { return A() } set { } }
+ subscript(a: Sub, b: NonHashableSub) -> A { get { return A() } set { } }
var nonMutatingProperty: B {
get { fatalError() }
@@ -27,8 +38,10 @@
struct B {}
struct C<T> {
var value: T
+ subscript() -> T { get { return value } }
subscript(sub: Sub) -> T { get { return value } set { } }
- subscript<U>(sub: U) -> U { get { return sub } set { } }
+ subscript<U: Hashable>(sub: U) -> U { get { return sub } set { } }
+ subscript<X>(noHashableConstraint sub: X) -> X { get { return sub } set { } }
}
extension Array where Element == A {
@@ -39,7 +52,8 @@
func expect<T>(_ x: inout T, toHaveType _: Exactly<T>.Type) {}
-func testKeyPath(sub: Sub, optSub: OptSub, x: Int) {
+func testKeyPath(sub: Sub, optSub: OptSub,
+ nonHashableSub: NonHashableSub, x: Int) {
var a = \A.property
expect(&a, toHaveType: Exactly<WritableKeyPath<A, Prop>>.self)
@@ -152,6 +166,21 @@
let _: AnyKeyPath = \.property // expected-error{{ambiguous}}
let _: AnyKeyPath = \C.value // expected-error{{cannot convert}} (need to improve diagnostic)
let _: AnyKeyPath = \.value // expected-error{{ambiguous}}
+
+ let _ = \Prop.[nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
+ let _ = \Prop.[sub, sub]
+ let _ = \Prop.[sub, nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
+
+ let _ = \C<Int>.[]
+ let _ = \C<Int>.[sub]
+ let _ = \C<Int>.[noHashableConstraint: sub]
+ let _ = \C<Int>.[noHashableConstraint: nonHashableSub] // expected-error{{subscript index of type 'NonHashableSub' in a key path must be Hashable}}
+}
+
+func testKeyPathInGenericContext<H: Hashable, X>(hashable: H, anything: X) {
+ let _ = \C<Int>.[hashable]
+ let _ = \C<Int>.[noHashableConstraint: hashable]
+ let _ = \C<Int>.[noHashableConstraint: anything] // expected-error{{subscript index of type 'X' in a key path must be Hashable}}
}
func testDisembodiedStringInterpolation(x: Int) {
diff --git a/test/lit.cfg b/test/lit.cfg
index 1dbaefc..12a5315 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -908,17 +908,24 @@
source_compiler_rt_libs(os.path.join(test_resource_dir, 'clang', 'lib',
platform.system().lower()))
-def check_runtime_feature(name):
+def check_runtime_libs(features_to_check):
for lib in config.compiler_rt_libs:
- if lib.startswith('libclang_rt.' + name + '_'):
- config.available_features.add(name + '_runtime')
- return
+ for (libname, feature) in features_to_check:
+ if lib.startswith("libclang_rt." + libname + "_"):
+ config.available_features.add(feature)
-check_runtime_feature('profile')
-check_runtime_feature('asan')
-check_runtime_feature('ubsan')
-check_runtime_feature('tsan')
-check_runtime_feature('safestack')
+runtime_libs = [
+ ('profile', 'profile_runtime'),
+ ('asan', 'asan_runtime'),
+ ('ubsan', 'ubsan_runtime'),
+ ('tsan', 'tsan_runtime'),
+ ('safestack', 'safestack_runtime')
+]
+
+if run_ptrsize != "32":
+ runtime_libs.append(('tsan', 'tsan_runtime'))
+
+check_runtime_libs(runtime_libs)
if not getattr(config, 'target_run_simple_swift', None):
config.target_run_simple_swift = (
diff --git a/test/stdlib/KeyPath.swift b/test/stdlib/KeyPath.swift
index fcfc008..478116e 100644
--- a/test/stdlib/KeyPath.swift
+++ b/test/stdlib/KeyPath.swift
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
-// RUN: %target-build-swift %s -Xfrontend -enable-sil-ownership -Xfrontend -enable-experimental-keypath-components -o %t/a.out
+// RUN: %target-build-swift %s -Xfrontend -enable-sil-ownership -Xfrontend -g -o %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
@@ -546,4 +546,125 @@
expectEqual(kp1.hashValue, kp2.hashValue)
}
+struct SubscriptResult<T: Hashable, U: Hashable> {
+ var canary = LifetimeTracked(3333)
+ var left: T
+ var right: U
+
+ init(left: T, right: U) {
+ self.left = left
+ self.right = right
+ }
+
+ subscript(left: T) -> Bool {
+ return self.left == left
+ }
+ subscript(right: U) -> Bool {
+ return self.right == right
+ }
+}
+
+struct Subscripts<T: Hashable> {
+ var canary = LifetimeTracked(4444)
+
+ subscript<U: Hashable>(x: T, y: U) -> SubscriptResult<T, U> {
+ return SubscriptResult(left: x, right: y)
+ }
+
+ subscript(x: Int, y: Int) -> Int {
+ return x + y
+ }
+}
+
+struct KeyA: Hashable {
+ var canary = LifetimeTracked(1111)
+ var value: String
+
+ init(value: String) { self.value = value }
+
+ static func ==(a: KeyA, b: KeyA) -> Bool { return a.value == b.value }
+ var hashValue: Int { return value.hashValue }
+}
+struct KeyB: Hashable {
+ var canary = LifetimeTracked(2222)
+
+ var value: Int
+
+ init(value: Int) { self.value = value }
+
+ static func ==(a: KeyB, b: KeyB) -> Bool { return a.value == b.value }
+ var hashValue: Int { return value.hashValue }
+}
+
+func fullGenericContext<T: Hashable, U: Hashable>(x: T, y: U) -> KeyPath<Subscripts<T>, SubscriptResult<T, U>> {
+ return \Subscripts<T>.[x, y]
+}
+
+func halfGenericContext<U: Hashable>(x: KeyA, y: U) -> KeyPath<Subscripts<KeyA>, SubscriptResult<KeyA, U>> {
+ return \Subscripts<KeyA>.[x, y]
+}
+
+func nonGenericContext(x: KeyA, y: KeyB) -> KeyPath<Subscripts<KeyA>, SubscriptResult<KeyA, KeyB>> {
+ return \Subscripts<KeyA>.[x, y]
+}
+
+keyPath.test("subscripts") {
+ let a = fullGenericContext(x: KeyA(value: "hey"), y: KeyB(value: 1738))
+ let b = halfGenericContext(x: KeyA(value: "hey"), y: KeyB(value: 1738))
+ let c = nonGenericContext(x: KeyA(value: "hey"), y: KeyB(value: 1738))
+
+ expectEqual(a, b)
+ expectEqual(a, c)
+ expectEqual(b, a)
+ expectEqual(b, c)
+ expectEqual(c, a)
+ expectEqual(c, b)
+ expectEqual(a.hashValue, b.hashValue)
+ expectEqual(a.hashValue, c.hashValue)
+ expectEqual(b.hashValue, a.hashValue)
+ expectEqual(b.hashValue, c.hashValue)
+ expectEqual(c.hashValue, a.hashValue)
+ expectEqual(c.hashValue, b.hashValue)
+
+ let base = Subscripts<KeyA>()
+
+ let kp2 = \SubscriptResult<KeyA, KeyB>.[KeyA(value: "hey")]
+
+ for kp in [a, b, c] {
+ let projected = base[keyPath: kp]
+ expectEqual(projected.left.value, "hey")
+ expectEqual(projected.right.value, 1738)
+
+ expectEqual(projected[keyPath: kp2], true)
+
+ let kp12 =
+ \Subscripts<KeyA>.[KeyA(value: "hey"), KeyB(value: 1738)][KeyA(value: "hey")]
+
+ let kp12a = kp.appending(path: kp2)
+
+ expectEqual(kp12, kp12a)
+ expectEqual(kp12a, kp12)
+ expectEqual(kp12.hashValue, kp12a.hashValue)
+ }
+
+ let ints = \Subscripts<KeyA>.[17, 38]
+ let ints2 = \Subscripts<KeyA>.[17, 38]
+ let ints3 = \Subscripts<KeyA>.[38, 17]
+ expectEqual(base[keyPath: ints], 17 + 38)
+
+ expectEqual(ints, ints2)
+ expectEqual(ints2, ints)
+ expectNotEqual(ints, ints3)
+ expectNotEqual(ints2, ints3)
+ expectNotEqual(ints3, ints)
+ expectNotEqual(ints3, ints2)
+
+ expectEqual(ints.hashValue, ints2.hashValue)
+
+ let ints_be = ints.appending(path: \Int.bigEndian)
+
+ expectEqual(base[keyPath: ints_be], (17 + 38).bigEndian)
+}
+
runAllTests()
+
diff --git a/test/stdlib/KeyPathImplementation.swift b/test/stdlib/KeyPathImplementation.swift
index 7d166e2..8ccde01 100644
--- a/test/stdlib/KeyPathImplementation.swift
+++ b/test/stdlib/KeyPathImplementation.swift
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
-// RUN: %target-build-swift %s -g -Xfrontend -enable-experimental-keypath-components -o %t/a.out
+// RUN: %target-build-swift %s -g -o %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
diff --git a/test/stdlib/KeyPathObjC.swift b/test/stdlib/KeyPathObjC.swift
index aface86..787b325 100644
--- a/test/stdlib/KeyPathObjC.swift
+++ b/test/stdlib/KeyPathObjC.swift
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
-// RUN: %target-build-swift %s -Xfrontend -enable-experimental-keypath-components -o %t/a.out
+// RUN: %target-build-swift %s -o %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
// REQUIRES: objc_interop
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
index 48aef12..67abda9 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
@@ -258,110 +258,261 @@
}
}
-
struct SwiftSyntaxToken {
- unsigned Column;
+ unsigned Offset;
unsigned Length:24;
SyntaxNodeKind Kind:8;
- SwiftSyntaxToken(unsigned Column, unsigned Length,
- SyntaxNodeKind Kind)
- :Column(Column), Length(Length), Kind(Kind) { }
+ static SwiftSyntaxToken createInvalid() {
+ return {0, 0, SyntaxNodeKind::AttributeBuiltin};
+ }
+
+ SwiftSyntaxToken(unsigned Offset, unsigned Length, SyntaxNodeKind Kind)
+ : Offset(Offset), Length(Length), Kind(Kind) {}
+
+ unsigned endOffset() const { return Offset + Length; }
+
+ bool isInvalid() const { return Length == 0; }
+
+ bool operator==(const SwiftSyntaxToken &Other) const {
+ return Offset == Other.Offset && Length == Other.Length &&
+ Kind == Other.Kind;
+ }
+
+ bool operator!=(const SwiftSyntaxToken &Other) const {
+ return Offset != Other.Offset || Length != Other.Length ||
+ Kind != Other.Kind;
+ }
};
-class SwiftSyntaxMap {
- typedef std::vector<SwiftSyntaxToken> SwiftSyntaxLineMap;
- std::vector<SwiftSyntaxLineMap> Lines;
+struct SwiftEditorCharRange {
+ unsigned Offset;
+ unsigned EndOffset;
-public:
- bool matchesFirstTokenOnLine(unsigned Line,
- const SwiftSyntaxToken &Token) const {
- assert(Line > 0);
- if (Lines.size() < Line)
+ SwiftEditorCharRange(unsigned Offset, unsigned EndOffset) :
+ Offset(Offset), EndOffset(EndOffset) {}
+
+ SwiftEditorCharRange(SwiftSyntaxToken Token) :
+ Offset(Token.Offset), EndOffset(Token.endOffset()) {}
+
+ size_t length() const { return EndOffset - Offset; }
+ bool isEmpty() const { return Offset == EndOffset; }
+ bool intersects(const SwiftSyntaxToken &Token) const {
+ return this->Offset < (Token.endOffset()) && this->EndOffset > Token.Offset;
+ }
+ void extendToInclude(const SwiftEditorCharRange &Range) {
+ if (Range.Offset < Offset)
+ Offset = Range.Offset;
+ if (Range.EndOffset > EndOffset)
+ EndOffset = Range.EndOffset;
+ }
+ void extendToInclude(unsigned OtherOffset) {
+ extendToInclude({OtherOffset, OtherOffset});
+ }
+};
+
+/// Finds and represents the first mismatching tokens in two syntax maps,
+/// ignoring invalidated tokens.
+template <class Iter>
+struct TokenMismatch {
+ /// The begin and end iterators of the previous syntax map
+ Iter PrevTok, PrevEnd;
+ /// The begin and end iterators of the current syntax map
+ Iter CurrTok, CurrEnd;
+
+ TokenMismatch(Iter CurrTok, Iter CurrEnd, Iter PrevTok, Iter PrevEnd) :
+ PrevTok(PrevTok), PrevEnd(PrevEnd), CurrTok(CurrTok), CurrEnd(CurrEnd) {
+ skipInvalid();
+ while(advance());
+ }
+
+ /// Returns true if a mismatch was found
+ bool foundMismatch() const {
+ return CurrTok != CurrEnd || PrevTok != PrevEnd;
+ }
+
+ /// Returns the smallest start offset of the mismatched token ranges
+ unsigned mismatchStart() const {
+ assert(foundMismatch());
+ if (CurrTok != CurrEnd) {
+ if (PrevTok != PrevEnd)
+ return std::min(CurrTok->Offset, PrevTok->Offset);
+ return CurrTok->Offset;
+ }
+ return PrevTok->Offset;
+ }
+
+ /// Returns the largest end offset of the mismatched token ranges
+ unsigned mismatchEnd() const {
+ assert(foundMismatch());
+ if (CurrTok != CurrEnd) {
+ if (PrevTok != PrevEnd)
+ return std::max(CurrTok->endOffset(), PrevTok->endOffset());
+ return CurrTok->endOffset();
+ }
+ return PrevTok->endOffset();
+ }
+
+private:
+ void skipInvalid() {
+ while (PrevTok != PrevEnd && PrevTok->isInvalid())
+ ++PrevTok;
+ }
+
+ bool advance() {
+ if (CurrTok == CurrEnd || PrevTok == PrevEnd || *CurrTok != *PrevTok)
return false;
+ ++CurrTok;
+ ++PrevTok;
+ skipInvalid();
+ return true;
+ }
+};
- unsigned LineOffset = Line - 1;
- const SwiftSyntaxLineMap &LineMap = Lines[LineOffset];
- if (LineMap.empty())
- return false;
+/// Represents a the syntax highlighted token ranges in a source file
+struct SwiftSyntaxMap {
+ std::vector<SwiftSyntaxToken> Tokens;
- const SwiftSyntaxToken &Tok = LineMap.front();
- if (Tok.Column == Token.Column && Tok.Length == Token.Length
- && Tok.Kind == Token.Kind) {
- return true;
- }
-
- return false;
+ explicit SwiftSyntaxMap(unsigned Capacity = 0) {
+ if (Capacity)
+ Tokens.reserve(Capacity);
}
- void addTokenForLine(unsigned Line, const SwiftSyntaxToken &Token) {
- assert(Line > 0);
- if (Lines.size() < Line) {
- Lines.resize(Line);
- }
- unsigned LineOffset = Line - 1;
- SwiftSyntaxLineMap &LineMap = Lines[LineOffset];
- // FIXME: Assert this token is after the last one
- LineMap.push_back(Token);
+ void addToken(const SwiftSyntaxToken &Token) {
+ assert(Tokens.empty() || Token.Offset >= Tokens.back().Offset);
+ Tokens.push_back(Token);
}
- void mergeTokenForLine(unsigned Line, const SwiftSyntaxToken &Token) {
- assert(Line > 0);
- if (Lines.size() < Line) {
- Lines.resize(Line);
+ /// Merge this nested token into the last token that was added
+ void mergeToken(const SwiftSyntaxToken &Token) {
+ if (Tokens.empty()) {
+ Tokens.push_back(Token);
+ return;
}
- unsigned LineOffset = Line - 1;
- SwiftSyntaxLineMap &LineMap = Lines[LineOffset];
- if (!LineMap.empty()) {
- auto &LastTok = LineMap.back();
- mergeSplitRanges(LastTok.Column, LastTok.Length,
- Token.Column, Token.Length,
- [&](unsigned BeforeOff, unsigned BeforeLen,
- unsigned AfterOff, unsigned AfterLen) {
- auto LastKind = LastTok.Kind;
- LineMap.pop_back();
- if (BeforeLen)
- LineMap.emplace_back(BeforeOff, BeforeLen, LastKind);
- LineMap.push_back(Token);
- if (AfterLen)
- LineMap.emplace_back(AfterOff, AfterLen, LastKind);
- });
+ auto &LastTok = Tokens.back();
+ assert(LastTok.Offset <= Token.Offset);
+ mergeSplitRanges(LastTok.Offset, LastTok.Length, Token.Offset, Token.Length,
+ [&](unsigned BeforeOff, unsigned BeforeLen,
+ unsigned AfterOff, unsigned AfterLen) {
+ auto LastKind = LastTok.Kind;
+ Tokens.pop_back();
+ if (BeforeLen)
+ Tokens.emplace_back(BeforeOff, BeforeLen, LastKind);
+ Tokens.push_back(Token);
+ if (AfterLen)
+ Tokens.emplace_back(AfterOff, AfterLen, LastKind);
+ });
+ }
+
+ /// Adjusts the token offsets and lengths in this syntax map to account for
+ /// replacing \p Len bytes at the given \p Offset with \p NewLen bytes. Tokens
+ /// before the replacement stay the same, tokens after it are shifted, and
+ /// tokens that intersect it are 'removed' (really just marked invalid).
+ /// Clients are expected to match this behavior.
+ ///
+ /// Returns the union of the replaced range and the token ranges it
+ /// intersected, or nothing if no tokens were intersected.
+ llvm::Optional<SwiftEditorCharRange>
+ adjustForReplacement(unsigned Offset, unsigned Len, unsigned NewLen) {
+ unsigned ReplacedStart = Offset;
+ unsigned ReplacedEnd = Offset + Len;
+ bool TokenIntersected = false;
+ SwiftEditorCharRange Affected = { /*Offset=*/ReplacedStart,
+ /*EndOffset=*/ReplacedEnd};
+ // Adjust the tokens
+ auto Token = Tokens.begin();
+ while (Token != Tokens.end() && Token->endOffset() <= ReplacedStart) {
+ // Completely before the replaced range – no change needed
+ ++Token;
}
- else {
- // Not overlapping, just add the new token to the end
- LineMap.push_back(Token);
+
+ while (Token != Tokens.end() && Token->Offset < ReplacedEnd) {
+ // Intersecting the replaced range – extend Affected and invalidate
+ TokenIntersected = true;
+ Affected.extendToInclude(*Token);
+ *Token = SwiftSyntaxToken::createInvalid();
+ ++Token;
+ }
+
+ while (Token != Tokens.end()) {
+ // Completely after the replaced range - shift to account for NewLen
+ if (NewLen >= Len)
+ Token->Offset += NewLen - Len;
+ else
+ Token->Offset -= Len - NewLen;
+ ++Token;
+ }
+
+ // If the replaced range didn't intersect with any existing tokens, there's
+ // no need to report an affected range
+ if (!TokenIntersected)
+ return None;
+
+ // Update the end of the affected range to account for NewLen
+ if (NewLen >= Len) {
+ Affected.EndOffset += NewLen - Len;
+ } else {
+ Affected.EndOffset -= Len - NewLen;
+ }
+
+ return Affected;
+ }
+
+ /// Passes each token in this SwiftSyntaxMap to the given \p Consumer
+ void forEach(EditorConsumer &Consumer) {
+ for (auto &Token: Tokens) {
+ auto Kind = SwiftLangSupport::getUIDForSyntaxNodeKind(Token.Kind);
+ Consumer.handleSyntaxMap(Token.Offset, Token.Length, Kind);
}
}
- void clearLineRange(unsigned StartLine, unsigned Length) {
- assert(StartLine > 0);
- unsigned LineOffset = StartLine - 1;
- for (unsigned Line = LineOffset; Line < LineOffset + Length
- && Line < Lines.size(); ++Line) {
- Lines[Line].clear();
+ /// Finds the delta between the given SwiftSyntaxMap, \p Prev, and this one.
+ /// It passes each token not in \p Prev to the given \p Consumer and, if
+ /// needed, also expands or sets the given \p Affected range to cover all
+ /// non-matching tokens in the two lists.
+ ///
+ /// Returns true if this SwiftSyntaxMap is different to \p Prev.
+ bool forEachChanged(const SwiftSyntaxMap &Prev,
+ llvm::Optional<SwiftEditorCharRange> &Affected,
+ EditorConsumer &Consumer) const {
+ typedef std::vector<SwiftSyntaxToken>::const_iterator ForwardIt;
+ typedef std::vector<SwiftSyntaxToken>::const_reverse_iterator ReverseIt;
+
+ // Find the first pair of tokens that don't match
+ TokenMismatch<ForwardIt>
+ Forward(Tokens.begin(), Tokens.end(), Prev.Tokens.begin(), Prev.Tokens.end());
+
+ // Exit early if there was no mismatch
+ if (!Forward.foundMismatch())
+ return Affected && !Affected->isEmpty();
+
+ // Find the last pair of tokens that don't match
+ TokenMismatch<ReverseIt>
+ Backward(Tokens.rbegin(), Tokens.rend(), Prev.Tokens.rbegin(), Prev.Tokens.rend());
+ assert(Backward.foundMismatch());
+
+ // Set or extend the affected range to include the mismatched range
+ SwiftEditorCharRange
+ MismatchRange = {Forward.mismatchStart(),Backward.mismatchEnd()};
+ if (!Affected) {
+ Affected = MismatchRange;
+ } else {
+ Affected->extendToInclude(MismatchRange);
}
- }
- void removeLineRange(unsigned StartLine, unsigned Length) {
- assert(StartLine > 0 && Length > 0);
-
- if (StartLine < Lines.size()) {
- unsigned EndLine = StartLine + Length - 1;
- // Delete all syntax map data from start line through end line
- Lines.erase(Lines.begin() + StartLine - 1,
- EndLine >= Lines.size() ? Lines.end()
- : Lines.begin() + EndLine);
+ // Report all tokens in the affected range to the EditorConsumer
+ auto From = Forward.CurrTok;
+ auto To = Backward.CurrTok;
+ while (From != Tokens.begin() && (From-1)->Offset >= Affected->Offset)
+ --From;
+ while (To != Tokens.rbegin() && (To-1)->endOffset() <= Affected->EndOffset)
+ --To;
+ for (; From < To.base(); ++From) {
+ auto Kind = SwiftLangSupport::getUIDForSyntaxNodeKind(From->Kind);
+ Consumer.handleSyntaxMap(From->Offset, From->Length, Kind);
}
- }
- void insertLineRange(unsigned StartLine, unsigned Length) {
- Lines.insert(StartLine <= Lines.size() ? Lines.begin() + StartLine - 1
- : Lines.end(),
- Length, SwiftSyntaxLineMap());
- }
-
- void reset() {
- Lines.clear();
+ return true;
}
};
@@ -373,8 +524,6 @@
:Offset(Offset), Length(Length), Kind(Kind) { }
};
-typedef std::pair<unsigned, unsigned> SwiftEditorCharRange;
-
struct SwiftSemanticToken {
unsigned ByteOffset;
unsigned Length : 24;
@@ -849,9 +998,12 @@
const std::string FilePath;
EditableTextBufferRef EditableBuffer;
+ /// The list of syntax highlighted token offsets and ranges in the document
SwiftSyntaxMap SyntaxMap;
- LineRange EditedLineRange;
- SwiftEditorCharRange AffectedRange;
+ /// The minimal range of syntax highlighted tokens affected by the last edit
+ llvm::Optional<SwiftEditorCharRange> AffectedRange;
+ /// Whether the last operation was an edit rather than a document open
+ bool Edited;
std::vector<DiagnosticEntryInfo> ParserDiagnostics;
RefPtr<SwiftDocumentSemanticInfo> SemanticInfo;
@@ -1180,121 +1332,39 @@
}
};
+/// Walks the syntax model to populate a given SwiftSyntaxMap with the token
+/// ranges to highlight and pass document structure information to the given
+/// EditorConsumer.
class SwiftEditorSyntaxWalker: public ide::SyntaxModelWalker {
+ /// The syntax map to populate
SwiftSyntaxMap &SyntaxMap;
- LineRange EditedLineRange;
- SwiftEditorCharRange &AffectedRange;
SourceManager &SrcManager;
- EditorConsumer &Consumer;
unsigned BufferID;
SwiftDocumentStructureWalker DocStructureWalker;
- std::vector<EditorConsumerSyntaxMapEntry> ConsumerSyntaxMap;
+ /// The current token nesting level (e.g. for a field in a doc comment)
unsigned NestingLevel = 0;
public:
SwiftEditorSyntaxWalker(SwiftSyntaxMap &SyntaxMap,
- LineRange EditedLineRange,
- SwiftEditorCharRange &AffectedRange,
SourceManager &SrcManager, EditorConsumer &Consumer,
unsigned BufferID)
- : SyntaxMap(SyntaxMap), EditedLineRange(EditedLineRange),
- AffectedRange(AffectedRange), SrcManager(SrcManager), Consumer(Consumer),
- BufferID(BufferID),
+ : SyntaxMap(SyntaxMap), SrcManager(SrcManager), BufferID(BufferID),
DocStructureWalker(SrcManager, BufferID, Consumer) { }
bool walkToNodePre(SyntaxNode Node) override {
if (Node.Kind == SyntaxNodeKind::CommentMarker)
return DocStructureWalker.walkToNodePre(Node);
-
++NestingLevel;
- SourceLoc StartLoc = Node.Range.getStart();
- auto StartLineAndColumn = SrcManager.getLineAndColumn(StartLoc);
- auto EndLineAndColumn = SrcManager.getLineAndColumn(Node.Range.getEnd());
- unsigned StartLine = StartLineAndColumn.first;
- unsigned EndLine = EndLineAndColumn.second > 1 ? EndLineAndColumn.first
- : EndLineAndColumn.first - 1;
- unsigned Offset = SrcManager.getByteDistance(
- SrcManager.getLocForBufferStart(BufferID), StartLoc);
- // Note that the length can span multiple lines.
- unsigned Length = Node.Range.getByteLength();
- SwiftSyntaxToken Token(StartLineAndColumn.second, Length,
- Node.Kind);
- if (EditedLineRange.isValid()) {
- if (StartLine < EditedLineRange.startLine()) {
- if (EndLine < EditedLineRange.startLine()) {
- // We're entirely before the edited range, no update needed.
- return true;
- }
+ auto End = SrcManager.getLocOffsetInBuffer(Node.Range.getEnd(), BufferID),
+ Start = SrcManager.getLocOffsetInBuffer(Node.Range.getStart(), BufferID);
- // This token starts before the edited range, but doesn't end before it,
- // we need to adjust edited line range and clear the affected syntax map
- // line range.
- unsigned AdjLineCount = EditedLineRange.startLine() - StartLine;
- EditedLineRange.setRange(StartLine, AdjLineCount
- + EditedLineRange.lineCount());
- SyntaxMap.clearLineRange(StartLine, AdjLineCount);
-
- // Also adjust the affected char range accordingly.
- unsigned AdjCharCount = AffectedRange.first - Offset;
- AffectedRange.first -= AdjCharCount;
- AffectedRange.second += AdjCharCount;
- }
- else if (Offset > AffectedRange.first + AffectedRange.second) {
- // We're passed the affected range and already synced up, just return.
- return true;
- }
- else if (StartLine > EditedLineRange.endLine()) {
- // We're after the edited line range, let's test if we're synced up.
- if (SyntaxMap.matchesFirstTokenOnLine(StartLine, Token)) {
- // We're synced up, mark the affected range and return.
- AffectedRange.second =
- Offset - (StartLineAndColumn.second - 1) - AffectedRange.first;
- return true;
- }
-
- // We're not synced up, continue replacing syntax map data on this line.
- SyntaxMap.clearLineRange(StartLine, 1);
- EditedLineRange.extendToIncludeLine(StartLine);
- }
-
- if (EndLine > StartLine) {
- // The token spans multiple lines, make sure to replace syntax map data
- // for affected lines.
- EditedLineRange.extendToIncludeLine(EndLine);
-
- unsigned LineCount = EndLine - StartLine + 1;
- SyntaxMap.clearLineRange(StartLine, LineCount);
- }
-
- }
-
- // Add the syntax map token.
- if (NestingLevel > 1)
- SyntaxMap.mergeTokenForLine(StartLine, Token);
- else
- SyntaxMap.addTokenForLine(StartLine, Token);
-
- // Add consumer entry.
- unsigned ByteOffset = SrcManager.getLocOffsetInBuffer(Node.Range.getStart(),
- BufferID);
- UIdent Kind = SwiftLangSupport::getUIDForSyntaxNodeKind(Node.Kind);
if (NestingLevel > 1) {
- assert(!ConsumerSyntaxMap.empty());
- auto &Last = ConsumerSyntaxMap.back();
- mergeSplitRanges(Last.Offset, Last.Length, ByteOffset, Length,
- [&](unsigned BeforeOff, unsigned BeforeLen,
- unsigned AfterOff, unsigned AfterLen) {
- auto LastKind = Last.Kind;
- ConsumerSyntaxMap.pop_back();
- if (BeforeLen)
- ConsumerSyntaxMap.emplace_back(BeforeOff, BeforeLen, LastKind);
- ConsumerSyntaxMap.emplace_back(ByteOffset, Length, Kind);
- if (AfterLen)
- ConsumerSyntaxMap.emplace_back(AfterOff, AfterLen, LastKind);
- });
+ // We're nested inside the previously reported token - merge
+ SyntaxMap.mergeToken({Start, End - Start, Node.Kind});
+ } else {
+ // We're a top-level token, add it after the previous one
+ SyntaxMap.addToken({Start, End - Start, Node.Kind});
}
- else
- ConsumerSyntaxMap.emplace_back(ByteOffset, Length, Kind);
return true;
}
@@ -1302,14 +1372,7 @@
bool walkToNodePost(SyntaxNode Node) override {
if (Node.Kind == SyntaxNodeKind::CommentMarker)
return DocStructureWalker.walkToNodePost(Node);
-
- if (--NestingLevel == 0) {
- // We've unwound to the top level, so inform the consumer and drain
- // the consumer syntax map queue.
- for (auto &Entry: ConsumerSyntaxMap)
- Consumer.handleSyntaxMap(Entry.Offset, Entry.Length, Entry.Kind);
- ConsumerSyntaxMap.clear();
- }
+ --NestingLevel;
return true;
}
@@ -1590,11 +1653,14 @@
llvm::sys::ScopedLock L(Impl.AccessMtx);
+ Impl.Edited = false;
Impl.EditableBuffer =
new EditableTextBuffer(Impl.FilePath, Buf->getBuffer());
- Impl.SyntaxMap.reset();
- Impl.EditedLineRange.setRange(0,0);
- Impl.AffectedRange = std::make_pair(0, Buf->getBufferSize());
+
+ // Reset the syntax map data and affected range
+ Impl.SyntaxMap.Tokens.clear();
+ Impl.AffectedRange = {0, static_cast<unsigned>(Buf->getBufferSize())};
+
Impl.SemanticInfo =
new SwiftDocumentSemanticInfo(Impl.FilePath, Impl.LangSupport);
Impl.SemanticInfo->setCompilerArgs(Args);
@@ -1607,7 +1673,10 @@
llvm::sys::ScopedLock L(Impl.AccessMtx);
+ Impl.Edited = true;
llvm::StringRef Str = Buf->getBuffer();
+
+ // Update the buffer itself
ImmutableTextSnapshotRef Snapshot =
Impl.EditableBuffer->replace(Offset, Length, Str);
@@ -1633,37 +1702,12 @@
}
}
- SourceManager &SrcManager = Impl.SyntaxInfo->getSourceManager();
- unsigned BufID = Impl.SyntaxInfo->getBufferID();
- SourceLoc StartLoc = SrcManager.getLocForBufferStart(BufID).getAdvancedLoc(
- Offset);
- unsigned StartLine = SrcManager.getLineAndColumn(StartLoc).first;
- unsigned EndLine = SrcManager.getLineAndColumn(
- StartLoc.getAdvancedLoc(Length)).first;
-
- // Delete all syntax map data from start line through end line.
- unsigned OldLineCount = EndLine - StartLine + 1;
- Impl.SyntaxMap.removeLineRange(StartLine, OldLineCount);
-
- // Insert empty syntax map data for replaced lines.
- unsigned NewLineCount = Str.count('\n') + 1;
- Impl.SyntaxMap.insertLineRange(StartLine, NewLineCount);
-
- // Update the edited line range.
- Impl.EditedLineRange.setRange(StartLine, NewLineCount);
-
- ImmutableTextBufferRef ImmBuf = Snapshot->getBuffer();
-
- // The affected range starts from the previous newline.
- if (Offset > 0) {
- auto AffectedRangeOffset = ImmBuf->getText().rfind('\n', Offset);
- Impl.AffectedRange.first =
- AffectedRangeOffset != StringRef::npos ? AffectedRangeOffset + 1 : 0;
- }
- else
- Impl.AffectedRange.first = 0;
-
- Impl.AffectedRange.second = ImmBuf->getText().size() - Impl.AffectedRange.first;
+ // Update the old syntax map offsets to account for the replaced range.
+ // Also set the initial AffectedRange to cover any tokens that
+ // the replaced range intersected. This allows for clients that split
+ // multi-line tokens at line boundaries, and ensure all parts of these tokens
+ // will be cleared.
+ Impl.AffectedRange = Impl.SyntaxMap.adjustForReplacement(Offset, Length, Str.size());
return Snapshot;
}
@@ -1716,17 +1760,34 @@
ide::SyntaxModelContext ModelContext(Impl.SyntaxInfo->getSourceFile());
- SwiftEditorSyntaxWalker SyntaxWalker(Impl.SyntaxMap,
- Impl.EditedLineRange,
- Impl.AffectedRange,
+ SwiftSyntaxMap NewMap = SwiftSyntaxMap(Impl.SyntaxMap.Tokens.size() + 16);
+
+ SwiftEditorSyntaxWalker SyntaxWalker(NewMap,
Impl.SyntaxInfo->getSourceManager(),
Consumer,
Impl.SyntaxInfo->getBufferID());
-
ModelContext.walk(SyntaxWalker);
- Consumer.recordAffectedRange(Impl.AffectedRange.first,
- Impl.AffectedRange.second);
+ bool SawChanges = true;
+ if (Impl.Edited) {
+ // We're ansering an edit request. Report all highlighted token ranges not
+ // in the previous syntax map to the Consumer and extend the AffectedRange
+ // to contain all added/removed token ranges.
+ SawChanges = NewMap.forEachChanged(Impl.SyntaxMap, Impl.AffectedRange,
+ Consumer);
+ } else {
+ // The is an open/initialise. Report all highlighted token ranges to the
+ // Consumer.
+ NewMap.forEach(Consumer);
+ }
+ Impl.SyntaxMap = std::move(NewMap);
+
+ // Recording an affected length of 0 still results in the client updating its
+ // copy of the syntax map (by clearning all tokens on the line of the affected
+ // offset). We need to not record it at all to signal a no-op.
+ if (SawChanges)
+ Consumer.recordAffectedRange(Impl.AffectedRange->Offset,
+ Impl.AffectedRange->length());
}
void SwiftEditorDocument::readSemanticInfo(ImmutableTextSnapshotRef Snapshot,
diff --git a/unittests/runtime/weak.mm b/unittests/runtime/weak.mm
index 2e11a3a..faf19d2 100644
--- a/unittests/runtime/weak.mm
+++ b/unittests/runtime/weak.mm
@@ -277,7 +277,8 @@
DestroyedObjCCount = 0;
WeakReference ref1;
- swift_unknownWeakInit(&ref1, o1);
+ auto res = swift_unknownWeakInit(&ref1, o1);
+ ASSERT_EQ(&ref1, res);
void *tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(tmp, o1);
@@ -435,7 +436,8 @@
ASSERT_EQ(nullptr, result);
// ref2 = ref1 (nil -> nil)
- swift_unknownUnownedCopyInit(&ref2, &ref1);
+ auto res = swift_unknownUnownedCopyInit(&ref2, &ref1);
+ ASSERT_EQ(&ref2, res);
result = swift_unknownUnownedLoadStrong(&ref1);
ASSERT_EQ(nullptr, result);
result = swift_unknownUnownedLoadStrong(&ref2);
@@ -535,7 +537,8 @@
ASSERT_EQ(nullptr, result);
// ref2 = ref1 (nil -> nil)
- swift_unknownUnownedTakeInit(&ref2, &ref1);
+ auto res = swift_unknownUnownedTakeInit(&ref2, &ref1);
+ ASSERT_EQ(&ref2, res);
result = swift_unknownUnownedLoadStrong(&ref2);
ASSERT_EQ(nullptr, result);
swift_unknownUnownedDestroy(&ref2);
@@ -638,7 +641,8 @@
swift_unknownRelease(result);
// ref1 = ref2 (objc self transition)
- swift_unknownUnownedCopyAssign(&ref1, &ref2);
+ auto res = swift_unknownUnownedCopyAssign(&ref1, &ref2);
+ ASSERT_EQ(&ref1, res);
result = swift_unknownUnownedLoadStrong(&ref1);
ASSERT_EQ(objc1, result);
swift_unknownRelease(result);
@@ -766,7 +770,8 @@
void *result;
// ref1 = objc1
- swift_unknownUnownedInit(&ref1, objc1);
+ auto res = swift_unknownUnownedInit(&ref1, objc1);
+ ASSERT_EQ(&ref1, res);
result = swift_unknownUnownedLoadStrong(&ref1);
ASSERT_EQ(objc1, result);
swift_unknownRelease(result);
@@ -778,7 +783,8 @@
swift_unknownRelease(result);
// ref1 = ref2 (objc self transition)
- swift_unknownUnownedTakeAssign(&ref1, &ref2);
+ res = swift_unknownUnownedTakeAssign(&ref1, &ref2);
+ ASSERT_EQ(&ref1, res);
result = swift_unknownUnownedLoadStrong(&ref1);
ASSERT_EQ(objc1, result);
swift_unknownRelease(result);
@@ -928,3 +934,34 @@
swift_unownedDestroy(&ref1);
swift_unknownUnownedDestroy(&ref2);
}
+
+TEST(WeakTest, unknownWeak) {
+ void *objc1 = make_objc_object();
+ HeapObject *swift1 = make_swift_object();
+
+ WeakReference ref1;
+ auto res = swift_unknownWeakInit(&ref1, objc1);
+ ASSERT_EQ(&ref1, res);
+
+ WeakReference ref2;
+ res = swift_unknownWeakCopyInit(&ref2, &ref1);
+ ASSERT_EQ(&ref2, res);
+
+ WeakReference ref3; // ref2 dead.
+ res = swift_unknownWeakTakeInit(&ref3, &ref2);
+ ASSERT_EQ(&ref3, res);
+
+ res = swift_unknownWeakAssign(&ref3, swift1);
+ ASSERT_EQ(&ref3, res);
+
+ res = swift_unknownWeakCopyAssign(&ref3, &ref1);
+ ASSERT_EQ(&ref3, res);
+
+ res = swift_unknownWeakTakeAssign(&ref3, &ref1);
+ ASSERT_EQ(&ref3, res);
+
+ swift_unknownWeakDestroy(&ref3);
+
+ swift_release(swift1);
+ swift_unknownRelease(objc1);
+}
diff --git a/utils/build-script b/utils/build-script
index a707aef..b4ba44d 100755
--- a/utils/build-script
+++ b/utils/build-script
@@ -268,80 +268,80 @@
# iterate over all supported platforms.
self.platforms_to_skip_build = set()
- if args.skip_build_linux:
+ if not args.build_linux:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.Linux)
- if args.skip_build_freebsd:
+ if not args.build_freebsd:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.FreeBSD)
- if args.skip_build_cygwin:
+ if not args.build_cygwin:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.Cygwin)
- if args.skip_build_osx:
+ if not args.build_osx:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.OSX)
- if args.skip_build_ios_device:
+ if not args.build_ios_device:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.iOS)
- if args.skip_build_ios_simulator:
+ if not args.build_ios_simulator:
self.platforms_to_skip_build.add(
StdlibDeploymentTarget.iOSSimulator)
- if args.skip_build_tvos_device:
+ if not args.build_tvos_device:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.AppleTV)
- if args.skip_build_tvos_simulator:
+ if not args.build_tvos_simulator:
self.platforms_to_skip_build.add(
StdlibDeploymentTarget.AppleTVSimulator)
- if args.skip_build_watchos_device:
+ if not args.build_watchos_device:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.AppleWatch)
- if args.skip_build_watchos_simulator:
+ if not args.build_watchos_simulator:
self.platforms_to_skip_build.add(
StdlibDeploymentTarget.AppleWatchSimulator)
- if args.skip_build_android:
+ if not args.build_android:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.Android)
self.platforms_to_skip_test = set()
self.platforms_archs_to_skip_test = set()
- if args.skip_test_linux:
+ if not args.test_linux:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.Linux)
- if args.skip_test_freebsd:
+ if not args.test_freebsd:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.FreeBSD)
- if args.skip_test_cygwin:
+ if not args.test_cygwin:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.Cygwin)
- if args.skip_test_osx:
+ if not args.test_osx:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.OSX)
- if args.skip_test_ios_host:
+ if not args.test_ios_device:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.iOS)
else:
exit_rejecting_arguments("error: iOS device tests are not " +
"supported in open-source Swift.")
- if args.skip_test_ios_simulator:
+ if not args.test_ios_simulator:
self.platforms_to_skip_test.add(
StdlibDeploymentTarget.iOSSimulator)
- if args.skip_test_ios_32bit_simulator:
+ if not args.test_ios_32bit_simulator:
self.platforms_archs_to_skip_test.add(
StdlibDeploymentTarget.iOSSimulator.i386)
- if args.skip_test_tvos_host:
+ if not args.test_tvos_device:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTV)
else:
exit_rejecting_arguments("error: tvOS device tests are not " +
"supported in open-source Swift.")
- if args.skip_test_tvos_simulator:
+ if not args.test_tvos_simulator:
self.platforms_to_skip_test.add(
StdlibDeploymentTarget.AppleTVSimulator)
- if args.skip_test_watchos_host:
+ if not args.test_watchos_device:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleWatch)
else:
exit_rejecting_arguments("error: watchOS device tests are not " +
"supported in open-source Swift.")
- if args.skip_test_watchos_simulator:
+ if not args.test_watchos_simulator:
self.platforms_to_skip_test.add(
StdlibDeploymentTarget.AppleWatchSimulator)
- if args.skip_test_android_host:
+ if not args.test_android_device:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.Android)
self.platforms_to_skip_test_host = set()
- if args.skip_test_ios_host:
+ if not args.test_ios_device:
self.platforms_to_skip_test_host.add(StdlibDeploymentTarget.iOS)
- if args.skip_test_tvos_host:
+ if not args.test_tvos_device:
self.platforms_to_skip_test_host.add(
StdlibDeploymentTarget.AppleTV)
- if args.skip_test_watchos_host:
+ if not args.test_watchos_device:
self.platforms_to_skip_test_host.add(
StdlibDeploymentTarget.AppleWatch)
@@ -501,7 +501,7 @@
impl_args += ["--skip-build-cmark",
"--skip-build-llvm",
"--skip-build-swift"]
- if args.skip_build_benchmarks:
+ if not args.build_benchmarks:
impl_args += ["--skip-build-benchmarks"]
if not args.build_foundation:
impl_args += ["--skip-build-foundation"]
@@ -532,27 +532,27 @@
if args.build_swift_static_sdk_overlay:
impl_args += ["--build-swift-static-sdk-overlay"]
- if args.skip_build_linux:
+ if not args.build_linux:
impl_args += ["--skip-build-linux"]
- if args.skip_build_freebsd:
+ if not args.build_freebsd:
impl_args += ["--skip-build-freebsd"]
- if args.skip_build_cygwin:
+ if not args.build_cygwin:
impl_args += ["--skip-build-cygwin"]
- if args.skip_build_osx:
+ if not args.build_osx:
impl_args += ["--skip-build-osx"]
- if args.skip_build_ios_device:
+ if not args.build_ios_device:
impl_args += ["--skip-build-ios-device"]
- if args.skip_build_ios_simulator:
+ if not args.build_ios_simulator:
impl_args += ["--skip-build-ios-simulator"]
- if args.skip_build_tvos_device:
+ if not args.build_tvos_device:
impl_args += ["--skip-build-tvos-device"]
- if args.skip_build_tvos_simulator:
+ if not args.build_tvos_simulator:
impl_args += ["--skip-build-tvos-simulator"]
- if args.skip_build_watchos_device:
+ if not args.build_watchos_device:
impl_args += ["--skip-build-watchos-device"]
- if args.skip_build_watchos_simulator:
+ if not args.build_watchos_simulator:
impl_args += ["--skip-build-watchos-simulator"]
- if args.skip_build_android:
+ if not args.build_android:
impl_args += ["--skip-build-android"]
if not args.test and not args.long_test:
@@ -568,29 +568,29 @@
"--skip-test-libicu",
"--skip-test-playgroundlogger",
"--skip-test-playgroundsupport"]
- if args.skip_test_linux:
+ if not args.test_linux:
impl_args += ["--skip-test-linux"]
- if args.skip_test_freebsd:
+ if not args.test_freebsd:
impl_args += ["--skip-test-freebsd"]
- if args.skip_test_cygwin:
+ if not args.test_cygwin:
impl_args += ["--skip-test-cygwin"]
- if args.skip_test_osx:
+ if not args.test_osx:
impl_args += ["--skip-test-osx"]
- if args.skip_test_ios_host:
+ if not args.test_ios_device:
impl_args += ["--skip-test-ios-host"]
- if args.skip_test_ios_simulator:
+ if not args.test_ios_simulator:
impl_args += ["--skip-test-ios-simulator"]
- if args.skip_test_ios_32bit_simulator:
+ if not args.test_ios_32bit_simulator:
impl_args += ["--skip-test-ios-32bit-simulator"]
- if args.skip_test_tvos_host:
+ if not args.test_tvos_device:
impl_args += ["--skip-test-tvos-host"]
- if args.skip_test_tvos_simulator:
+ if not args.test_tvos_simulator:
impl_args += ["--skip-test-tvos-simulator"]
- if args.skip_test_watchos_host:
+ if not args.test_watchos_device:
impl_args += ["--skip-test-watchos-host"]
- if args.skip_test_watchos_simulator:
+ if not args.test_watchos_simulator:
impl_args += ["--skip-test-watchos-simulator"]
- if args.skip_test_android_host:
+ if not args.test_android_device:
impl_args += ["--skip-test-android-host"]
if args.build_runtime_with_host_compiler:
impl_args += ["--build-runtime-with-host-compiler"]
diff --git a/utils/build_swift/driver_arguments.py b/utils/build_swift/driver_arguments.py
index dab1b72..c902c00 100644
--- a/utils/build_swift/driver_arguments.py
+++ b/utils/build_swift/driver_arguments.py
@@ -144,15 +144,15 @@
# Propagate global --skip-build
if args.skip_build:
- args.skip_build_linux = True
- args.skip_build_freebsd = True
- args.skip_build_cygwin = True
- args.skip_build_osx = True
- args.skip_build_ios = True
- args.skip_build_tvos = True
- args.skip_build_watchos = True
- args.skip_build_android = True
- args.skip_build_benchmarks = True
+ args.build_linux = False
+ args.build_freebsd = False
+ args.build_cygwin = False
+ args.build_osx = False
+ args.build_ios = False
+ args.build_tvos = False
+ args.build_watchos = False
+ args.build_android = False
+ args.build_benchmarks = False
args.build_lldb = False
args.build_llbuild = False
args.build_swiftpm = False
@@ -165,20 +165,20 @@
# --skip-{ios,tvos,watchos} or --skip-build-{ios,tvos,watchos} are
# merely shorthands for --skip-build-{**os}-{device,simulator}
- if not args.ios or args.skip_build_ios:
- args.skip_build_ios_device = True
- args.skip_build_ios_simulator = True
+ if not args.ios or not args.build_ios:
+ args.build_ios_device = False
+ args.build_ios_simulator = False
- if not args.tvos or args.skip_build_tvos:
- args.skip_build_tvos_device = True
- args.skip_build_tvos_simulator = True
+ if not args.tvos or not args.build_tvos:
+ args.build_tvos_device = False
+ args.build_tvos_simulator = False
- if not args.watchos or args.skip_build_watchos:
- args.skip_build_watchos_device = True
- args.skip_build_watchos_simulator = True
+ if not args.watchos or not args.build_watchos:
+ args.build_watchos_device = False
+ args.build_watchos_simulator = False
- if not args.android or args.skip_build_android:
- args.skip_build_android = True
+ if not args.android or not args.build_android:
+ args.build_android = False
# --validation-test implies --test.
if args.validation_test:
@@ -194,53 +194,53 @@
# If none of tests specified skip swift stdlib test on all platforms
if not args.test and not args.validation_test and not args.long_test:
- args.skip_test_linux = True
- args.skip_test_freebsd = True
- args.skip_test_cygwin = True
- args.skip_test_osx = True
- args.skip_test_ios = True
- args.skip_test_tvos = True
- args.skip_test_watchos = True
+ args.test_linux = False
+ args.test_freebsd = False
+ args.test_cygwin = False
+ args.test_osx = False
+ args.test_ios = False
+ args.test_tvos = False
+ args.test_watchos = False
# --skip-test-ios is merely a shorthand for host and simulator tests.
- if args.skip_test_ios:
- args.skip_test_ios_host = True
- args.skip_test_ios_simulator = True
+ if not args.test_ios:
+ args.test_ios_device = False
+ args.test_ios_simulator = False
# --skip-test-tvos is merely a shorthand for host and simulator tests.
- if args.skip_test_tvos:
- args.skip_test_tvos_host = True
- args.skip_test_tvos_simulator = True
+ if not args.test_tvos:
+ args.test_tvos_device = False
+ args.test_tvos_simulator = False
# --skip-test-watchos is merely a shorthand for host and simulator
# --tests.
- if args.skip_test_watchos:
- args.skip_test_watchos_host = True
- args.skip_test_watchos_simulator = True
+ if not args.test_watchos:
+ args.test_watchos_device = False
+ args.test_watchos_simulator = False
# --skip-build-{ios,tvos,watchos}-{device,simulator} implies
# --skip-test-{ios,tvos,watchos}-{host,simulator}
- if args.skip_build_ios_device:
- args.skip_test_ios_host = True
- if args.skip_build_ios_simulator:
- args.skip_test_ios_simulator = True
+ if not args.build_ios_device:
+ args.test_ios_device = False
+ if not args.build_ios_simulator:
+ args.test_ios_simulator = False
- if args.skip_build_tvos_device:
- args.skip_test_tvos_host = True
- if args.skip_build_tvos_simulator:
- args.skip_test_tvos_simulator = True
+ if not args.build_tvos_device:
+ args.test_tvos_device = False
+ if not args.build_tvos_simulator:
+ args.test_tvos_simulator = False
- if args.skip_build_watchos_device:
- args.skip_test_watchos_host = True
- if args.skip_build_watchos_simulator:
- args.skip_test_watchos_simulator = True
+ if not args.build_watchos_device:
+ args.test_watchos_device = False
+ if not args.build_watchos_simulator:
+ args.test_watchos_simulator = False
- if args.skip_build_android:
- args.skip_test_android_host = True
+ if not args.build_android:
+ args.test_android_device = False
if not args.host_test:
- args.skip_test_ios_host = True
- args.skip_test_tvos_host = True
- args.skip_test_watchos_host = True
- args.skip_test_android_host = True
+ args.test_ios_device = False
+ args.test_tvos_device = False
+ args.test_watchos_device = False
+ args.test_android_device = False
if args.build_subdir is None:
args.build_subdir = \
@@ -259,7 +259,7 @@
if StdlibDeploymentTarget.Android.contains(tgt)]
if not args.android and len(android_tgts) > 0:
args.android = True
- args.skip_build_android = True
+ args.build_android = False
def create_argument_parser():
@@ -616,20 +616,24 @@
iterations with -Onone", metavar='N', type=int, default=3)
run_tests_group.add_argument(
"--skip-test-osx",
- help="skip testing Swift stdlibs for Mac OS X",
- action=arguments.action.optional_bool)
+ dest='test_osx',
+ action=arguments.action.optional_false,
+ help="skip testing Swift stdlibs for Mac OS X")
run_tests_group.add_argument(
"--skip-test-linux",
- help="skip testing Swift stdlibs for Linux",
- action=arguments.action.optional_bool)
+ dest='test_linux',
+ action=arguments.action.optional_false,
+ help="skip testing Swift stdlibs for Linux")
run_tests_group.add_argument(
"--skip-test-freebsd",
- help="skip testing Swift stdlibs for FreeBSD",
- action=arguments.action.optional_bool)
+ dest='test_freebsd',
+ action=arguments.action.optional_false,
+ help="skip testing Swift stdlibs for FreeBSD")
run_tests_group.add_argument(
"--skip-test-cygwin",
- help="skip testing Swift stdlibs for Cygwin",
- action=arguments.action.optional_bool)
+ dest='test_cygwin',
+ action=arguments.action.optional_false,
+ help="skip testing Swift stdlibs for Cygwin")
parser.add_argument(
"--build-runtime-with-host-compiler",
help="Use the host compiler, not the self-built one to compile the "
@@ -666,130 +670,155 @@
action="store_true")
run_build_group.add_argument(
"--skip-build-linux",
- help="skip building Swift stdlibs for Linux",
- action=arguments.action.optional_bool)
+ dest='build_linux',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for Linux")
run_build_group.add_argument(
"--skip-build-freebsd",
- help="skip building Swift stdlibs for FreeBSD",
- action=arguments.action.optional_bool)
+ dest='build_freebsd',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for FreeBSD")
run_build_group.add_argument(
"--skip-build-cygwin",
- help="skip building Swift stdlibs for Cygwin",
- action=arguments.action.optional_bool)
+ dest='build_cygwin',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for Cygwin")
run_build_group.add_argument(
"--skip-build-osx",
- help="skip building Swift stdlibs for MacOSX",
- action=arguments.action.optional_bool)
+ dest='build_osx',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for MacOSX")
run_build_group.add_argument(
"--skip-build-ios",
- help="skip building Swift stdlibs for iOS",
- action=arguments.action.optional_bool)
+ dest='build_ios',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for iOS")
run_build_group.add_argument(
"--skip-build-ios-device",
+ dest='build_ios_device',
+ action=arguments.action.optional_false,
help="skip building Swift stdlibs for iOS devices "
- "(i.e. build simulators only)",
- action=arguments.action.optional_bool)
+ "(i.e. build simulators only)")
run_build_group.add_argument(
"--skip-build-ios-simulator",
+ dest='build_ios_simulator',
+ action=arguments.action.optional_false,
help="skip building Swift stdlibs for iOS simulator "
- "(i.e. build devices only)",
- action=arguments.action.optional_bool)
+ "(i.e. build devices only)")
run_build_group.add_argument(
"--skip-build-tvos",
- help="skip building Swift stdlibs for tvOS",
- action=arguments.action.optional_bool)
+ dest='build_tvos',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for tvOS")
run_build_group.add_argument(
"--skip-build-tvos-device",
+ dest='build_tvos_device',
+ action=arguments.action.optional_false,
help="skip building Swift stdlibs for tvOS devices "
- "(i.e. build simulators only)",
- action=arguments.action.optional_bool)
+ "(i.e. build simulators only)")
run_build_group.add_argument(
"--skip-build-tvos-simulator",
+ dest='build_tvos_simulator',
+ action=arguments.action.optional_false,
help="skip building Swift stdlibs for tvOS simulator "
- "(i.e. build devices only)",
- action=arguments.action.optional_bool)
+ "(i.e. build devices only)")
run_build_group.add_argument(
"--skip-build-watchos",
- help="skip building Swift stdlibs for watchOS",
- action=arguments.action.optional_bool)
+ dest='build_watchos',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for watchOS")
run_build_group.add_argument(
"--skip-build-watchos-device",
+ dest='build_watchos_device',
+ action=arguments.action.optional_false,
help="skip building Swift stdlibs for watchOS devices "
- "(i.e. build simulators only)",
- action=arguments.action.optional_bool)
+ "(i.e. build simulators only)")
run_build_group.add_argument(
"--skip-build-watchos-simulator",
+ dest='build_watchos_simulator',
+ action=arguments.action.optional_false,
help="skip building Swift stdlibs for watchOS simulator "
- "(i.e. build devices only)",
- action=arguments.action.optional_bool)
+ "(i.e. build devices only)")
run_build_group.add_argument(
"--skip-build-android",
- help="skip building Swift stdlibs for Android",
- action=arguments.action.optional_bool)
+ dest='build_android',
+ action=arguments.action.optional_false,
+ help="skip building Swift stdlibs for Android")
run_build_group.add_argument(
"--skip-build-benchmarks",
- help="skip building Swift Benchmark Suite",
- action=arguments.action.optional_bool)
+ dest='build_benchmarks',
+ action=arguments.action.optional_false,
+ help="skip building Swift Benchmark Suite")
skip_test_group = parser.add_argument_group(
title="Skip testing specified targets")
skip_test_group.add_argument(
"--skip-test-ios",
+ dest='test_ios',
+ action=arguments.action.optional_false,
help="skip testing all iOS targets. Equivalent to specifying both "
- "--skip-test-ios-simulator and --skip-test-ios-host",
- action=arguments.action.optional_bool)
+ "--skip-test-ios-simulator and --skip-test-ios-host")
skip_test_group.add_argument(
"--skip-test-ios-simulator",
- help="skip testing iOS simulator targets",
- action=arguments.action.optional_bool)
+ dest='test_ios_simulator',
+ action=arguments.action.optional_false,
+ help="skip testing iOS simulator targets")
skip_test_group.add_argument(
"--skip-test-ios-32bit-simulator",
- help="skip testing iOS 32 bit simulator targets",
- action=arguments.action.optional_bool,
- default=False)
+ dest='test_ios_32bit_simulator',
+ action=arguments.action.optional_false,
+ help="skip testing iOS 32 bit simulator targets")
skip_test_group.add_argument(
"--skip-test-ios-host",
+ dest='test_ios_device',
+ action=arguments.action.optional_false,
help="skip testing iOS device targets on the host machine (the phone "
- "itself)",
- action=arguments.action.optional_bool)
+ "itself)")
skip_test_group.add_argument(
"--skip-test-tvos",
+ dest='test_tvos',
+ action=arguments.action.optional_false,
help="skip testing all tvOS targets. Equivalent to specifying both "
- "--skip-test-tvos-simulator and --skip-test-tvos-host",
- action=arguments.action.optional_bool)
+ "--skip-test-tvos-simulator and --skip-test-tvos-host")
skip_test_group.add_argument(
"--skip-test-tvos-simulator",
- help="skip testing tvOS simulator targets",
- action=arguments.action.optional_bool)
+ dest='test_tvos_simulator',
+ action=arguments.action.optional_false,
+ help="skip testing tvOS simulator targets")
skip_test_group.add_argument(
"--skip-test-tvos-host",
+ dest='test_tvos_device',
+ action=arguments.action.optional_false,
help="skip testing tvOS device targets on the host machine (the TV "
- "itself)",
- action=arguments.action.optional_bool)
+ "itself)")
skip_test_group.add_argument(
"--skip-test-watchos",
+ dest='test_watchos',
+ action=arguments.action.optional_false,
help="skip testing all tvOS targets. Equivalent to specifying both "
- "--skip-test-watchos-simulator and --skip-test-watchos-host",
- action=arguments.action.optional_bool)
+ "--skip-test-watchos-simulator and --skip-test-watchos-host")
skip_test_group.add_argument(
"--skip-test-watchos-simulator",
- help="skip testing watchOS simulator targets",
- action=arguments.action.optional_bool)
+ dest='test_watchos_simulator',
+ action=arguments.action.optional_false,
+ help="skip testing watchOS simulator targets")
skip_test_group.add_argument(
"--skip-test-watchos-host",
+ dest='test_watchos_device',
+ action=arguments.action.optional_false,
help="skip testing watchOS device targets on the host machine (the "
- "watch itself)",
- action=arguments.action.optional_bool)
+ "watch itself)")
skip_test_group.add_argument(
"--skip-test-android-host",
+ dest='test_android_device',
+ action=arguments.action.optional_false,
help="skip testing Android device targets on the host machine (the "
- "phone itself)",
- action=arguments.action.optional_bool)
+ "phone itself)")
parser.add_argument(
"-i", "--ios",
diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py
index 2ca8d8d..58b6c2e 100644
--- a/utils/build_swift/tests/expected_options.py
+++ b/utils/build_swift/tests/expected_options.py
@@ -41,14 +41,23 @@
'benchmark': False,
'benchmark_num_o_iterations': 3,
'benchmark_num_onone_iterations': 3,
+ 'build_android': False,
'build_args': [],
+ 'build_benchmarks': True,
+ 'build_cygwin': True,
'build_foundation': False,
+ 'build_freebsd': True,
+ 'build_ios': True,
+ 'build_ios_device': False,
+ 'build_ios_simulator': False,
'build_jobs': 4,
'build_libdispatch': False,
'build_libicu': False,
+ 'build_linux': True,
'build_llbuild': False,
'build_lldb': False,
'build_ninja': False,
+ 'build_osx': True,
'build_playgroundlogger': False,
'build_playgroundsupport': False,
'build_runtime_with_host_compiler': False,
@@ -60,7 +69,13 @@
'build_swift_static_stdlib': False,
'build_swift_stdlib_unittest_extra': False,
'build_swiftpm': False,
+ 'build_tvos': True,
+ 'build_tvos_device': False,
+ 'build_tvos_simulator': False,
'build_variant': 'Debug',
+ 'build_watchos': True,
+ 'build_watchos_device': False,
+ 'build_watchos_simulator': False,
'build_xctest': False,
'clang_compiler_version': None,
'clang_profile_instr_use': None,
@@ -116,36 +131,6 @@
'lto_type': None,
'show_sdks': False,
'skip_build': False,
- 'skip_build_android': True,
- 'skip_build_benchmarks': False,
- 'skip_build_cygwin': False,
- 'skip_build_freebsd': False,
- 'skip_build_ios': False,
- 'skip_build_ios_device': True,
- 'skip_build_ios_simulator': True,
- 'skip_build_linux': False,
- 'skip_build_osx': False,
- 'skip_build_tvos': False,
- 'skip_build_tvos_device': True,
- 'skip_build_tvos_simulator': True,
- 'skip_build_watchos': False,
- 'skip_build_watchos_device': True,
- 'skip_build_watchos_simulator': True,
- 'skip_test_android_host': True,
- 'skip_test_cygwin': True,
- 'skip_test_freebsd': True,
- 'skip_test_ios': True,
- 'skip_test_ios_32bit_simulator': False,
- 'skip_test_ios_host': True,
- 'skip_test_ios_simulator': True,
- 'skip_test_linux': True,
- 'skip_test_osx': True,
- 'skip_test_tvos': True,
- 'skip_test_tvos_host': True,
- 'skip_test_tvos_simulator': True,
- 'skip_test_watchos': True,
- 'skip_test_watchos_host': True,
- 'skip_test_watchos_simulator': True,
'stdlib_deployment_targets': [
'macosx-x86_64',
'iphonesimulator-i386',
@@ -168,8 +153,23 @@
'swift_user_visible_version': '4.1',
'symbols_package': None,
'test': None,
+ 'test_android_device': False,
+ 'test_cygwin': False,
+ 'test_freebsd': False,
+ 'test_ios': False,
+ 'test_ios_32bit_simulator': True,
+ 'test_ios_device': False,
+ 'test_ios_simulator': False,
+ 'test_linux': False,
'test_optimize_for_size': None,
'test_optimized': None,
+ 'test_osx': False,
+ 'test_tvos': False,
+ 'test_tvos_device': False,
+ 'test_tvos_simulator': False,
+ 'test_watchos': False,
+ 'test_watchos_device': False,
+ 'test_watchos_simulator': False,
'tvos': False,
'tvos_all': False,
'validation_test': None,
@@ -373,43 +373,43 @@
ToggleOption('--libicu', dest='build_libicu'),
ToggleOption('--long-test', dest='long_test'),
ToggleOption('--show-sdks', dest='show_sdks'),
- ToggleOption('--skip-build-android', dest='skip_build_android'),
- ToggleOption('--skip-build-benchmarks', dest='skip_build_benchmarks'),
- ToggleOption('--skip-build-cygwin', dest='skip_build_cygwin'),
- ToggleOption('--skip-build-freebsd', dest='skip_build_freebsd'),
- ToggleOption('--skip-build-ios', dest='skip_build_ios'),
- ToggleOption('--skip-build-ios-device', dest='skip_build_ios_device'),
+ ToggleOption('--skip-build-android', dest='build_android'),
+ ToggleOption('--skip-build-benchmarks', dest='build_benchmarks'),
+ ToggleOption('--skip-build-cygwin', dest='build_cygwin'),
+ ToggleOption('--skip-build-freebsd', dest='build_freebsd'),
+ ToggleOption('--skip-build-ios', dest='build_ios'),
+ ToggleOption('--skip-build-ios-device', dest='build_ios_device'),
ToggleOption('--skip-build-ios-simulator',
- dest='skip_build_ios_simulator'),
- ToggleOption('--skip-build-linux', dest='skip_build_linux'),
- ToggleOption('--skip-build-osx', dest='skip_build_osx'),
- ToggleOption('--skip-build-tvos', dest='skip_build_tvos'),
- ToggleOption('--skip-build-tvos-device', dest='skip_build_tvos_device'),
+ dest='build_ios_simulator'),
+ ToggleOption('--skip-build-linux', dest='build_linux'),
+ ToggleOption('--skip-build-osx', dest='build_osx'),
+ ToggleOption('--skip-build-tvos', dest='build_tvos'),
+ ToggleOption('--skip-build-tvos-device', dest='build_tvos_device'),
ToggleOption('--skip-build-tvos-simulator',
- dest='skip_build_tvos_simulator'),
- ToggleOption('--skip-build-watchos', dest='skip_build_watchos'),
+ dest='build_tvos_simulator'),
+ ToggleOption('--skip-build-watchos', dest='build_watchos'),
ToggleOption('--skip-build-watchos-device',
- dest='skip_build_watchos_device'),
+ dest='build_watchos_device'),
ToggleOption('--skip-build-watchos-simulator',
- dest='skip_build_watchos_simulator'),
- ToggleOption('--skip-test-android-host', dest='skip_test_android_host'),
- ToggleOption('--skip-test-cygwin', dest='skip_test_cygwin'),
- ToggleOption('--skip-test-freebsd', dest='skip_test_freebsd'),
- ToggleOption('--skip-test-ios', dest='skip_test_ios'),
+ dest='build_watchos_simulator'),
+ ToggleOption('--skip-test-android-host', dest='test_android_device'),
+ ToggleOption('--skip-test-cygwin', dest='test_cygwin'),
+ ToggleOption('--skip-test-freebsd', dest='test_freebsd'),
+ ToggleOption('--skip-test-ios', dest='test_ios'),
ToggleOption('--skip-test-ios-32bit-simulator',
- dest='skip_test_ios_32bit_simulator'),
- ToggleOption('--skip-test-ios-host', dest='skip_test_ios_host'),
- ToggleOption('--skip-test-ios-simulator', dest='skip_test_ios_simulator'),
- ToggleOption('--skip-test-linux', dest='skip_test_linux'),
- ToggleOption('--skip-test-osx', dest='skip_test_osx'),
- ToggleOption('--skip-test-tvos', dest='skip_test_tvos'),
- ToggleOption('--skip-test-tvos-host', dest='skip_test_tvos_host'),
+ dest='test_ios_32bit_simulator'),
+ ToggleOption('--skip-test-ios-host', dest='test_ios_device'),
+ ToggleOption('--skip-test-ios-simulator', dest='test_ios_simulator'),
+ ToggleOption('--skip-test-linux', dest='test_linux'),
+ ToggleOption('--skip-test-osx', dest='test_osx'),
+ ToggleOption('--skip-test-tvos', dest='test_tvos'),
+ ToggleOption('--skip-test-tvos-host', dest='test_tvos_device'),
ToggleOption('--skip-test-tvos-simulator',
- dest='skip_test_tvos_simulator'),
- ToggleOption('--skip-test-watchos', dest='skip_test_watchos'),
- ToggleOption('--skip-test-watchos-host', dest='skip_test_watchos_host'),
+ dest='test_tvos_simulator'),
+ ToggleOption('--skip-test-watchos', dest='test_watchos'),
+ ToggleOption('--skip-test-watchos-host', dest='test_watchos_device'),
ToggleOption('--skip-test-watchos-simulator',
- dest='skip_test_watchos_simulator'),
+ dest='test_watchos_simulator'),
ToggleOption('--test', dest='test'),
ToggleOption('--test-optimize-for-size', dest='test_optimize_for_size'),
ToggleOption('--test-optimized', dest='test_optimized'),
diff --git a/utils/build_swift/tests/test_driver_arguments.py b/utils/build_swift/tests/test_driver_arguments.py
index 8fdb3ba..f5c9b94 100644
--- a/utils/build_swift/tests/test_driver_arguments.py
+++ b/utils/build_swift/tests/test_driver_arguments.py
@@ -170,6 +170,8 @@
self.parse_args([option.option_string])
self.assertNotEmpty(output)
+ return test
+
@classmethod
def _generate_int_option_test(cls, option):
def test(self):
@@ -416,16 +418,16 @@
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-build'])
- self.assertTrue(args.skip_build_benchmarks)
+ self.assertFalse(args.build_benchmarks)
- self.assertTrue(args.skip_build_linux)
- self.assertTrue(args.skip_build_android)
- self.assertTrue(args.skip_build_freebsd)
- self.assertTrue(args.skip_build_cygwin)
- self.assertTrue(args.skip_build_osx)
- self.assertTrue(args.skip_build_ios)
- self.assertTrue(args.skip_build_tvos)
- self.assertTrue(args.skip_build_watchos)
+ self.assertFalse(args.build_linux)
+ self.assertFalse(args.build_android)
+ self.assertFalse(args.build_freebsd)
+ self.assertFalse(args.build_cygwin)
+ self.assertFalse(args.build_osx)
+ self.assertFalse(args.build_ios)
+ self.assertFalse(args.build_tvos)
+ self.assertFalse(args.build_watchos)
self.assertFalse(args.build_foundation)
self.assertFalse(args.build_libdispatch)
@@ -440,32 +442,32 @@
def test_implied_defaults_skip_build_ios(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-build-ios'])
- self.assertTrue(args.skip_build_ios_device)
- self.assertTrue(args.skip_build_ios_simulator)
+ self.assertFalse(args.build_ios_device)
+ self.assertFalse(args.build_ios_simulator)
# Also implies that the tests should be skipped
- self.assertTrue(args.skip_test_ios_host)
- self.assertTrue(args.skip_test_ios_simulator)
+ self.assertFalse(args.test_ios_device)
+ self.assertFalse(args.test_ios_simulator)
def test_implied_defaults_skip_build_tvos(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-build-tvos'])
- self.assertTrue(args.skip_build_tvos_device)
- self.assertTrue(args.skip_build_tvos_simulator)
+ self.assertFalse(args.build_tvos_device)
+ self.assertFalse(args.build_tvos_simulator)
# Also implies that the tests should be skipped
- self.assertTrue(args.skip_test_tvos_host)
- self.assertTrue(args.skip_test_tvos_simulator)
+ self.assertFalse(args.test_tvos_device)
+ self.assertFalse(args.test_tvos_simulator)
def test_implied_defaults_skip_build_watchos(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-build-watchos'])
- self.assertTrue(args.skip_build_watchos_device)
- self.assertTrue(args.skip_build_watchos_simulator)
+ self.assertFalse(args.build_watchos_device)
+ self.assertFalse(args.build_watchos_simulator)
# Also implies that the tests should be skipped
- self.assertTrue(args.skip_test_watchos_host)
- self.assertTrue(args.skip_test_watchos_simulator)
+ self.assertFalse(args.test_watchos_device)
+ self.assertFalse(args.test_watchos_simulator)
def test_implied_defaults_validation_test(self):
with self.assertNotRaises(ParserError):
@@ -490,48 +492,48 @@
'--long-test', '0',
])
- self.assertTrue(args.skip_test_linux)
- self.assertTrue(args.skip_test_freebsd)
- self.assertTrue(args.skip_test_cygwin)
- self.assertTrue(args.skip_test_osx)
- self.assertTrue(args.skip_test_ios)
- self.assertTrue(args.skip_test_tvos)
- self.assertTrue(args.skip_test_watchos)
+ self.assertFalse(args.test_linux)
+ self.assertFalse(args.test_freebsd)
+ self.assertFalse(args.test_cygwin)
+ self.assertFalse(args.test_osx)
+ self.assertFalse(args.test_ios)
+ self.assertFalse(args.test_tvos)
+ self.assertFalse(args.test_watchos)
def test_implied_defaults_skip_test_ios(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-test-ios'])
- self.assertTrue(args.skip_test_ios_host)
- self.assertTrue(args.skip_test_ios_simulator)
+ self.assertFalse(args.test_ios_device)
+ self.assertFalse(args.test_ios_simulator)
def test_implied_defaults_skip_test_tvos(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-test-tvos'])
- self.assertTrue(args.skip_test_tvos_host)
- self.assertTrue(args.skip_test_tvos_simulator)
+ self.assertFalse(args.test_tvos_device)
+ self.assertFalse(args.test_tvos_simulator)
def test_implied_defaults_skip_test_watchos(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-test-watchos'])
- self.assertTrue(args.skip_test_watchos_host)
- self.assertTrue(args.skip_test_watchos_simulator)
+ self.assertFalse(args.test_watchos_device)
+ self.assertFalse(args.test_watchos_simulator)
def test_implied_defaults_skip_build_android(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--android', '0'])
- self.assertTrue(args.skip_test_android_host)
+ self.assertFalse(args.test_android_device)
with self.assertNotRaises(ParserError):
args = self.parse_args(['--skip-build-android'])
- self.assertTrue(args.skip_test_android_host)
+ self.assertFalse(args.test_android_device)
def test_implied_defaults_host_test(self):
with self.assertNotRaises(ParserError):
args = self.parse_args(['--host-test', '0'])
- self.assertTrue(args.skip_test_ios_host)
- self.assertTrue(args.skip_test_tvos_host)
- self.assertTrue(args.skip_test_watchos_host)
- self.assertTrue(args.skip_test_android_host)
+ self.assertFalse(args.test_ios_device)
+ self.assertFalse(args.test_tvos_device)
+ self.assertFalse(args.test_watchos_device)
+ self.assertFalse(args.test_android_device)
if __name__ == '__main__':
diff --git a/utils/jobstats/jobstats.py b/utils/jobstats/jobstats.py
index 947a5e8..022ada9 100644
--- a/utils/jobstats/jobstats.py
+++ b/utils/jobstats/jobstats.py
@@ -61,11 +61,22 @@
assert(self.is_driver_job())
return self.driver_jobs_ran() + self.driver_jobs_skipped()
- def merged_with(self, other):
+ def merged_with(self, other, merge_by="sum"):
"""Return a new JobStats, holding the merger of self and other"""
merged_stats = {}
+ ops = {"sum": lambda a, b: a + b,
+ # Because 0 is also a sentinel on counters we do a modified
+ # "nonzero-min" here. Not ideal but best we can do.
+ "min": lambda a, b: (min(a, b)
+ if a != 0 and b != 0
+ else max(a, b)),
+ "max": lambda a, b: max(a, b)}
+ op = ops[merge_by]
for k, v in self.stats.items() + other.stats.items():
- merged_stats[k] = v + merged_stats.get(k, 0.0)
+ if k in merged_stats:
+ merged_stats[k] = op(v, merged_stats[k])
+ else:
+ merged_stats[k] = v
merged_kind = self.jobkind
if other.jobkind != merged_kind:
merged_kind = "<merged>"
@@ -160,7 +171,7 @@
def load_stats_dir(path, select_module=[], select_stat=[],
- exclude_timers=False):
+ exclude_timers=False, **kwargs):
"""Loads all stats-files found in path into a list of JobStats objects"""
jobstats = []
auxpat = (r"(?P<module>[^-]+)-(?P<input>[^-]+)-(?P<triple>[^-]+)" +
@@ -213,7 +224,8 @@
return jobstats
-def merge_all_jobstats(jobstats, select_module=[], group_by_module=False):
+def merge_all_jobstats(jobstats, select_module=[], group_by_module=False,
+ merge_by="sum", **kwargs):
"""Does a pairwise merge of the elements of list of jobs"""
m = None
if len(select_module) > 0:
@@ -221,15 +233,16 @@
if group_by_module:
def keyfunc(j):
return j.module
+ jobstats = list(jobstats)
jobstats.sort(key=keyfunc)
prefixed = []
for mod, group in itertools.groupby(jobstats, keyfunc):
- groupmerge = merge_all_jobstats(group)
+ groupmerge = merge_all_jobstats(group, merge_by=merge_by)
prefixed.append(groupmerge.prefixed_by(mod))
jobstats = prefixed
for j in jobstats:
if m is None:
m = j
else:
- m = m.merged_with(j)
+ m = m.merged_with(j, merge_by=merge_by)
return m
diff --git a/utils/process-stats-dir.py b/utils/process-stats-dir.py
index cbef76e..c9a3425 100755
--- a/utils/process-stats-dir.py
+++ b/utils/process-stats-dir.py
@@ -36,9 +36,6 @@
def load_paired_stats_dirs(args):
assert(len(args.remainder) == 2)
paired_stats = []
- mod = args.select_module
- stat = args.select_stat
- xt = args.exclude_timers
(old, new) = args.remainder
for p in sorted(os.listdir(old)):
full_old = os.path.join(old, p)
@@ -46,14 +43,8 @@
if not (os.path.exists(full_old) and os.path.isdir(full_old) and
os.path.exists(full_new) and os.path.isdir(full_new)):
continue
- old_stats = load_stats_dir(full_old,
- select_module=mod,
- select_stat=stat,
- exclude_timers=xt)
- new_stats = load_stats_dir(full_new,
- select_module=mod,
- select_stat=stat,
- exclude_timers=xt)
+ old_stats = load_stats_dir(full_old, **vars(args))
+ new_stats = load_stats_dir(full_new, **vars(args))
if len(old_stats) == 0 or len(new_stats) == 0:
continue
paired_stats.append((p, (old_stats, new_stats)))
@@ -63,22 +54,14 @@
def write_catapult_trace(args):
allstats = []
for path in args.remainder:
- allstats += load_stats_dir(path,
- select_module=args.select_module,
- select_stat=args.select_stat,
- exclude_timers=args.exclude_timers)
+ allstats += load_stats_dir(path, **vars(args))
json.dump([s.to_catapult_trace_obj() for s in allstats], args.output)
def write_lnt_values(args):
for d in args.remainder:
- stats = load_stats_dir(d,
- select_module=args.select_module,
- select_stat=args.select_stat,
- exclude_timers=args.exclude_timers)
- merged = merge_all_jobstats(stats,
- select_module=args.select_module,
- group_by_module=args.group_by_module)
+ stats = load_stats_dir(d, **vars(args))
+ merged = merge_all_jobstats(stats, **vars(args))
j = merged.to_lnt_test_obj(args)
if args.lnt_submit is None:
json.dump(j, args.output, indent=4)
@@ -107,16 +90,11 @@
out = csv.DictWriter(args.output, fieldnames, dialect='excel-tab')
out.writeheader()
- sel = args.select_module
for (name, (oldstats, newstats)) in load_paired_stats_dirs(args):
olddriver = merge_all_jobstats((x for x in oldstats
- if x.is_driver_job()),
- select_module=sel,
- group_by_module=args.group_by_module)
+ if x.is_driver_job()), **vars(args))
newdriver = merge_all_jobstats((x for x in newstats
- if x.is_driver_job()),
- select_module=sel,
- group_by_module=args.group_by_module)
+ if x.is_driver_job()), **vars(args))
if olddriver is None or newdriver is None:
continue
oldpct = olddriver.incrementality_percentage()
@@ -137,10 +115,7 @@
out.writeheader()
for path in args.remainder:
- stats = load_stats_dir(path,
- select_module=args.select_module,
- select_stat=args.select_stat,
- exclude_timers=args.exclude_timers)
+ stats = load_stats_dir(path, **vars(args))
for s in stats:
if s.is_driver_job():
pct = s.incrementality_percentage()
@@ -223,16 +198,12 @@
with open(args.set_csv_baseline, "wb") as f:
out = csv.DictWriter(f, fieldnames, dialect='excel-tab',
quoting=csv.QUOTE_NONNUMERIC)
- mod = args.select_module
- stat = args.select_stat
- xt = args.exclude_timers
m = merge_all_jobstats((s for d in args.remainder
- for s in load_stats_dir(d,
- select_module=mod,
- select_stat=stat,
- exclude_timers=xt)),
- select_module=mod,
- group_by_module=args.group_by_module)
+ for s in load_stats_dir(d, **vars(args))),
+ **vars(args))
+ if m is None:
+ print "no stats found"
+ return 1
changed = 0
newepoch = int(time.time())
for name in sorted(m.stats.keys()):
@@ -303,16 +274,9 @@
def compare_to_csv_baseline(args):
old_stats = read_stats_dict_from_csv(args.compare_to_csv_baseline)
- mod = args.select_module
- stat = args.select_stat
- xt = args.exclude_timers
m = merge_all_jobstats((s for d in args.remainder
- for s in load_stats_dir(d,
- select_module=mod,
- select_stat=stat,
- exclude_timers=xt)),
- select_module=mod,
- group_by_module=args.group_by_module)
+ for s in load_stats_dir(d, **vars(args))),
+ **vars(args))
old_stats = dict((k, v) for (k, (_, v)) in old_stats.items())
new_stats = m.stats
@@ -325,20 +289,10 @@
raise ValueError("Expected exactly 2 stats-dirs")
(old, new) = args.remainder
- old_stats = merge_all_jobstats(
- load_stats_dir(old,
- select_module=args.select_module,
- select_stat=args.select_stat,
- exclude_timers=args.exclude_timers),
- select_module=args.select_module,
- group_by_module=args.group_by_module)
- new_stats = merge_all_jobstats(
- load_stats_dir(new,
- select_module=args.select_module,
- select_stat=args.select_stat,
- exclude_timers=args.exclude_timers),
- select_module=args.select_module,
- group_by_module=args.group_by_module)
+ old_stats = merge_all_jobstats(load_stats_dir(old, **vars(args)),
+ **vars(args))
+ new_stats = merge_all_jobstats(load_stats_dir(new, **vars(args)),
+ **vars(args))
return write_comparison(args, old_stats.stats, new_stats.stats)
@@ -395,6 +349,10 @@
default=False,
action="store_true",
help="Sort comparison results in descending order")
+ parser.add_argument("--merge-by",
+ default="sum",
+ type=str,
+ help="Merge identical metrics by (sum|min|max)")
parser.add_argument("--markdown",
default=False,
action="store_true",
diff --git a/utils/swift_build_support/swift_build_support/arguments.py b/utils/swift_build_support/swift_build_support/arguments.py
index 436ebb1..d55cfbe 100644
--- a/utils/swift_build_support/swift_build_support/arguments.py
+++ b/utils/swift_build_support/swift_build_support/arguments.py
@@ -190,6 +190,7 @@
option_strings,
dest,
default=False,
+ const=True,
metavar="BOOL",
help=None):
super(_OptionalBoolAction, self).__init__(
@@ -200,10 +201,40 @@
nargs="?",
type=type.bool,
help=help,
- const=True)
+ const=const)
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
_register(action, 'optional_bool', _OptionalBoolAction)
+
+
+class _OptionalTrueAction(_OptionalBoolAction):
+ """Action that defaults to False when absent and to True when parsed with
+ the option to override the value by passing a bool-like value as an
+ argument.
+ """
+
+ def __init__(self, *args, **kwargs):
+ kwargs['const'] = True
+ kwargs['default'] = kwargs.pop('default', False)
+ super(_OptionalTrueAction, self).__init__(*args, **kwargs)
+
+
+_register(action, 'optional_true', _OptionalTrueAction)
+
+
+class _OptionalFalseAction(_OptionalBoolAction):
+ """Action that defaults to True when absent and to False when parsed with
+ the option to override the value by passing a bool-like value as an
+ argument.
+ """
+
+ def __init__(self, *args, **kwargs):
+ kwargs['const'] = False
+ kwargs['default'] = kwargs.pop('default', True)
+ super(_OptionalFalseAction, self).__init__(*args, **kwargs)
+
+
+_register(action, 'optional_false', _OptionalFalseAction)
diff --git a/validation-test/Evolution/test_function_change_transparent_body.swift b/validation-test/Evolution/test_function_change_transparent_body.swift
index 577d875..10f8113 100644
--- a/validation-test/Evolution/test_function_change_transparent_body.swift
+++ b/validation-test/Evolution/test_function_change_transparent_body.swift
@@ -1,6 +1,9 @@
-// RUN: %target-resilience-test
+// RUN: %target-resilience-test-wmo
// REQUIRES: executable_test
+// FIXME: shouldn't need -whole-module-optimization here; we need to fix the
+// frontend to merge serialized SIL functions from different translation units
+
import StdlibUnittest
import function_change_transparent_body