Merge pull request #13613 from aschwaighofer/fix_unowned_refcount_insertion
When inserting retain/releases for sil_unowned types use the right in…
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 112b5d6..497cfb0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -207,6 +207,10 @@
"Whether to enable CrashReporter integration"
FALSE)
+option(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
+ "Enable the Swift stable ABI's class marker bit"
+ FALSE)
+
set(SWIFT_DARWIN_XCRUN_TOOLCHAIN "XcodeDefault" CACHE STRING
"The name of the toolchain to pass to 'xcrun'")
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index 78c574e..fefc6bb 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -175,9 +175,13 @@
static ::= 'Z'
curry-thunk ::= 'Tc'
+ label-list ::= empty-list // represents complete absence of parameter labels
+ label-list ::= ('_' | identifier)* // '_' is inserted as placeholder for empty label,
+ // since the number of labels should match the number of parameters
+
// The leading type is the function type
- entity-spec ::= type file-discriminator? 'fC' // allocating constructor
- entity-spec ::= type file-discriminator? 'fc' // non-allocating constructor
+ entity-spec ::= label-list type file-discriminator? 'fC' // allocating constructor
+ entity-spec ::= label-list type file-discriminator? 'fc' // non-allocating constructor
entity-spec ::= type 'fU' INDEX // explicit anonymous closure expression
entity-spec ::= type 'fu' INDEX // implicit anonymous closure
entity-spec ::= 'fA' INDEX // default argument N+1 generator
@@ -189,11 +193,11 @@
entity-spec ::= 'Tv' NATURAL // outlined global variable (from context function)
entity-spec ::= 'Te' bridge-spec // outlined objective c method call
- entity-spec ::= decl-name function-signature generic-signature? 'F' // function
- entity-spec ::= type file-discriminator? 'i' ACCESSOR // subscript
- entity-spec ::= decl-name type 'v' ACCESSOR // variable
- entity-spec ::= decl-name type 'fp' // generic type parameter
- entity-spec ::= decl-name type 'fo' // enum element (currently not used)
+ entity-spec ::= decl-name label-list function-signature generic-signature? 'F' // function
+ entity-spec ::= label-list type file-discriminator? 'i' ACCESSOR // subscript
+ entity-spec ::= decl-name label-list? type 'v' ACCESSOR // variable
+ entity-spec ::= decl-name type 'fp' // generic type parameter
+ entity-spec ::= decl-name type 'fo' // enum element (currently not used)
ACCESSOR ::= 'm' // materializeForSet
ACCESSOR ::= 's' // setter
@@ -351,7 +355,8 @@
function-signature ::= params-type params-type throws? // results and parameters
params-type := type 'z'? 'h'? // tuple in case of multiple parameters or a single parameter with a single tuple type
- // with optional inout convention, shared convention
+ // with optional inout convention, shared convention. parameters don't have labels,
+ // they are mangled separately as part of the entity.
params-type := empty-list // shortcut for no parameters
throws ::= 'K' // 'throws' annotation on function types
diff --git a/docs/Runtime.md b/docs/Runtime.md
index a7a8899..10347ba 100644
--- a/docs/Runtime.md
+++ b/docs/Runtime.md
@@ -314,8 +314,9 @@
000000000001e620 T _swift_allocateGenericValueMetadata
0000000000022be0 T _swift_initClassMetadata_UniversalStrategy
000000000001c100 T _swift_initEnumMetadataMultiPayload
-000000000001bd60 T _swift_initEnumValueWitnessTableSinglePayload
-0000000000022a20 T _swift_initStructMetadata_UniversalStrategy
+000000000001bd60 T _swift_initEnumMetadataSingleCase
+000000000001bd60 T _swift_initEnumMetadataSinglePayload
+0000000000022a20 T _swift_initStructMetadata
0000000000024230 T _swift_initializeSuperclass
0000000000028b60 T _swift_instantiateObjCClass
```
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index fdd3a02..a5f9f2b 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -86,12 +86,16 @@
}
/// Swift class flags.
+/// These flags are valid only when isTypeMetadata().
+/// When !isTypeMetadata() these flags will collide with other Swift ABIs.
enum class ClassFlags : uint32_t {
- /// Is this a Swift 1 class?
- IsSwift1 = 0x1,
+ /// Is this a Swift class from the Darwin pre-stable ABI?
+ /// This bit is clear in stable ABI Swift classes.
+ /// The Objective-C runtime also reads this bit.
+ IsSwiftPreStableABI = 0x1,
- /// Does this class use Swift 1.0 refcounting?
- UsesSwift1Refcounting = 0x2,
+ /// Does this class use Swift refcounting?
+ UsesSwiftRefcounting = 0x2,
/// Has this class a custom name, specified with the @objc attribute?
HasCustomObjCName = 0x4
@@ -747,6 +751,62 @@
return uintptr_t(flags) & uintptr_t(ExclusivityFlags::WarningOnly);
}
+/// Flags for struct layout.
+enum class StructLayoutFlags : uintptr_t {
+ /// Reserve space for 256 layout algorithms.
+ AlgorithmMask = 0xff,
+
+ /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
+ Swift5Algorithm = 0x00,
+
+ /// Is the value-witness table mutable in place, or does layout need to
+ /// clone it?
+ IsVWTMutable = 0x100,
+};
+static inline StructLayoutFlags operator|(StructLayoutFlags lhs,
+ StructLayoutFlags rhs) {
+ return StructLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
+}
+static inline StructLayoutFlags &operator|=(StructLayoutFlags &lhs,
+ StructLayoutFlags rhs) {
+ return (lhs = (lhs | rhs));
+}
+static inline StructLayoutFlags getLayoutAlgorithm(StructLayoutFlags flags) {
+ return StructLayoutFlags(uintptr_t(flags)
+ & uintptr_t(StructLayoutFlags::AlgorithmMask));
+}
+static inline bool isValueWitnessTableMutable(StructLayoutFlags flags) {
+ return uintptr_t(flags) & uintptr_t(StructLayoutFlags::IsVWTMutable);
+}
+
+/// Flags for enum layout.
+enum class EnumLayoutFlags : uintptr_t {
+ /// Reserve space for 256 layout algorithms.
+ AlgorithmMask = 0xff,
+
+ /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
+ Swift5Algorithm = 0x00,
+
+ /// Is the value-witness table mutable in place, or does layout need to
+ /// clone it?
+ IsVWTMutable = 0x100,
+};
+static inline EnumLayoutFlags operator|(EnumLayoutFlags lhs,
+ EnumLayoutFlags rhs) {
+ return EnumLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
+}
+static inline EnumLayoutFlags &operator|=(EnumLayoutFlags &lhs,
+ EnumLayoutFlags rhs) {
+ return (lhs = (lhs | rhs));
+}
+static inline EnumLayoutFlags getLayoutAlgorithm(EnumLayoutFlags flags) {
+ return EnumLayoutFlags(uintptr_t(flags)
+ & uintptr_t(EnumLayoutFlags::AlgorithmMask));
+}
+static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) {
+ return uintptr_t(flags) & uintptr_t(EnumLayoutFlags::IsVWTMutable);
+}
+
} // end namespace swift
#endif /* SWIFT_ABI_METADATAVALUES_H */
diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h
index e611b58..57a60d6 100644
--- a/include/swift/AST/ASTContext.h
+++ b/include/swift/AST/ASTContext.h
@@ -482,8 +482,8 @@
FuncDecl *getEqualIntDecl() const;
/// Retrieve the declaration of
- /// Swift._mixForSynthesizedHashValue (Int, Int) -> Int.
- FuncDecl *getMixForSynthesizedHashValueDecl() const;
+ /// Swift._combineHashValues(Int, Int) -> Int.
+ FuncDecl *getCombineHashValuesDecl() const;
/// Retrieve the declaration of Swift._mixInt(Int) -> Int.
FuncDecl *getMixIntDecl() const;
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index 58330b0..fcef79d 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -287,8 +287,17 @@
SWIFT_INLINE_BITFIELD_EMPTY(ImplicitConversionExpr, Expr);
- SWIFT_INLINE_BITFIELD(TupleShuffleExpr, ImplicitConversionExpr, 2,
- TypeImpact : 2
+ SWIFT_INLINE_BITFIELD_FULL(TupleShuffleExpr, ImplicitConversionExpr, 2+16+16+16,
+ TypeImpact : 2,
+ : NumPadBits,
+ NumCallerDefaultArgs : 16,
+ /// This contains an entry for each element in the Expr type. Each element
+ /// specifies which index from the SubExpr that the destination element gets.
+ /// If the element value is DefaultInitialize, then the destination value
+ /// gets the default initializer for that tuple element value.
+ NumElementMappings : 16,
+ /// The arguments that are packed into the variadic element.
+ NumVariadicArgs : 16
);
SWIFT_INLINE_BITFIELD(InOutToPointerExpr, ImplicitConversionExpr, 1,
@@ -299,6 +308,21 @@
IsNonAccessing : 1
);
+ SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32,
+ : NumPadBits,
+ NumConformances : 32
+ );
+
+ SWIFT_INLINE_BITFIELD_FULL(UnresolvedSpecializeExpr, Expr, 32,
+ : NumPadBits,
+ NumUnresolvedParams : 32
+ );
+
+ SWIFT_INLINE_BITFIELD_FULL(CaptureListExpr, Expr, 32,
+ : NumPadBits,
+ NumCaptures : 32
+ );
+
SWIFT_INLINE_BITFIELD(ApplyExpr, Expr, 1+1,
ThrowsIsSet : 1,
Throws : 1
@@ -371,6 +395,9 @@
SWIFT_INLINE_BITS(ParenExpr);
SWIFT_INLINE_BITS(SequenceExpr);
SWIFT_INLINE_BITS(CollectionExpr);
+ SWIFT_INLINE_BITS(ErasureExpr);
+ SWIFT_INLINE_BITS(UnresolvedSpecializeExpr);
+ SWIFT_INLINE_BITS(CaptureListExpr);
} Bits;
private:
@@ -2824,7 +2851,20 @@
/// If hasScalarSource() is true, the subexpression should be treated
/// as if it were implicitly injected into a single-element tuple
/// type. Otherwise, the subexpression is known to have a tuple type.
-class TupleShuffleExpr : public ImplicitConversionExpr {
+class TupleShuffleExpr final : public ImplicitConversionExpr,
+ private llvm::TrailingObjects<TupleShuffleExpr, Expr *, int, unsigned> {
+ friend TrailingObjects;
+
+ size_t numTrailingObjects(OverloadToken<Expr *>) const {
+ return Bits.TupleShuffleExpr.NumCallerDefaultArgs;
+ }
+ size_t numTrailingObjects(OverloadToken<int>) const {
+ return Bits.TupleShuffleExpr.NumElementMappings;
+ }
+ size_t numTrailingObjects(OverloadToken<unsigned>) const {
+ return Bits.TupleShuffleExpr.NumVariadicArgs;
+ }
+
public:
enum : int {
/// The element mapping value indicating that a field of the destination
@@ -2859,12 +2899,6 @@
};
private:
- /// This contains an entry for each element in the Expr type. Each element
- /// specifies which index from the SubExpr that the destination element gets.
- /// If the element value is DefaultInitialize, then the destination value
- /// gets the default initializer for that tuple element value.
- ArrayRef<int> ElementMapping;
-
/// If we're doing a varargs shuffle, this is the array type to build.
Type VarargsArrayTy;
@@ -2872,28 +2906,41 @@
/// declaration.
ConcreteDeclRef DefaultArgsOwner;
- /// The arguments that are packed into the variadic element.
- ArrayRef<unsigned> VariadicArgs;
-
- MutableArrayRef<Expr *> CallerDefaultArgs;
-
-public:
- TupleShuffleExpr(Expr *subExpr, ArrayRef<int> elementMapping,
+ TupleShuffleExpr(Expr *subExpr, ArrayRef<int> elementMapping,
TypeImpact typeImpact,
ConcreteDeclRef defaultArgsOwner,
ArrayRef<unsigned> VariadicArgs,
Type VarargsArrayTy,
- MutableArrayRef<Expr *> CallerDefaultArgs,
+ ArrayRef<Expr *> CallerDefaultArgs,
Type ty)
: ImplicitConversionExpr(ExprKind::TupleShuffle, subExpr, ty),
- ElementMapping(elementMapping), VarargsArrayTy(VarargsArrayTy),
- DefaultArgsOwner(defaultArgsOwner), VariadicArgs(VariadicArgs),
- CallerDefaultArgs(CallerDefaultArgs)
- {
+ VarargsArrayTy(VarargsArrayTy), DefaultArgsOwner(defaultArgsOwner) {
Bits.TupleShuffleExpr.TypeImpact = typeImpact;
+ Bits.TupleShuffleExpr.NumCallerDefaultArgs = CallerDefaultArgs.size();
+ Bits.TupleShuffleExpr.NumElementMappings = elementMapping.size();
+ Bits.TupleShuffleExpr.NumVariadicArgs = VariadicArgs.size();
+ std::uninitialized_copy(CallerDefaultArgs.begin(), CallerDefaultArgs.end(),
+ getTrailingObjects<Expr*>());
+ std::uninitialized_copy(elementMapping.begin(), elementMapping.end(),
+ getTrailingObjects<int>());
+ std::uninitialized_copy(VariadicArgs.begin(), VariadicArgs.end(),
+ getTrailingObjects<unsigned>());
}
- ArrayRef<int> getElementMapping() const { return ElementMapping; }
+public:
+ static TupleShuffleExpr *create(ASTContext &ctx, Expr *subExpr,
+ ArrayRef<int> elementMapping,
+ TypeImpact typeImpact,
+ ConcreteDeclRef defaultArgsOwner,
+ ArrayRef<unsigned> VariadicArgs,
+ Type VarargsArrayTy,
+ ArrayRef<Expr *> CallerDefaultArgs,
+ Type ty);
+
+ ArrayRef<int> getElementMapping() const {
+ return {getTrailingObjects<int>(),
+ Bits.TupleShuffleExpr.NumElementMappings};
+ }
/// What is the type impact of this shuffle?
TypeImpact getTypeImpact() const {
@@ -2917,16 +2964,25 @@
}
/// Retrieve the argument indices for the variadic arguments.
- ArrayRef<unsigned> getVariadicArgs() const { return VariadicArgs; }
+ ArrayRef<unsigned> getVariadicArgs() const {
+ return {getTrailingObjects<unsigned>(),
+ Bits.TupleShuffleExpr.NumVariadicArgs};
+ }
/// Retrieve the owner of the default arguments.
ConcreteDeclRef getDefaultArgsOwner() const { return DefaultArgsOwner; }
/// Retrieve the caller-defaulted arguments.
- ArrayRef<Expr *> getCallerDefaultArgs() const { return CallerDefaultArgs; }
+ ArrayRef<Expr *> getCallerDefaultArgs() const {
+ return {getTrailingObjects<Expr*>(),
+ Bits.TupleShuffleExpr.NumCallerDefaultArgs};
+ }
/// Retrieve the caller-defaulted arguments.
- MutableArrayRef<Expr *> getCallerDefaultArgs() { return CallerDefaultArgs; }
+ MutableArrayRef<Expr *> getCallerDefaultArgs() {
+ return {getTrailingObjects<Expr*>(),
+ Bits.TupleShuffleExpr.NumCallerDefaultArgs};
+ }
static bool classof(const Expr *E) {
return E->getKind() == ExprKind::TupleShuffle;
@@ -3090,14 +3146,21 @@
///
/// "Appropriate kind" means e.g. a concrete/existential metatype if the
/// result is an existential metatype.
-class ErasureExpr : public ImplicitConversionExpr {
- ArrayRef<ProtocolConformanceRef> Conformances;
+class ErasureExpr final : public ImplicitConversionExpr,
+ private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef> {
+ friend TrailingObjects;
-public:
ErasureExpr(Expr *subExpr, Type type,
ArrayRef<ProtocolConformanceRef> conformances)
- : ImplicitConversionExpr(ExprKind::Erasure, subExpr, type),
- Conformances(conformances) {}
+ : ImplicitConversionExpr(ExprKind::Erasure, subExpr, type) {
+ Bits.ErasureExpr.NumConformances = conformances.size();
+ std::uninitialized_copy(conformances.begin(), conformances.end(),
+ getTrailingObjects<ProtocolConformanceRef>());
+ }
+
+public:
+ static ErasureExpr *create(ASTContext &ctx, Expr *subExpr, Type type,
+ ArrayRef<ProtocolConformanceRef> conformances);
/// \brief Retrieve the mapping specifying how the type of the subexpression
/// maps to the resulting existential type. If the resulting existential
@@ -3110,7 +3173,8 @@
/// type is either an archetype or an existential type that conforms to
/// that corresponding protocol).
ArrayRef<ProtocolConformanceRef> getConformances() const {
- return Conformances;
+ return {getTrailingObjects<ProtocolConformanceRef>(),
+ Bits.ErasureExpr.NumConformances };
}
static bool classof(const Expr *E) {
@@ -3189,28 +3253,43 @@
/// UnresolvedSpecializeExpr - Represents an explicit specialization using
/// a type parameter list (e.g. "Vector<Int>") that has not been resolved.
-class UnresolvedSpecializeExpr : public Expr {
+class UnresolvedSpecializeExpr final : public Expr,
+ private llvm::TrailingObjects<UnresolvedSpecializeExpr, TypeLoc> {
+ friend TrailingObjects;
+
Expr *SubExpr;
SourceLoc LAngleLoc;
SourceLoc RAngleLoc;
- MutableArrayRef<TypeLoc> UnresolvedParams;
-public:
+
UnresolvedSpecializeExpr(Expr *SubExpr,
SourceLoc LAngleLoc,
- MutableArrayRef<TypeLoc> UnresolvedParams,
+ ArrayRef<TypeLoc> UnresolvedParams,
SourceLoc RAngleLoc)
: Expr(ExprKind::UnresolvedSpecialize, /*Implicit=*/false),
- SubExpr(SubExpr),
- LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
- UnresolvedParams(UnresolvedParams) { }
+ SubExpr(SubExpr), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {
+ Bits.UnresolvedSpecializeExpr.NumUnresolvedParams = UnresolvedParams.size();
+ std::uninitialized_copy(UnresolvedParams.begin(), UnresolvedParams.end(),
+ getTrailingObjects<TypeLoc>());
+ }
+
+public:
+ static UnresolvedSpecializeExpr *
+ create(ASTContext &ctx, Expr *SubExpr, SourceLoc LAngleLoc,
+ ArrayRef<TypeLoc> UnresolvedParams, SourceLoc RAngleLoc);
Expr *getSubExpr() const { return SubExpr; }
void setSubExpr(Expr *e) { SubExpr = e; }
/// \brief Retrieve the list of type parameters. These parameters have not yet
/// been bound to archetypes of the entity to be specialized.
- ArrayRef<TypeLoc> getUnresolvedParams() const { return UnresolvedParams; }
- MutableArrayRef<TypeLoc> getUnresolvedParams() { return UnresolvedParams; }
+ ArrayRef<TypeLoc> getUnresolvedParams() const {
+ return {getTrailingObjects<TypeLoc>(),
+ Bits.UnresolvedSpecializeExpr.NumUnresolvedParams};
+ }
+ MutableArrayRef<TypeLoc> getUnresolvedParams() {
+ return {getTrailingObjects<TypeLoc>(),
+ Bits.UnresolvedSpecializeExpr.NumUnresolvedParams};
+ }
SourceLoc getLoc() const { return LAngleLoc; }
SourceLoc getLAngleLoc() const { return LAngleLoc; }
@@ -3645,17 +3724,30 @@
/// CaptureList wraps the ClosureExpr. The dynamic semantics are that evaluates
/// the variable bindings from the capture list, then evaluates the
/// subexpression (the closure itself) and returns the result.
-class CaptureListExpr : public Expr {
- ArrayRef<CaptureListEntry> captureList;
+class CaptureListExpr final : public Expr,
+ private llvm::TrailingObjects<CaptureListExpr, CaptureListEntry> {
+ friend TrailingObjects;
+
ClosureExpr *closureBody;
-public:
+
CaptureListExpr(ArrayRef<CaptureListEntry> captureList,
ClosureExpr *closureBody)
: Expr(ExprKind::CaptureList, /*Implicit=*/false, Type()),
- captureList(captureList), closureBody(closureBody) {
+ closureBody(closureBody) {
+ Bits.CaptureListExpr.NumCaptures = captureList.size();
+ std::uninitialized_copy(captureList.begin(), captureList.end(),
+ getTrailingObjects<CaptureListEntry>());
}
- ArrayRef<CaptureListEntry> getCaptureList() { return captureList; }
+public:
+ static CaptureListExpr *create(ASTContext &ctx,
+ ArrayRef<CaptureListEntry> captureList,
+ ClosureExpr *closureBody);
+
+ ArrayRef<CaptureListEntry> getCaptureList() {
+ return {getTrailingObjects<CaptureListEntry>(),
+ Bits.CaptureListExpr.NumCaptures};
+ }
ClosureExpr *getClosureBody() { return closureBody; }
const ClosureExpr *getClosureBody() const { return closureBody; }
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 6e80301..d7167bc 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -289,12 +289,13 @@
);
enum { NumAFTExtInfoBits = 7 };
- SWIFT_INLINE_BITFIELD(AnyFunctionType, TypeBase, NumAFTExtInfoBits+10,
+ SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+16,
/// Extra information which affects how the function is called, like
/// regparm and the calling convention.
ExtInfo : NumAFTExtInfoBits,
- NumParams : 10
+ : NumPadBits,
+ NumParams : 16
);
SWIFT_INLINE_BITFIELD_FULL(ArchetypeType, TypeBase, 1+1+1+16,
@@ -1037,7 +1038,7 @@
/// is produced when parsing types and when name binding type aliases, and is
/// installed in declaration that use these erroneous types. All uses of a
/// declaration of invalid type should be ignored and not re-diagnosed.
-class ErrorType : public TypeBase {
+class ErrorType final : public TypeBase {
friend class ASTContext;
// The Error type is always canonical.
ErrorType(ASTContext &C, Type originalType,
@@ -5104,6 +5105,17 @@
return ty->getTrailingObjects<Type>();
llvm_unreachable("Unhandled BoundGenericType!");
}
+
+inline ArrayRef<AnyFunctionType::Param> AnyFunctionType::getParams() const {
+ switch (getKind()) {
+ case TypeKind::Function:
+ return cast<FunctionType>(this)->getParams();
+ case TypeKind::GenericFunction:
+ return cast<GenericFunctionType>(this)->getParams();
+ default:
+ llvm_unreachable("Undefined function type");
+ }
+}
/// \brief If this is a method in a type or extension thereof, compute
/// and return a parameter to be used for the 'self' argument. The type of
diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h
index b3fb777..1fea5fc 100644
--- a/include/swift/Basic/LangOptions.h
+++ b/include/swift/Basic/LangOptions.h
@@ -18,6 +18,7 @@
#ifndef SWIFT_BASIC_LANGOPTIONS_H
#define SWIFT_BASIC_LANGOPTIONS_H
+#include "swift/Config.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
@@ -128,6 +129,10 @@
/// configuration options.
bool EnableObjCInterop = true;
+ /// On Darwin platforms, use the pre-stable ABI's mark bit for Swift
+ /// classes instead of the stable ABI's bit.
+ bool UseDarwinPreStableABIBit = !bool(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT);
+
/// Enables checking that uses of @objc require importing
/// the Foundation module.
/// This is enabled by default because SILGen can crash in such a case, but
diff --git a/include/swift/Config.h.in b/include/swift/Config.h.in
index 652fbf4..b45083e 100644
--- a/include/swift/Config.h.in
+++ b/include/swift/Config.h.in
@@ -8,4 +8,6 @@
#cmakedefine HAVE_UNICODE_LIBEDIT 1
+#cmakedefine01 SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
+
#endif // SWIFT_CONFIG_H
diff --git a/include/swift/IDE/RefactoringKinds.def b/include/swift/IDE/RefactoringKinds.def
index 0e6a1ae..ecd3667 100644
--- a/include/swift/IDE/RefactoringKinds.def
+++ b/include/swift/IDE/RefactoringKinds.def
@@ -55,6 +55,11 @@
RANGE_REFACTORING(MoveMembersToExtension, "Move To Extension", move.members.to.extension)
RANGE_REFACTORING(ConvertStringsConcatenationToInterpolation, "Convert to String Interpolation", convert.string-concatenation.interpolation)
+
+RANGE_REFACTORING(ExpandTernaryExpr, "Expand Ternary Expression", expand.ternary.expr)
+
+RANGE_REFACTORING(ConvertToTernaryExpr, "Convert To Ternary Expression", convert.ternary.expr)
+
#undef CURSOR_REFACTORING
#undef RANGE_REFACTORING
#undef SEMANTIC_REFACTORING
diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h
index 1fb56df..ef2d095 100644
--- a/include/swift/Parse/Lexer.h
+++ b/include/swift/Parse/Lexer.h
@@ -126,13 +126,13 @@
///
/// This is only preserved if this Lexer was constructed with
/// `TriviaRetentionMode::WithTrivia`.
- syntax::TriviaList LeadingTrivia;
+ syntax::Trivia LeadingTrivia;
/// The current trailing trivia for the next token.
///
/// This is only preserved if this Lexer was constructed with
/// `TriviaRetentionMode::WithTrivia`.
- syntax::TriviaList TrailingTrivia;
+ syntax::Trivia TrailingTrivia;
Lexer(const Lexer&) = delete;
void operator=(const Lexer&) = delete;
@@ -255,7 +255,7 @@
TokStart = Tok.getLoc();
auto S = getStateForBeginningOfTokenLoc(TokStart);
if (TriviaRetention == TriviaRetentionMode::WithTrivia)
- S.LeadingTrivia = LeadingTrivia.Pieces;
+ S.LeadingTrivia = LeadingTrivia;
return S;
}
@@ -503,7 +503,7 @@
void lexOperatorIdentifier();
void lexHexNumber();
void lexNumber();
- void lexTrivia(syntax::TriviaList &T, bool IsForTrailingTrivia);
+ void lexTrivia(syntax::Trivia &T, bool IsForTrailingTrivia);
static unsigned lexUnicodeEscape(const char *&CurPtr, Lexer *Diags);
unsigned lexCharacter(const char *&CurPtr,
diff --git a/include/swift/Parse/LexerState.h b/include/swift/Parse/LexerState.h
index ec0ed9c..5151d2b 100644
--- a/include/swift/Parse/LexerState.h
+++ b/include/swift/Parse/LexerState.h
@@ -39,7 +39,7 @@
private:
explicit LexerState(SourceLoc Loc) : Loc(Loc) {}
SourceLoc Loc;
- llvm::Optional<syntax::TriviaList> LeadingTrivia;
+ llvm::Optional<syntax::Trivia> LeadingTrivia;
friend class Lexer;
};
diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h
index 717127b..94e4c2b 100644
--- a/include/swift/Parse/Parser.h
+++ b/include/swift/Parse/Parser.h
@@ -1295,6 +1295,10 @@
ParserResult<Stmt> parseStmtReturn(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtThrow(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtDefer();
+ ParserStatus
+ parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
+ Diag<> DefaultID, StmtKind ParentKind,
+ StringRef &BindingKindStr);
ParserStatus parseStmtCondition(StmtCondition &Result, Diag<> ID,
StmtKind ParentKind);
ParserResult<PoundAvailableInfo> parseStmtConditionPoundAvailable();
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index e77064b..1b4acee 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -894,9 +894,9 @@
case MetadataKind::ForeignClass: {
auto namePtrAddress =
Meta.getAddress() + TargetForeignClassMetadata<Runtime>::OffsetToName;
- StoredPointer namePtr;
- if (!Reader->readInteger(RemoteAddress(namePtrAddress), &namePtr) ||
- namePtr == 0)
+
+ StoredPointer namePtr = resolveRelativeOffset<int32_t>(namePtrAddress);
+ if (namePtr == 0)
return BuiltType();
std::string name;
if (!Reader->readString(RemoteAddress(namePtr), name))
diff --git a/include/swift/Runtime/Config.h b/include/swift/Runtime/Config.h
index ca8b293..c0e5e4f 100644
--- a/include/swift/Runtime/Config.h
+++ b/include/swift/Runtime/Config.h
@@ -65,6 +65,16 @@
#error Masking ISAs are incompatible with opaque ISAs
#endif
+/// Which bits in the class metadata are used to distinguish Swift classes
+/// from ObjC classes?
+#ifndef SWIFT_CLASS_IS_SWIFT_MASK
+# if __APPLE__ && SWIFT_OBJC_INTEROP && SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
+# define SWIFT_CLASS_IS_SWIFT_MASK 2ULL
+# else
+# define SWIFT_CLASS_IS_SWIFT_MASK 1ULL
+# endif
+#endif
+
// We try to avoid global constructors in the runtime as much as possible.
// These macros delimit allowed global ctors.
#if __clang__
diff --git a/include/swift/Runtime/Enum.h b/include/swift/Runtime/Enum.h
index 6102ff7..2b514ae 100644
--- a/include/swift/Runtime/Enum.h
+++ b/include/swift/Runtime/Enum.h
@@ -33,17 +33,29 @@
using EnumMetadata = TargetEnumMetadata<InProcess>;
struct TypeLayout;
-/// \brief Initialize the value witness table for a generic, single-payload
-/// enum instance.
+/// \brief Initialize the type metadata for a single-case enum type.
///
-/// \param vwtable - pointer to the instantiated but uninitialized value
-/// witness table for the enum.
+/// \param enumType - pointer to the instantiated but uninitialized metadata
+/// for the enum.
+/// \param flags - flags controlling the layout
+/// \param payload - type metadata for the payload of the enum.
+SWIFT_RUNTIME_EXPORT
+void swift_initEnumMetadataSingleCase(EnumMetadata *enumType,
+ EnumLayoutFlags flags,
+ const TypeLayout *payload);
+
+/// \brief Initialize the type metadata for a single-payload enum type.
+///
+/// \param enumType - pointer to the instantiated but uninitialized metadata
+/// for the enum.
+/// \param flags - flags controlling the layout
/// \param payload - type metadata for the payload case of the enum.
/// \param emptyCases - the number of empty cases in the enum.
SWIFT_RUNTIME_EXPORT
-void swift_initEnumValueWitnessTableSinglePayload(ValueWitnessTable *vwtable,
- const TypeLayout *payload,
- unsigned emptyCases);
+void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType,
+ EnumLayoutFlags flags,
+ const TypeLayout *payload,
+ unsigned emptyCases);
/// \brief Faster variant of the above which avoids digging into the enum type
/// metadata when the caller already has the payload information handy.
@@ -81,11 +93,11 @@
unsigned emptyCases)
SWIFT_CC(RegisterPreservingCC);
-/// \brief Initialize the value witness table for a generic, multi-payload
+/// \brief Initialize the type metadata for a generic, multi-payload
/// enum instance.
SWIFT_RUNTIME_EXPORT
-void swift_initEnumMetadataMultiPayload(ValueWitnessTable *vwtable,
- EnumMetadata *enumType,
+void swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
+ EnumLayoutFlags flags,
unsigned numPayloads,
const TypeLayout * const *payloadTypes);
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index b869107..7e94796 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -1355,7 +1355,7 @@
/// Is this object a valid swift type metadata?
bool isTypeMetadata() const {
- return (Data & 1);
+ return (Data & SWIFT_CLASS_IS_SWIFT_MASK);
}
/// A different perspective on the same bit
bool isPureObjC() const {
@@ -1567,86 +1567,152 @@
using StoredPointer = typename Runtime::StoredPointer;
using StoredSize = typename Runtime::StoredSize;
using InitializationFunction_t =
- void (*)(TargetForeignTypeMetadata<Runtime> *selectedMetadata);
+ void (TargetForeignTypeMetadata<Runtime> *selectedMetadata);
using RuntimeMetadataPointer =
ConstTargetMetadataPointer<Runtime, swift::TargetForeignTypeMetadata>;
+ /// An invasive cache for the runtime-uniqued lookup structure that is stored
+ /// in the header prefix of foreign metadata records.
+ ///
+ /// Prior to initialization, as emitted by the compiler, this contains the
+ /// initialization flags.
+ /// After initialization, it holds a pointer to the actual, runtime-uniqued
+ /// metadata for this type.
+ struct CacheValue {
+ StoredSize Value;
+
+ /// Work around a bug in libstdc++'s std::atomic that requires the type to
+ /// be default-constructible.
+ CacheValue() = default;
+
+ explicit CacheValue(RuntimeMetadataPointer p)
+ : Value(reinterpret_cast<StoredSize>(p))
+ {}
+
+ /// Various flags. The largest flag bit should be less than 4096 so that
+ /// a flag set is distinguishable from a valid pointer.
+ enum : StoredSize {
+ /// This metadata has an initialization callback function. If
+ /// this flag is not set, the metadata object needn't actually
+ /// have a InitializationFunction field, and that field will be
+ /// undefined.
+ HasInitializationFunction = 0x1,
+
+ LargestFlagMask = 0xFFF,
+ };
+
+ /// True if the metadata record associated with this cache has not been
+ /// initialized, so contains a flag set describing parameters to the
+ /// initialization operation. isFlags() == !isInitialized()
+ bool isFlags() const {
+ return Value <= LargestFlagMask;
+ }
+ /// True if the metadata record associated with this cache has an
+ /// initialization function which must be run if it is picked as the
+ /// canonical metadata record for its key.
+ ///
+ /// Undefined if !isFlags().
+ bool hasInitializationFunction() const {
+ assert(isFlags());
+ return Value & HasInitializationFunction;
+ }
+
+ /// True if the metadata record associated with this cache has been
+ /// initialized, so the cache contains an absolute pointer to the
+ /// canonical metadata record for its key. isInitialized() == !isFlags()
+ bool isInitialized() const {
+ return !isFlags();
+ }
+
+ /// Gets the cached pointer to the unique canonical metadata record for
+ /// this metadata record's key.
+ ///
+ /// Undefined if !isInitialized().
+ RuntimeMetadataPointer getCachedUniqueMetadata() const {
+ assert(isInitialized());
+ return RuntimeMetadataPointer(Value);
+ }
+ };
+
+
/// Foreign type metadata may have extra header fields depending on
/// the flags.
struct HeaderPrefix {
/// An optional callback performed when a particular metadata object
/// is chosen as the unique structure.
+ ///
/// If there is no initialization function, this metadata record can be
/// assumed to be immutable (except for the \c Unique invasive cache
- /// field).
- InitializationFunction_t InitializationFunction;
+ /// field). The field is not present unless the HasInitializationFunction
+ /// flag is set.
+ RelativeDirectPointer<InitializationFunction_t> InitializationFunction;
- /// The Swift-mangled name of the type. This is the uniquing key for the
- /// type.
- TargetPointer<Runtime, const char> Name;
+ /// The uniquing key for the metadata record. Metadata records with the
+ /// same Name string are considered equivalent by the runtime, and the
+ /// runtime will pick one to be canonical.
+ RelativeDirectPointer<const char> Name;
- /// A pointer to the actual, runtime-uniqued metadata for this
- /// type. This is essentially an invasive cache for the lookup
- /// structure.
- mutable std::atomic<RuntimeMetadataPointer> Unique;
-
- /// Various flags.
- enum : StoredSize {
- /// This metadata has an initialization callback function. If
- /// this flag is not set, the metadata object needn't actually
- /// have a InitializationFunction field.
- HasInitializationFunction = 0x1,
- } Flags;
+ mutable std::atomic<CacheValue> Cache;
};
struct HeaderType : HeaderPrefix, TypeMetadataHeader {};
- static constexpr int OffsetToName =
- (int) offsetof(HeaderType, Name) - (int) sizeof(HeaderType);
+ static constexpr int32_t OffsetToName =
+ (int32_t) offsetof(HeaderType, Name) - (int32_t) sizeof(HeaderType);
TargetPointer<Runtime, const char> getName() const {
return reinterpret_cast<TargetPointer<Runtime, const char>>(
- asFullMetadata(this)->Name);
+ asFullMetadata(this)->Name.get());
}
- RuntimeMetadataPointer getCachedUniqueMetadata() const {
-#if __alpha__
- // TODO: This can be a relaxed-order load if there is no initialization
- // function. On platforms we care about, consume is no more expensive than
- // relaxed, so there's no reason to branch here (and LLVM isn't smart
- // enough to eliminate it when it's not needed).
- if (!hasInitializationFunction())
- return asFullMetadata(this)->Unique.load(std::memory_order_relaxed);
-#endif
- return asFullMetadata(this)->Unique.load(SWIFT_MEMORY_ORDER_CONSUME);
+ CacheValue getCacheValue() const {
+ /// NB: This can be a relaxed-order load if there is no initialization
+ /// function. On platforms Swift currently targets, consume is no more
+ /// expensive than relaxed, so there's no reason to branch here (and LLVM
+ /// isn't smart enough to eliminate it when it's not needed).
+ ///
+ /// A port to a platform where relaxed is significantly less expensive than
+ /// consume (historically, Alpha) would probably want to preserve the
+ /// 'hasInitializationFunction' bit in its own word to be able to avoid
+ /// the consuming load when not needed.
+ return asFullMetadata(this)->Cache
+ .load(SWIFT_MEMORY_ORDER_CONSUME);
}
void setCachedUniqueMetadata(RuntimeMetadataPointer unique) const {
- assert((static_cast<RuntimeMetadataPointer>(asFullMetadata(this)->Unique) ==
- nullptr ||
- asFullMetadata(this)->Unique == unique) &&
- "already set unique metadata");
+ auto cache = getCacheValue();
+
+ // If the cache was already set to a pointer, we're done. We ought to
+ // converge on a single unique pointer.
+ if (cache.isInitialized()) {
+ assert(cache.getCachedUniqueMetadata() == unique
+ && "already set unique metadata to something else");
+ return;
+ }
+
+ auto newCache = CacheValue(unique);
// If there is no initialization function, this can be a relaxed store.
- if (!hasInitializationFunction())
- asFullMetadata(this)->Unique.store(unique, std::memory_order_relaxed);
+ if (cache.hasInitializationFunction())
+ asFullMetadata(this)->Cache.store(newCache, std::memory_order_relaxed);
// Otherwise, we need a release store to publish the result of
- // initialization
+ // initialization.
else
- asFullMetadata(this)->Unique.store(unique, std::memory_order_release);
+ asFullMetadata(this)->Cache.store(newCache, std::memory_order_release);
}
- StoredSize getFlags() const {
- return asFullMetadata(this)->Flags;
- }
+ /// Return the initialization function for this metadata record.
+ ///
+ /// As a prerequisite, the metadata record must not have been initialized yet,
+ /// and must have an initialization function to begin with, otherwise the
+ /// result is undefined.
+ InitializationFunction_t *getInitializationFunction() const {
+#ifndef NDEBUG
+ auto cache = getCacheValue();
+ assert(cache.hasInitializationFunction());
+#endif
- bool hasInitializationFunction() const {
- return getFlags() & HeaderPrefix::HasInitializationFunction;
- }
-
- InitializationFunction_t getInitializationFunction() const {
- assert(hasInitializationFunction());
return asFullMetadata(this)->InitializationFunction;
}
};
@@ -2901,10 +2967,11 @@
/// Initialize the value witness table and struct field offset vector for a
/// struct, using the "Universal" layout strategy.
SWIFT_RUNTIME_EXPORT
-void swift_initStructMetadata_UniversalStrategy(size_t numFields,
- const TypeLayout * const *fieldTypes,
- size_t *fieldOffsets,
- ValueWitnessTable *vwtable);
+void swift_initStructMetadata(StructMetadata *self,
+ StructLayoutFlags flags,
+ size_t numFields,
+ const TypeLayout * const *fieldTypes,
+ size_t *fieldOffsets);
/// Relocate the metadata for a class and copy fields from the given template.
/// The final size of the metadata is calculated at runtime from the size of
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index add1e4f..5bee126 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -968,37 +968,47 @@
SizeTy->getPointerTo()),
ATTRS(NoUnwind))
-// void swift_initStructMetadata_UniversalStrategy(size_t numFields,
-// TypeLayout * const *fieldTypes,
-// size_t *fieldOffsets,
-// value_witness_table_t *vwtable);
-FUNCTION(InitStructMetadataUniversal,
- swift_initStructMetadata_UniversalStrategy, DefaultCC,
+// void swift_initStructMetadata(Metadata *structType,
+// StructLayoutFlags flags,
+// size_t numFields,
+// TypeLayout * const *fieldTypes,
+// size_t *fieldOffsets);
+FUNCTION(InitStructMetadata,
+ swift_initStructMetadata, DefaultCC,
RETURNS(VoidTy),
- ARGS(SizeTy, Int8PtrPtrTy->getPointerTo(),
- SizeTy->getPointerTo(), WitnessTablePtrTy),
+ ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0),
+ SizeTy->getPointerTo()),
ATTRS(NoUnwind))
-// void swift_initEnumValueWitnessTableSinglePayload(value_witness_table_t *vwt,
-// TypeLayout *payload,
-// unsigned num_empty_cases);
-FUNCTION(InitEnumValueWitnessTableSinglePayload,
- swift_initEnumValueWitnessTableSinglePayload,
+// void swift_initEnumMetadataSingleCase(Metadata *enumType,
+// EnumLayoutFlags flags,
+// TypeLayout *payload);
+FUNCTION(InitEnumMetadataSingleCase,
+ swift_initEnumMetadataSingleCase,
DefaultCC,
RETURNS(VoidTy),
- ARGS(WitnessTablePtrTy, Int8PtrPtrTy, Int32Ty),
+ ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy),
ATTRS(NoUnwind))
-// void swift_initEnumMetadataMultiPayload(value_witness_table_t *vwt,
-// Metadata *enumType,
+// void swift_initEnumMetadataSinglePayload(Metadata *enumType,
+// EnumLayoutFlags flags,
+// TypeLayout *payload,
+// unsigned num_empty_cases);
+FUNCTION(InitEnumMetadataSinglePayload,
+ swift_initEnumMetadataSinglePayload,
+ DefaultCC,
+ RETURNS(VoidTy),
+ ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy, Int32Ty),
+ ATTRS(NoUnwind))
+
+// void swift_initEnumMetadataMultiPayload(Metadata *enumType,
// size_t numPayloads,
// TypeLayout * const *payloadTypes);
FUNCTION(InitEnumMetadataMultiPayload,
swift_initEnumMetadataMultiPayload,
DefaultCC,
RETURNS(VoidTy),
- ARGS(WitnessTablePtrTy, TypeMetadataPtrTy, SizeTy,
- Int8PtrPtrTy->getPointerTo(0)),
+ ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0)),
ATTRS(NoUnwind))
// int swift_getEnumCaseSinglePayload(opaque_t *obj, Metadata *payload,
diff --git a/include/swift/SIL/Dominance.h b/include/swift/SIL/Dominance.h
index 79e20d8..539c580 100644
--- a/include/swift/SIL/Dominance.h
+++ b/include/swift/SIL/Dominance.h
@@ -52,6 +52,11 @@
/// Does instruction A properly dominate instruction B?
bool properlyDominates(SILInstruction *a, SILInstruction *b);
+ /// Does instruction A dominate instruction B?
+ bool dominates(SILInstruction *a, SILInstruction *b) {
+ return a == b || properlyDominates(a, b);
+ }
+
/// Does value A properly dominate instruction B?
bool properlyDominates(SILValue a, SILInstruction *b);
@@ -74,6 +79,7 @@
}
using DominatorTreeBase::properlyDominates;
+ using DominatorTreeBase::dominates;
bool isValid(SILFunction *F) const {
return getNode(&F->front()) != nullptr;
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 3329c15..d4b007c 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -2604,26 +2604,21 @@
/// Represents an invocation of builtin functionality provided by the code
/// generator.
-class BuiltinInst
+class BuiltinInst final
: public InstructionBase<SILInstructionKind::BuiltinInst,
- SingleValueInstruction> {
+ SingleValueInstruction>,
+ private llvm::TrailingObjects<BuiltinInst, Operand, Substitution> {
+ friend TrailingObjects;
friend SILBuilder;
/// The name of the builtin to invoke.
Identifier Name;
-
- /// The number of tail-allocated substitutions, allocated after the operand
- /// list's tail allocation.
- unsigned NumSubstitutions;
-
- /// The value arguments to the builtin.
- TailAllocatedOperandList<0> Operands;
-
- Substitution *getSubstitutionsStorage() {
- return reinterpret_cast<Substitution*>(Operands.asArray().end());
+
+ size_t numTrailingObjects(OverloadToken<Operand>) const {
+ return SILInstruction::Bits.BuiltinInst.NumOperands;
}
- const Substitution *getSubstitutionsStorage() const {
- return reinterpret_cast<const Substitution*>(Operands.asArray().end());
+ size_t numTrailingObjects(OverloadToken<Substitution>) const {
+ return SILInstruction::Bits.BuiltinInst.NumSubstitutions;
}
BuiltinInst(SILDebugLocation DebugLoc, Identifier Name, SILType ReturnType,
@@ -2635,6 +2630,12 @@
ArrayRef<SILValue> Args, SILModule &M);
public:
+ ~BuiltinInst() {
+ for (auto &op : getAllOperands()) {
+ op.~Operand();
+ }
+ }
+
/// Return the name of the builtin operation.
Identifier getName() const { return Name; }
void setName(Identifier I) { Name = I; }
@@ -2670,29 +2671,33 @@
/// True if this builtin application has substitutions, which represent type
/// parameters to the builtin.
bool hasSubstitutions() const {
- return NumSubstitutions != 0;
+ return SILInstruction::Bits.BuiltinInst.NumSubstitutions != 0;
}
/// Return the type parameters to the builtin.
SubstitutionList getSubstitutions() const {
- return {getSubstitutionsStorage(), NumSubstitutions};
+ return {getTrailingObjects<Substitution>(),
+ SILInstruction::Bits.BuiltinInst.NumSubstitutions};
}
/// Return the type parameters to the builtin.
MutableArrayRef<Substitution> getSubstitutions() {
- return {getSubstitutionsStorage(), NumSubstitutions};
+ return {getTrailingObjects<Substitution>(),
+ SILInstruction::Bits.BuiltinInst.NumSubstitutions};
}
/// The arguments to the builtin.
ArrayRef<Operand> getAllOperands() const {
- return Operands.asArray();
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.BuiltinInst.NumOperands};
}
/// The arguments to the builtin.
MutableArrayRef<Operand> getAllOperands() {
- return Operands.asArray();
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.BuiltinInst.NumOperands};
}
/// The arguments to the builtin.
OperandValueArrayRef getArguments() const {
- return Operands.asValueArray();
+ return OperandValueArrayRef(getAllOperands());
}
};
@@ -2837,9 +2842,6 @@
};
private:
- unsigned Length;
- Encoding TheEncoding;
-
StringLiteralInst(SILDebugLocation DebugLoc, StringRef text,
Encoding encoding, SILType ty);
@@ -2849,11 +2851,14 @@
public:
/// getValue - Return the string data for the literal, in UTF-8.
StringRef getValue() const {
- return {getTrailingObjects<char>(), Length};
+ return {getTrailingObjects<char>(),
+ SILInstruction::Bits.StringLiteralInst.Length};
}
/// getEncoding - Return the desired encoding of the text.
- Encoding getEncoding() const { return TheEncoding; }
+ Encoding getEncoding() const {
+ return Encoding(SILInstruction::Bits.StringLiteralInst.TheEncoding);
+ }
/// getCodeUnitCount - Return encoding-based length of the string
/// literal in code units.
@@ -2881,9 +2886,6 @@
};
private:
- unsigned Length;
- Encoding TheEncoding;
-
ConstStringLiteralInst(SILDebugLocation DebugLoc, StringRef text,
Encoding encoding, SILType ty);
@@ -2893,10 +2895,15 @@
public:
/// getValue - Return the string data for the literal, in UTF-8.
- StringRef getValue() const { return {getTrailingObjects<char>(), Length}; }
+ StringRef getValue() const {
+ return {getTrailingObjects<char>(),
+ SILInstruction::Bits.ConstStringLiteralInst.Length};
+ }
/// getEncoding - Return the desired encoding of the text.
- Encoding getEncoding() const { return TheEncoding; }
+ Encoding getEncoding() const {
+ return Encoding(SILInstruction::Bits.ConstStringLiteralInst.TheEncoding);
+ }
/// getCodeUnitCount - Return encoding-based length of the string
/// literal in code units.
@@ -4382,13 +4389,13 @@
};
/// StructInst - Represents a constructed loadable struct.
-class StructInst
+class StructInst final
: public InstructionBase<SILInstructionKind::StructInst,
- SingleValueInstruction> {
+ SingleValueInstruction>,
+ private llvm::TrailingObjects<StructInst, Operand> {
+ friend TrailingObjects;
friend SILBuilder;
- TailAllocatedOperandList<0> Operands;
-
/// Because of the storage requirements of StructInst, object
/// creation goes through 'create()'.
StructInst(SILDebugLocation DebugLoc, SILType Ty,
@@ -4399,18 +4406,32 @@
ArrayRef<SILValue> Elements, SILModule &M);
public:
+ ~StructInst() {
+ for (auto &op : getAllOperands()) {
+ op.~Operand();
+ }
+ }
+
/// The elements referenced by this StructInst.
MutableArrayRef<Operand> getElementOperands() {
- return Operands.getDynamicAsArray();
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.StructInst.NumOperands};
}
/// The elements referenced by this StructInst.
OperandValueArrayRef getElements() const {
- return Operands.getDynamicValuesAsArray();
+ return OperandValueArrayRef({getTrailingObjects<Operand>(),
+ SILInstruction::Bits.StructInst.NumOperands});
}
- ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
- MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
+ ArrayRef<Operand> getAllOperands() const {
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.StructInst.NumOperands};
+ }
+ MutableArrayRef<Operand> getAllOperands() {
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.StructInst.NumOperands};
+ }
SILValue getFieldValue(const VarDecl *V) const {
return getOperandForField(V)->get();
@@ -4740,13 +4761,13 @@
/// TupleInst - Represents a constructed loadable tuple.
-class TupleInst
+class TupleInst final
: public InstructionBase<SILInstructionKind::TupleInst,
- SingleValueInstruction> {
+ SingleValueInstruction>,
+ private llvm::TrailingObjects<TupleInst, Operand> {
+ friend TrailingObjects;
friend SILBuilder;
- TailAllocatedOperandList<0> Operands;
-
/// Because of the storage requirements of TupleInst, object
/// creation goes through 'create()'.
TupleInst(SILDebugLocation DebugLoc, SILType Ty,
@@ -4757,14 +4778,22 @@
ArrayRef<SILValue> Elements, SILModule &M);
public:
+ ~TupleInst() {
+ for (auto &op : getAllOperands()) {
+ op.~Operand();
+ }
+ }
+
/// The elements referenced by this TupleInst.
MutableArrayRef<Operand> getElementOperands() {
- return Operands.getDynamicAsArray();
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.TupleInst.NumOperands};
}
/// The elements referenced by this TupleInst.
OperandValueArrayRef getElements() const {
- return Operands.getDynamicValuesAsArray();
+ return OperandValueArrayRef({getTrailingObjects<Operand>(),
+ SILInstruction::Bits.TupleInst.NumOperands});
}
/// Return the i'th value referenced by this TupleInst.
@@ -4777,8 +4806,14 @@
return operand->getOperandNumber();
}
- ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
- MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
+ ArrayRef<Operand> getAllOperands() const {
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.TupleInst.NumOperands};
+ }
+ MutableArrayRef<Operand> getAllOperands() {
+ return {getTrailingObjects<Operand>(),
+ SILInstruction::Bits.TupleInst.NumOperands};
+ }
TupleType *getTupleType() const {
return getType().getSwiftRValueType()->castTo<TupleType>();
diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h
index 6120cc4..d2e91a4 100644
--- a/include/swift/SIL/SILNode.h
+++ b/include/swift/SIL/SILNode.h
@@ -145,6 +145,22 @@
SWIFT_INLINE_BITFIELD_EMPTY(LiteralInst, SingleValueInstruction);
SWIFT_INLINE_BITFIELD_EMPTY(AllocationInst, SingleValueInstruction);
+ SWIFT_INLINE_BITFIELD_FULL(StructInst, SingleValueInstruction, 32,
+ : NumPadBits,
+ NumOperands : 32
+ );
+
+ SWIFT_INLINE_BITFIELD_FULL(TupleInst, SingleValueInstruction, 32,
+ : NumPadBits,
+ NumOperands : 32
+ );
+
+ SWIFT_INLINE_BITFIELD_FULL(BuiltinInst, SingleValueInstruction,
+ 64-NumSingleValueInstructionBits,
+ NumSubstitutions : 32-NumSingleValueInstructionBits,
+ NumOperands : 32
+ );
+
SWIFT_INLINE_BITFIELD_FULL(IntegerLiteralInst, LiteralInst, 32,
: NumPadBits,
numBits : 32
@@ -155,6 +171,18 @@
numBits : 32
);
+ SWIFT_INLINE_BITFIELD_FULL(StringLiteralInst, LiteralInst, 2+32,
+ TheEncoding : 2,
+ : NumPadBits,
+ Length : 32
+ );
+
+ SWIFT_INLINE_BITFIELD_FULL(ConstStringLiteralInst, LiteralInst, 1+32,
+ TheEncoding : 1,
+ : NumPadBits,
+ Length : 32
+ );
+
SWIFT_INLINE_BITFIELD(DeallocRefInst, DeallocationInst, 1,
OnStack : 1
);
@@ -339,6 +367,11 @@
SWIFT_INLINE_BITS(BeginAccessInst);
SWIFT_INLINE_BITS(EndAccessInst);
SWIFT_INLINE_BITS(MetatypeInst);
+ SWIFT_INLINE_BITS(BuiltinInst);
+ SWIFT_INLINE_BITS(StringLiteralInst);
+ SWIFT_INLINE_BITS(ConstStringLiteralInst);
+ SWIFT_INLINE_BITS(StructInst);
+ SWIFT_INLINE_BITS(TupleInst);
} Bits;
private:
diff --git a/include/swift/SIL/SILPrintContext.h b/include/swift/SIL/SILPrintContext.h
index 1ac3c3e..17b390f 100644
--- a/include/swift/SIL/SILPrintContext.h
+++ b/include/swift/SIL/SILPrintContext.h
@@ -29,7 +29,7 @@
class SILPrintContext {
public:
struct ID {
- enum ID_Kind { SILBasicBlock, SILUndef, SSAValue } Kind;
+ enum ID_Kind { SILBasicBlock, SILUndef, SSAValue, Null } Kind;
unsigned Number;
// A stable ordering of ID objects.
diff --git a/include/swift/SIL/SILWitnessVisitor.h b/include/swift/SIL/SILWitnessVisitor.h
index 9c6f2d0..a2a9e70 100644
--- a/include/swift/SIL/SILWitnessVisitor.h
+++ b/include/swift/SIL/SILWitnessVisitor.h
@@ -24,6 +24,7 @@
#include "swift/AST/ProtocolAssociations.h"
#include "swift/AST/Types.h"
#include "swift/SIL/TypeLowering.h"
+#include "llvm/Support/ErrorHandling.h"
namespace swift {
diff --git a/include/swift/Syntax/RawSyntax.h b/include/swift/Syntax/RawSyntax.h
index 3982724..70fcad7 100644
--- a/include/swift/Syntax/RawSyntax.h
+++ b/include/swift/Syntax/RawSyntax.h
@@ -126,27 +126,51 @@
}
/// Add some number of newlines to the position, resetting the column.
- void addNewlines(uint32_t NewLines) {
+ /// Size is byte size of newline char.
+ /// '\n' and '\r' are 1, '\r\n' is 2.
+ void addNewlines(uint32_t NewLines, uint32_t Size) {
Line += NewLines;
Column = 1;
- Offset += NewLines;
+ Offset += NewLines * Size;
}
-
+
/// Use some text as a reference for adding to the absolute position,
/// taking note of newlines, etc.
void addText(StringRef Str) {
- for (auto C : Str) {
- addCharacter(C);
+ const char * C = Str.begin();
+ while (C != Str.end()) {
+ switch (*C++) {
+ case '\n':
+ addNewlines(1, 1);
+ break;
+ case '\r':
+ if (C != Str.end() && *C == '\n') {
+ addNewlines(1, 2);
+ ++C;
+ } else {
+ addNewlines(1, 1);
+ }
+ break;
+ default:
+ addColumns(1);
+ break;
+ }
}
}
/// Use some character as a reference for adding to the absolute position,
/// taking note of newlines, etc.
+ /// Take care that consecutive call of this function with '\r' and '\n'
+ /// causes increase of 2 Line but desirable result may be 1 Line.
void addCharacter(char C) {
- if (C == '\n') {
- addNewlines(1);
- } else {
+ switch (C) {
+ case '\n':
+ case '\r':
+ addNewlines(1, 1);
+ break;
+ default:
addColumns(1);
+ break;
}
}
diff --git a/include/swift/Syntax/Serialization/SyntaxSerialization.h b/include/swift/Syntax/Serialization/SyntaxSerialization.h
index 9259095..aaf68af 100644
--- a/include/swift/Syntax/Serialization/SyntaxSerialization.h
+++ b/include/swift/Syntax/Serialization/SyntaxSerialization.h
@@ -69,6 +69,7 @@
case syntax::TriviaKind::Formfeed:
case syntax::TriviaKind::Newline:
case syntax::TriviaKind::CarriageReturn:
+ case syntax::TriviaKind::CarriageReturnLineFeed:
case syntax::TriviaKind::Backtick:
out.mapRequired("value", value.Count);
break;
@@ -95,6 +96,7 @@
out.enumCase(value, "Formfeed", syntax::TriviaKind::Formfeed);
out.enumCase(value, "Newline", syntax::TriviaKind::Newline);
out.enumCase(value, "CarriageReturn", syntax::TriviaKind::CarriageReturn);
+ out.enumCase(value, "CarriageReturnLineFeed", syntax::TriviaKind::CarriageReturnLineFeed);
out.enumCase(value, "LineComment", syntax::TriviaKind::LineComment);
out.enumCase(value, "BlockComment", syntax::TriviaKind::BlockComment);
out.enumCase(value, "DocLineComment", syntax::TriviaKind::DocLineComment);
diff --git a/include/swift/Syntax/SyntaxNodes.h.gyb b/include/swift/Syntax/SyntaxNodes.h.gyb
index 78baadd..45037f9 100644
--- a/include/swift/Syntax/SyntaxNodes.h.gyb
+++ b/include/swift/Syntax/SyntaxNodes.h.gyb
@@ -99,7 +99,6 @@
% end
% end
-
}
}
diff --git a/include/swift/Syntax/Trivia.h b/include/swift/Syntax/Trivia.h
index 16c0601..ff3a6cc 100644
--- a/include/swift/Syntax/Trivia.h
+++ b/include/swift/Syntax/Trivia.h
@@ -113,6 +113,9 @@
/// A newline '\r' character.
CarriageReturn,
+
+ /// A newline consists of contiguous '\r' and '\n' characters.
+ CarriageReturnLineFeed,
/// A developer line comment, starting with '//'
LineComment,
@@ -189,6 +192,12 @@
static TriviaPiece carriageReturns(unsigned Count) {
return {TriviaKind::CarriageReturn, Count};
}
+
+ /// Return a piece of trivia for some number of two bytes sequence
+ /// consists of CR and LF in a row.
+ static TriviaPiece carriageReturnLineFeeds(unsigned Count) {
+ return {TriviaKind::CarriageReturnLineFeed, Count};
+ }
/// Return a piece of trivia for a single line of ('//') developer comment.
static TriviaPiece lineComment(const OwnedString Text) {
@@ -241,10 +250,16 @@
case TriviaKind::VerticalTab:
case TriviaKind::Formfeed:
return Count;
+ case TriviaKind::CarriageReturnLineFeed:
+ return Count * 2;
}
}
void accumulateAbsolutePosition(AbsolutePosition &Pos) const;
+
+ /// Try to compose this and Next to one TriviaPiece.
+ /// It returns true if it is succeeded.
+ bool trySquash(const TriviaPiece &Next);
/// Print a debug representation of this trivia piece to the provided output
/// stream and indentation level.
@@ -336,6 +351,10 @@
Len += P.getTextLength();
return Len;
}
+
+ /// Append Next TriviaPiece or compose last TriviaPiece and
+ /// Next TriviaPiece to one last TriviaPiece if it can.
+ void appendOrSquash(const TriviaPiece &Next);
/// Dump a debug representation of this Trivia collection to standard error.
void dump() const;
@@ -411,6 +430,15 @@
}
return {{TriviaPiece::carriageReturns(Count)}};
}
+
+ /// Return a collection of trivia of some number of two bytes sequence
+ /// consists of CR and LF in a row.
+ static Trivia carriageReturnLineFeeds(unsigned Count) {
+ if (Count == 0) {
+ return {};
+ }
+ return {{TriviaPiece::carriageReturnLineFeeds(Count)}};
+ }
/// Return a collection of trivia with a single line of ('//')
/// developer comment.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7ba377e..d53d188 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -194,8 +194,8 @@
/// func ==(Int, Int) -> Bool
FuncDecl *EqualIntDecl = nullptr;
- /// func _mixForSynthesizedHashValue(Int, Int) -> Int
- FuncDecl *MixForSynthesizedHashValueDecl = nullptr;
+ /// func _combineHashValues(Int, Int) -> Int
+ FuncDecl *CombineHashValuesDecl = nullptr;
/// func _mixInt(Int) -> Int
FuncDecl *MixIntDecl = nullptr;
@@ -1048,9 +1048,9 @@
return decl;
}
-FuncDecl *ASTContext::getMixForSynthesizedHashValueDecl() const {
- if (Impl.MixForSynthesizedHashValueDecl)
- return Impl.MixForSynthesizedHashValueDecl;
+FuncDecl *ASTContext::getCombineHashValuesDecl() const {
+ if (Impl.CombineHashValuesDecl)
+ return Impl.CombineHashValuesDecl;
auto resolver = getLazyResolver();
auto intType = getIntDecl()->getDeclaredType();
@@ -1066,8 +1066,8 @@
};
auto decl = lookupLibraryIntrinsicFunc(
- *this, "_mixForSynthesizedHashValue", resolver, callback);
- Impl.MixForSynthesizedHashValueDecl = decl;
+ *this, "_combineHashValues", resolver, callback);
+ Impl.CombineHashValuesDecl = decl;
return decl;
}
@@ -3605,17 +3605,6 @@
return properties;
}
-ArrayRef<AnyFunctionType::Param> AnyFunctionType::getParams() const {
- switch (getKind()) {
- case TypeKind::Function:
- return cast<FunctionType>(this)->getParams();
- case TypeKind::GenericFunction:
- return cast<GenericFunctionType>(this)->getParams();
- default:
- llvm_unreachable("Undefined function type");
- }
-}
-
AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const {
if (isa<FunctionType>(this))
return FunctionType::get(getInput(), getResult(), info);
diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
index 5456345..e44c544 100644
--- a/lib/AST/ASTVerifier.cpp
+++ b/lib/AST/ASTVerifier.cpp
@@ -2710,6 +2710,24 @@
}
}
+ if (CD->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>()) {
+ if (!CD->getInterfaceType() ||
+ !CD->getInterfaceType()->is<AnyFunctionType>()) {
+ Out << "Expected FuncDecl to have a function type!\n";
+ abort();
+ }
+
+ auto resultTy = CD->getResultInterfaceType();
+
+ // FIXME: Update to look for plain Optional once
+ // ImplicitlyUnwrappedOptional is removed
+ if (!resultTy->getAnyOptionalObjectType()) {
+ Out << "implicitly unwrapped optional attribute should only be set "
+ "on functions with optional return types\n";
+ abort();
+ }
+ }
+
verifyCheckedBase(CD);
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9d56d05..7dbaf8c 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1370,6 +1370,49 @@
return ::new(Buffer) SequenceExpr(elements);
}
+ErasureExpr *ErasureExpr::create(ASTContext &ctx, Expr *subExpr, Type type,
+ ArrayRef<ProtocolConformanceRef> conformances){
+ auto size = totalSizeToAlloc<ProtocolConformanceRef>(conformances.size());
+ auto mem = ctx.Allocate(size, alignof(ErasureExpr));
+ return ::new(mem) ErasureExpr(subExpr, type, conformances);
+}
+
+UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
+ Expr *SubExpr, SourceLoc LAngleLoc,
+ ArrayRef<TypeLoc> UnresolvedParams,
+ SourceLoc RAngleLoc) {
+ auto size = totalSizeToAlloc<TypeLoc>(UnresolvedParams.size());
+ auto mem = ctx.Allocate(size, alignof(UnresolvedSpecializeExpr));
+ return ::new(mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
+ UnresolvedParams, RAngleLoc);
+}
+
+CaptureListExpr *CaptureListExpr::create(ASTContext &ctx,
+ ArrayRef<CaptureListEntry> captureList,
+ ClosureExpr *closureBody) {
+ auto size = totalSizeToAlloc<CaptureListEntry>(captureList.size());
+ auto mem = ctx.Allocate(size, alignof(CaptureListExpr));
+ return ::new(mem) CaptureListExpr(captureList, closureBody);
+}
+
+TupleShuffleExpr *TupleShuffleExpr::create(ASTContext &ctx,
+ Expr *subExpr,
+ ArrayRef<int> elementMapping,
+ TypeImpact typeImpact,
+ ConcreteDeclRef defaultArgsOwner,
+ ArrayRef<unsigned> VariadicArgs,
+ Type VarargsArrayTy,
+ ArrayRef<Expr *> CallerDefaultArgs,
+ Type ty) {
+ auto size = totalSizeToAlloc<Expr*, int, unsigned>(CallerDefaultArgs.size(),
+ elementMapping.size(),
+ VariadicArgs.size());
+ auto mem = ctx.Allocate(size, alignof(TupleShuffleExpr));
+ return ::new(mem) TupleShuffleExpr(subExpr, elementMapping, typeImpact,
+ defaultArgsOwner, VariadicArgs,
+ VarargsArrayTy, CallerDefaultArgs, ty);
+}
+
SourceRange TupleExpr::getSourceRange() const {
SourceLoc start = SourceLoc();
SourceLoc end = SourceLoc();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 5b7c020..c396385 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1184,6 +1184,12 @@
Target.isOSDarwin());
Opts.EnableSILOpaqueValues |= Args.hasArg(OPT_enable_sil_opaque_values);
+#if SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
+ Opts.UseDarwinPreStableABIBit = false;
+#else
+ Opts.UseDarwinPreStableABIBit = true;
+#endif
+
// Must be processed after any other language options that could affect
// platform conditions.
bool UnsupportedOS, UnsupportedArch;
diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp
index bc794c7..28325a6 100644
--- a/lib/IDE/Refactoring.cpp
+++ b/lib/IDE/Refactoring.cpp
@@ -1793,6 +1793,395 @@
return false;
}
+/// Abstract helper class containing info about an IfExpr
+/// that can be expanded into an IfStmt.
+class ExpandableTernaryExprInfo {
+
+public:
+ virtual ~ExpandableTernaryExprInfo() {}
+
+ virtual IfExpr *getIf() = 0;
+
+ virtual SourceRange getNameRange() = 0;
+
+ virtual Type getType() = 0;
+
+ virtual bool shouldDeclareNameAndType() {
+ return !getType().isNull();
+ }
+
+ virtual bool isValid() {
+
+ //Ensure all public properties are non-nil and valid
+ if (!getIf() || !getNameRange().isValid())
+ return false;
+ if (shouldDeclareNameAndType() && getType().isNull())
+ return false;
+
+ return true; //valid
+ }
+
+ CharSourceRange getNameCharRange(const SourceManager &SM) {
+ return Lexer::getCharSourceRangeFromSourceRange(SM, getNameRange());
+ }
+};
+
+/// Concrete subclass containing info about an AssignExpr
+/// where the source is the expandable IfExpr.
+class ExpandableAssignTernaryExprInfo: public ExpandableTernaryExprInfo {
+
+public:
+ ExpandableAssignTernaryExprInfo(AssignExpr *Assign): Assign(Assign) {}
+
+ IfExpr *getIf() {
+ if (!Assign)
+ return nullptr;
+
+ return dyn_cast<IfExpr>(Assign->getSrc());
+ }
+
+ SourceRange getNameRange() {
+ auto Invalid = SourceRange();
+
+ if (!Assign)
+ return Invalid;
+
+ if (auto dest = Assign->getDest())
+ return dest->getSourceRange();
+
+ return Invalid;
+ }
+
+ Type getType() {
+ return nullptr;
+ }
+
+private:
+ AssignExpr *Assign = nullptr;
+};
+
+/// Concrete subclass containing info about a PatternBindingDecl
+/// where the pattern initializer is the expandable IfExpr.
+class ExpandableBindingTernaryExprInfo: public ExpandableTernaryExprInfo {
+
+public:
+ ExpandableBindingTernaryExprInfo(PatternBindingDecl *Binding):
+ Binding(Binding) {}
+
+ IfExpr *getIf() {
+ if (Binding && Binding->getNumPatternEntries() == 1)
+ return dyn_cast<IfExpr>(Binding->getInit(0));
+
+ return nullptr;
+ }
+
+ SourceRange getNameRange() {
+ if (auto Pattern = getNamePattern())
+ return Pattern->getSourceRange();
+
+ return SourceRange();
+ }
+
+ Type getType() {
+ if (auto Pattern = getNamePattern())
+ return Pattern->getType();
+
+ return nullptr;
+ }
+
+private:
+ Pattern *getNamePattern() {
+ if (!Binding || Binding->getNumPatternEntries() != 1)
+ return nullptr;
+
+ auto Pattern = Binding->getPattern(0);
+
+ if (!Pattern)
+ return nullptr;
+
+ if (auto TyPattern = dyn_cast<TypedPattern>(Pattern))
+ Pattern = TyPattern->getSubPattern();
+
+ return Pattern;
+ }
+
+ PatternBindingDecl *Binding = nullptr;
+};
+
+std::unique_ptr<ExpandableTernaryExprInfo>
+findExpandableTernaryExpression(ResolvedRangeInfo Info) {
+
+ if (Info.Kind != RangeKind::SingleDecl
+ && Info.Kind != RangeKind:: SingleExpression)
+ return nullptr;
+
+ if (Info.ContainedNodes.size() != 1)
+ return nullptr;
+
+ if (auto D = Info.ContainedNodes[0].dyn_cast<Decl*>())
+ if (auto Binding = dyn_cast<PatternBindingDecl>(D))
+ return llvm::make_unique<ExpandableBindingTernaryExprInfo>(Binding);
+
+ if (auto E = Info.ContainedNodes[0].dyn_cast<Expr*>())
+ if (auto Assign = dyn_cast<AssignExpr>(E))
+ return llvm::make_unique<ExpandableAssignTernaryExprInfo>(Assign);
+
+ return nullptr;
+}
+
+bool RefactoringActionExpandTernaryExpr::
+isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
+ auto Target = findExpandableTernaryExpression(Info);
+ return Target && Target->isValid();
+}
+
+bool RefactoringActionExpandTernaryExpr::performChange() {
+ auto Target = findExpandableTernaryExpression(RangeInfo);
+
+ if (!Target || !Target->isValid())
+ return true; //abort
+
+ auto NameCharRange = Target->getNameCharRange(SM);
+
+ auto IfRange = Target->getIf()->getSourceRange();
+ auto IfCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, IfRange);
+
+ auto CondRange = Target->getIf()->getCondExpr()->getSourceRange();
+ auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, CondRange);
+
+ auto ThenRange = Target->getIf()->getThenExpr()->getSourceRange();
+ auto ThenCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ThenRange);
+
+ auto ElseRange = Target->getIf()->getElseExpr()->getSourceRange();
+ auto ElseCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ElseRange);
+
+ llvm::SmallString<64> DeclBuffer;
+ llvm::raw_svector_ostream OS(DeclBuffer);
+
+ llvm::StringRef Space = " ";
+ llvm::StringRef NewLine = "\n";
+
+ if (Target->shouldDeclareNameAndType()) {
+ //Specifier will not be replaced; append after specifier
+ OS << NameCharRange.str() << tok::colon << Space;
+ OS << Target->getType() << NewLine;
+ }
+
+ OS << tok::kw_if << Space;
+ OS << CondCharRange.str() << Space;
+ OS << tok::l_brace << NewLine;
+
+ OS << NameCharRange.str() << Space;
+ OS << tok::equal << Space;
+ OS << ThenCharRange.str() << NewLine;
+
+ OS << tok::r_brace << Space;
+ OS << tok::kw_else << Space;
+ OS << tok::l_brace << NewLine;
+
+ OS << NameCharRange.str() << Space;
+ OS << tok::equal << Space;
+ OS << ElseCharRange.str() << NewLine;
+
+ OS << tok::r_brace;
+
+ //Start replacement with name range, skip the specifier
+ auto ReplaceRange(NameCharRange);
+ ReplaceRange.widen(IfCharRange);
+
+ EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());
+
+ return false; //don't abort
+}
+
+/// Struct containing info about an IfStmt that can be converted into an IfExpr.
+struct ConvertToTernaryExprInfo {
+ ConvertToTernaryExprInfo() {}
+
+ Expr *AssignDest() {
+
+ if (!Then || !Then->getDest() || !Else || !Else->getDest())
+ return nullptr;
+
+ auto ThenDest = Then->getDest();
+ auto ElseDest = Else->getDest();
+
+ if (ThenDest->getKind() != ElseDest->getKind())
+ return nullptr;
+
+ switch (ThenDest->getKind()) {
+ case ExprKind::DeclRef: {
+ auto ThenRef = dyn_cast<DeclRefExpr>(Then->getDest());
+ auto ElseRef = dyn_cast<DeclRefExpr>(Else->getDest());
+
+ if (!ThenRef || !ThenRef->getDecl() || !ElseRef || !ElseRef->getDecl())
+ return nullptr;
+
+ auto ThenName = ThenRef->getDecl()->getFullName();
+ auto ElseName = ElseRef->getDecl()->getFullName();
+
+ if (ThenName.compare(ElseName) != 0)
+ return nullptr;
+
+ return Then->getDest();
+ }
+ case ExprKind::Tuple: {
+ auto ThenTuple = dyn_cast<TupleExpr>(Then->getDest());
+ auto ElseTuple = dyn_cast<TupleExpr>(Else->getDest());
+
+ if (!ThenTuple || !ElseTuple)
+ return nullptr;
+
+ auto ThenNames = ThenTuple->getElementNames();
+ auto ElseNames = ElseTuple->getElementNames();
+
+ if (!ThenNames.equals(ElseNames))
+ return nullptr;
+
+ return ThenTuple;
+ }
+ default:
+ return nullptr;
+ }
+ }
+
+ Expr *ThenSrc() {
+ if (!Then)
+ return nullptr;
+ return Then->getSrc();
+ }
+
+ Expr *ElseSrc() {
+ if (!Else)
+ return nullptr;
+ return Else->getSrc();
+ }
+
+ bool isValid() {
+ if (!Cond || !AssignDest() || !ThenSrc() || !ElseSrc()
+ || !IfRange.isValid())
+ return false;
+
+ return true;
+ }
+
+ PatternBindingDecl *Binding = nullptr; //optional
+
+ Expr *Cond = nullptr; //required
+ AssignExpr *Then = nullptr; //required
+ AssignExpr *Else = nullptr; //required
+ SourceRange IfRange;
+};
+
+ConvertToTernaryExprInfo
+findConvertToTernaryExpression(ResolvedRangeInfo Info) {
+
+ auto notFound = ConvertToTernaryExprInfo();
+
+ if (Info.Kind != RangeKind::SingleStatement
+ && Info.Kind != RangeKind::MultiStatement)
+ return notFound;
+
+ if (Info.ContainedNodes.size() == 0)
+ return notFound;
+
+ struct AssignExprFinder: public SourceEntityWalker {
+
+ AssignExpr *Assign = nullptr;
+
+ AssignExprFinder(Stmt* S) {
+ if (S)
+ walk(S);
+ }
+
+ virtual bool walkToExprPre(Expr *E) {
+ Assign = dyn_cast<AssignExpr>(E);
+ return false;
+ }
+ };
+
+ ConvertToTernaryExprInfo Target;
+
+ IfStmt *If = nullptr;
+
+ if (Info.ContainedNodes.size() == 1) {
+ if (auto S = Info.ContainedNodes[0].dyn_cast<Stmt*>())
+ If = dyn_cast<IfStmt>(S);
+ }
+
+ if (Info.ContainedNodes.size() == 2) {
+ if (auto D = Info.ContainedNodes[0].dyn_cast<Decl*>())
+ Target.Binding = dyn_cast<PatternBindingDecl>(D);
+ if (auto S = Info.ContainedNodes[1].dyn_cast<Stmt*>())
+ If = dyn_cast<IfStmt>(S);
+ }
+
+ if (!If)
+ return notFound;
+
+ auto CondList = If->getCond();
+
+ if (CondList.size() != 1)
+ return notFound;
+
+ Target.Cond = CondList[0].getBooleanOrNull();
+ Target.IfRange = If->getSourceRange();
+
+ Target.Then = AssignExprFinder(If->getThenStmt()).Assign;
+ Target.Else = AssignExprFinder(If->getElseStmt()).Assign;
+
+ return Target;
+}
+
+bool RefactoringActionConvertToTernaryExpr::
+isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
+ return findConvertToTernaryExpression(Info).isValid();
+}
+
+bool RefactoringActionConvertToTernaryExpr::performChange() {
+ auto Target = findConvertToTernaryExpression(RangeInfo);
+
+ if (!Target.isValid())
+ return true; //abort
+
+ llvm::SmallString<64> DeclBuffer;
+ llvm::raw_svector_ostream OS(DeclBuffer);
+
+ llvm::StringRef Space = " ";
+
+ auto IfRange = Target.IfRange;
+ auto ReplaceRange = Lexer::getCharSourceRangeFromSourceRange(SM, IfRange);
+
+ auto CondRange = Target.Cond->getSourceRange();
+ auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, CondRange);
+
+ auto ThenRange = Target.ThenSrc()->getSourceRange();
+ auto ThenCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ThenRange);
+
+ auto ElseRange = Target.ElseSrc()->getSourceRange();
+ auto ElseCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ElseRange);
+
+ CharSourceRange DestCharRange;
+
+ if (Target.Binding) {
+ auto DestRange = Target.Binding->getSourceRange();
+ DestCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, DestRange);
+ ReplaceRange.widen(DestCharRange);
+ } else {
+ auto DestRange = Target.AssignDest()->getSourceRange();
+ DestCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, DestRange);
+ }
+
+ OS << DestCharRange.str() << Space << tok::equal << Space;
+ OS << CondCharRange.str() << Space << tok::question_postfix << Space;
+ OS << ThenCharRange.str() << Space << tok::colon << Space;
+ OS << ElseCharRange.str();
+
+ EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());
+
+ return false; //don't abort
+}
+
/// The helper class analyzes a given nominal decl or an extension decl to
/// decide whether stubs are required to filled in and the context in which
/// these stubs should be filled.
diff --git a/lib/IRGen/FixedTypeInfo.h b/lib/IRGen/FixedTypeInfo.h
index 8d7465d..188dcea 100644
--- a/lib/IRGen/FixedTypeInfo.h
+++ b/lib/IRGen/FixedTypeInfo.h
@@ -226,7 +226,7 @@
/// Fixed-size types never need dynamic value witness table instantiation.
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {}
void collectArchetypeMetadata(
diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp
index de064a0..c260771 100644
--- a/lib/IRGen/GenCall.cpp
+++ b/lib/IRGen/GenCall.cpp
@@ -1281,8 +1281,10 @@
assert(LastArgWritten == 1 && "emitting unnaturally to indirect result");
Args[0] = result.getAddress();
+ SILFunctionConventions FnConv(CurCallee.getSubstFunctionType(),
+ IGF.getSILModule());
addIndirectResultAttributes(IGF.IGM, CurCallee.getMutableAttributes(),
- 0, true);
+ 0, FnConv.getNumIndirectSILResults() <= 1);
#ifndef NDEBUG
LastArgWritten = 0; // appease an assert
#endif
diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp
index 7776b2d..eb1bca6 100644
--- a/lib/IRGen/GenEnum.cpp
+++ b/lib/IRGen/GenEnum.cpp
@@ -130,6 +130,14 @@
using namespace swift;
using namespace irgen;
+static llvm::Constant *emitEnumLayoutFlags(IRGenModule &IGM, bool isVWTMutable){
+ // For now, we always use the Swift 5 algorithm.
+ auto flags = EnumLayoutFlags::Swift5Algorithm;
+ if (isVWTMutable) flags |= EnumLayoutFlags::IsVWTMutable;
+
+ return IGM.getSize(Size(uintptr_t(flags)));
+}
+
SpareBitVector getBitVectorFromAPInt(const APInt &bits, unsigned startBit = 0) {
if (startBit == 0) {
return SpareBitVector::fromAPInt(bits);
@@ -587,78 +595,21 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
// Fixed-size enums don't need dynamic witness table initialization.
if (TIK >= Fixed) return;
- assert(!ElementsWithPayload.empty() &&
+ assert(ElementsWithPayload.size() == 1 &&
"empty singleton enum should not be dynamic!");
- // Get the value witness table for the element.
- SILType eltTy = T.getEnumElementType(ElementsWithPayload[0].decl,
- IGM.getSILModule());
- llvm::Value *eltLayout = IGF.emitTypeLayoutRef(eltTy);
-
- Address vwtAddr(vwtable, IGF.IGM.getPointerAlignment());
- Address eltLayoutAddr(eltLayout, IGF.IGM.getPointerAlignment());
-
- auto getWitnessDestAndSrc = [&](ValueWitness witness,
- Address *dest,
- Address *src) {
- *dest = IGF.Builder.CreateConstArrayGEP(vwtAddr,
- unsigned(witness), IGF.IGM.getPointerSize());
- *src = IGF.Builder.CreateConstArrayGEP(eltLayoutAddr,
- unsigned(witness) - unsigned(ValueWitness::First_TypeLayoutWitness),
- IGF.IGM.getPointerSize());
- };
-
- auto copyWitnessFromElt = [&](ValueWitness witness) {
- Address dest, src;
- getWitnessDestAndSrc(witness, &dest, &src);
- auto val = IGF.Builder.CreateLoad(src);
- IGF.Builder.CreateStore(val, dest);
- };
-
- copyWitnessFromElt(ValueWitness::Size);
- copyWitnessFromElt(ValueWitness::Stride);
-
- // Copy flags over, adding HasEnumWitnesses flag
- auto copyFlagsFromElt = [&](ValueWitness witness) -> llvm::Value* {
- Address dest, src;
- getWitnessDestAndSrc(witness, &dest, &src);
- auto val = IGF.Builder.CreateLoad(src);
- auto ewFlag = IGF.Builder.CreatePtrToInt(val, IGF.IGM.SizeTy);
- auto ewMask
- = IGF.IGM.getSize(Size(ValueWitnessFlags::HasEnumWitnesses));
- ewFlag = IGF.Builder.CreateOr(ewFlag, ewMask);
- auto flag = IGF.Builder.CreateIntToPtr(ewFlag,
- dest.getType()->getElementType());
- IGF.Builder.CreateStore(flag, dest);
- return val;
- };
-
- auto flags = copyFlagsFromElt(ValueWitness::Flags);
-
- // If the original type had extra inhabitants, carry over its
- // extra inhabitant flags.
- auto xiBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
- auto noXIBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
-
- auto xiFlag = IGF.Builder.CreatePtrToInt(flags, IGF.IGM.SizeTy);
- auto xiMask
- = IGF.IGM.getSize(Size(ValueWitnessFlags::Enum_HasExtraInhabitants));
- xiFlag = IGF.Builder.CreateAnd(xiFlag, xiMask);
- auto xiBool = IGF.Builder.CreateICmpNE(xiFlag,
- IGF.IGM.getSize(Size(0)));
- IGF.Builder.CreateCondBr(xiBool, xiBB, noXIBB);
-
- IGF.Builder.emitBlock(xiBB);
- ConditionalDominanceScope condition(IGF);
- copyWitnessFromElt(ValueWitness::ExtraInhabitantFlags);
- IGF.Builder.CreateBr(noXIBB);
-
- IGF.Builder.emitBlock(noXIBB);
+ auto payloadTy = T.getEnumElementType(ElementsWithPayload[0].decl,
+ IGM.getSILModule());
+ auto payloadLayout = IGF.emitTypeLayoutRef(payloadTy);
+ auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
+ IGF.Builder.CreateCall(
+ IGF.IGM.getInitEnumMetadataSingleCaseFn(),
+ {metadata, flags, payloadLayout});
}
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
@@ -904,7 +855,7 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
// No-payload enums are always fixed-size so never need dynamic value
// witness table initialization.
@@ -2846,7 +2797,7 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
// Fixed-size enums don't need dynamic witness table initialization.
if (TIK >= Fixed) return;
@@ -2858,10 +2809,10 @@
auto payloadLayout = IGF.emitTypeLayoutRef(payloadTy);
auto emptyCasesVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
ElementsWithNoPayload.size());
-
+ auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
IGF.Builder.CreateCall(
- IGF.IGM.getInitEnumValueWitnessTableSinglePayloadFn(),
- {vwtable, payloadLayout, emptyCasesVal});
+ IGF.IGM.getInitEnumMetadataSinglePayloadFn(),
+ {metadata, flags, payloadLayout, emptyCasesVal});
}
/// \group Extra inhabitants
@@ -4744,7 +4695,7 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
// Fixed-size enums don't need dynamic metadata initialization.
if (TIK >= Fixed) return;
@@ -4754,8 +4705,9 @@
auto numPayloadsVal = llvm::ConstantInt::get(IGF.IGM.SizeTy,
ElementsWithPayload.size());
+ auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
IGF.Builder.CreateCall(IGF.IGM.getInitEnumMetadataMultiPayloadFn(),
- {vwtable, metadata, numPayloadsVal,
+ {metadata, flags, numPayloadsVal,
payloadLayoutArray});
}
@@ -5139,7 +5091,7 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
llvm_unreachable("resilient enums cannot be defined");
}
@@ -5392,9 +5344,9 @@
}
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
- return Strategy.initializeMetadata(IGF, metadata, vwtable, T);
+ return Strategy.initializeMetadata(IGF, metadata, isVWTMutable, T);
}
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
return Strategy.mayHaveExtraInhabitants(IGM);
diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h
index b82a370..262f88e 100644
--- a/lib/IRGen/GenEnum.h
+++ b/lib/IRGen/GenEnum.h
@@ -372,7 +372,7 @@
virtual void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const = 0;
virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0;
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index c728254..0a07b69 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -2779,14 +2779,9 @@
bool HasDependentMetadata = false;
/// Set to true if the value witness table for the generic type is dependent
- /// on its generic parameters. If true, the value witness will be
- /// tail-emplaced inside the metadata pattern and initialized by the fill
- /// function. Implies HasDependentMetadata.
+ /// on its generic parameters. Implies HasDependentMetadata.
bool HasDependentVWT = false;
- /// The offset of the tail-allocated dependent VWT, if any.
- Size DependentVWTPoint = Size::invalid();
-
template <class... T>
GenericMetadataBuilderBase(IRGenModule &IGM, T &&...args)
: super(IGM, std::forward<T>(args)...) {}
@@ -2852,31 +2847,13 @@
value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
IGF.Builder.CreateStore(value, dest);
}
-
- // Initialize the instantiated dependent value witness table, if we have
- // one.
- llvm::Value *vwtableValue = nullptr;
- if (HasDependentVWT) {
- assert(!AddressPoint.isInvalid() && "did not set valid address point!");
- assert(!DependentVWTPoint.isInvalid() && "did not set dependent VWT point!");
-
- // Fill in the pointer from the metadata to the VWT. The VWT pointer
- // always immediately precedes the address point.
- auto vwtAddr = createPointerSizedGEP(IGF, metadataWords,
- DependentVWTPoint - AddressPoint);
- vwtableValue = IGF.Builder.CreateBitCast(vwtAddr.getAddress(),
- IGF.IGM.WitnessTablePtrTy);
- auto vwtAddrVal = IGF.Builder.CreateBitCast(vwtableValue, IGM.Int8PtrTy);
- auto vwtRefAddr = createPointerSizedGEP(IGF, metadataWords,
- Size(0) - IGM.getPointerSize());
- IGF.Builder.CreateStore(vwtAddrVal, vwtRefAddr);
-
+ // A dependent VWT means that we have dependent metadata.
+ if (HasDependentVWT)
HasDependentMetadata = true;
- }
if (HasDependentMetadata) {
- asImpl().emitInitializeMetadata(IGF, metadataValue, vwtableValue);
+ asImpl().emitInitializeMetadata(IGF, metadataValue, false);
}
// The metadata is now complete.
@@ -2912,13 +2889,6 @@
// Lay out the template data.
super::layout();
- // If we have a dependent value witness table, emit its template.
- if (HasDependentVWT) {
- // Note the dependent VWT offset.
- DependentVWTPoint = getNextOffsetFromTemplateHeader();
- asImpl().addDependentValueWitnessTablePattern();
- }
-
// Fill in the header:
// Metadata *(*CreateFunction)(GenericMetadata *, const void*);
@@ -3009,7 +2979,7 @@
void irgen::emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
- llvm::Value *vwtable) {
+ bool isVWTMutable) {
auto *target = T.getNominalOrBoundGenericNominal();
llvm::Value *fieldVector
= emitAddressOfFieldOffsetVector(IGF, metadata, target)
@@ -3045,15 +3015,18 @@
auto numFields = IGF.IGM.getSize(Size(storedProperties.size()));
if (isa<ClassDecl>(target)) {
- assert(vwtable == nullptr);
IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
{metadata, numFields,
fields.getAddress(), fieldVector});
} else {
assert(isa<StructDecl>(target));
- IGF.Builder.CreateCall(IGF.IGM.getInitStructMetadataUniversalFn(),
- {numFields, fields.getAddress(),
- fieldVector, vwtable});
+ StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm;
+ if (isVWTMutable)
+ flags |= StructLayoutFlags::IsVWTMutable;
+
+ IGF.Builder.CreateCall(IGF.IGM.getInitStructMetadataFn(),
+ {metadata, IGF.IGM.getSize(Size(uintptr_t(flags))),
+ numFields, fields.getAddress(), fieldVector});
}
IGF.Builder.CreateLifetimeEnd(fields,
@@ -3360,16 +3333,16 @@
}
void addClassFlags() {
- // Always set a flag saying that this is a Swift 1.0 class.
- ClassFlags flags = ClassFlags::IsSwift1;
+ auto flags = ClassFlags();
- // Set a flag if the class uses Swift 1.0 refcounting.
+ // Set a flag if the class uses Swift refcounting.
auto type = Target->getDeclaredType()->getCanonicalType();
if (getReferenceCountingForType(IGM, type)
== ReferenceCounting::Native) {
- flags |= ClassFlags::UsesSwift1Refcounting;
+ flags |= ClassFlags::UsesSwiftRefcounting;
}
+ // Set a flag if the class has a custom ObjC name.
DeclAttributes attrs = Target->getAttrs();
if (auto objc = attrs.getAttribute<ObjCAttr>()) {
if (objc->getName())
@@ -3438,17 +3411,21 @@
if (!IGM.ObjCInterop) {
// with no Objective-C runtime, just give an empty pointer with the
// swift bit set.
+ // FIXME: Remove null data altogether rdar://problem/18801263
B.addInt(IGM.IntPtrTy, 1);
return;
}
+
// Derive the RO-data.
llvm::Constant *data = emitClassPrivateData(IGM, Target);
- // We always set the low bit to indicate this is a Swift class.
- data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
- data = llvm::ConstantExpr::getAdd(data,
- llvm::ConstantInt::get(IGM.IntPtrTy, 1));
+ // Set a low bit to indicate this class has Swift metadata.
+ auto bit = llvm::ConstantInt::get(IGM.IntPtrTy,
+ IGM.UseDarwinPreStableABIBit ? 1 : 2);
+ // Emit data + bit.
+ data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
+ data = llvm::ConstantExpr::getAdd(data, bit);
B.add(data);
}
@@ -3505,8 +3482,7 @@
auto classTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto loweredClassTy = IGF.IGM.getLoweredType(classTy);
emitInitializeFieldOffsetVector(IGF, loweredClassTy,
- metadata,
- /*vwtable=*/nullptr);
+ metadata, /*VWT is mutable*/ false);
// Realizing the class with the ObjC runtime will copy back to the
// field offset globals for us; but if ObjC interop is disabled, we
@@ -3923,10 +3899,6 @@
DependentMetaclassRODataPoint -= TemplateHeaderSize;
}
- void addDependentValueWitnessTablePattern() {
- llvm_unreachable("classes should never have dependent vwtables");
- }
-
void noteStartOfFieldOffsets(ClassDecl *whichClass) {}
void noteEndOfFieldOffsets(ClassDecl *whichClass) {}
@@ -3960,7 +3932,7 @@
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable) {
+ bool isVWTMutable) {
assert(!HasDependentVWT && "class should never have dependent VWT");
// Fill in the metaclass pointer.
@@ -4553,12 +4525,8 @@
SILType loweredType = IGF.IGM.getLoweredType(AbstractionPattern(type), type);
auto &ti = IGF.IGM.getTypeInfo(loweredType);
if (!ti.isFixedSize()) {
- // We assume that that value witness table will already have been written
- // into the metadata; just load it.
- llvm::Value *vwtable = IGF.emitValueWitnessTableRefForMetadata(metadata);
-
// Initialize the metadata.
- ti.initializeMetadata(IGF, metadata, vwtable, loweredType.getAddressType());
+ ti.initializeMetadata(IGF, metadata, true, loweredType.getAddressType());
}
return metadata;
@@ -4659,7 +4627,7 @@
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
- B.add(emitValueWitnessTable(IGM, type));
+ B.add(emitValueWitnessTable(IGM, type, false));
}
void createMetadataAccessFunction() {
@@ -4677,11 +4645,8 @@
CanType unboundType
= decl->getDeclaredType()->getCanonicalType();
- dependent = hasDependentValueWitnessTable(IGM, unboundType);
- if (dependent)
- return llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
- else
- return emitValueWitnessTable(IGM, unboundType);
+ dependent = hasDependentValueWitnessTable(IGM, unboundType);
+ return emitValueWitnessTable(IGM, unboundType, dependent);
}
/// A builder for metadata templates.
@@ -4712,18 +4677,13 @@
HasDependentVWT));
}
- void addDependentValueWitnessTablePattern() {
- emitDependentValueWitnessTablePattern(IGM, B,
- Target->getDeclaredType()->getCanonicalType());
- }
-
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable) {
+ bool isVWTMutable) {
// Nominal types are always preserved through SIL lowering.
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
IGM.getTypeInfoForUnlowered(structTy)
- .initializeMetadata(IGF, metadata, vwtable,
+ .initializeMetadata(IGF, metadata, isVWTMutable,
IGF.IGM.getLoweredType(structTy));
}
};
@@ -4814,7 +4774,7 @@
void addValueWitnessTable() {
auto type = Target->getDeclaredType()->getCanonicalType();
- B.add(emitValueWitnessTable(IGM, type));
+ B.add(emitValueWitnessTable(IGM, type, false));
}
void addPayloadSize() {
@@ -4862,11 +4822,6 @@
HasDependentVWT));
}
- void addDependentValueWitnessTablePattern() {
- emitDependentValueWitnessTablePattern(IGM, B,
- Target->getDeclaredType()->getCanonicalType());
- }
-
void addPayloadSize() {
// In all cases where a payload size is demanded in the metadata, it's
// runtime-dependent, so fill in a zero here.
@@ -4880,11 +4835,11 @@
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable) {
+ bool isVWTMutable) {
// Nominal types are always preserved through SIL lowering.
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
IGM.getTypeInfoForUnlowered(enumTy)
- .initializeMetadata(IGF, metadata, vwtable,
+ .initializeMetadata(IGF, metadata, isVWTMutable,
IGF.IGM.getLoweredType(enumTy));
}
};
@@ -5001,8 +4956,9 @@
void layout() {
if (asImpl().requiresInitializationFunction())
asImpl().addInitializationFunction();
+ else
+ asImpl().addPaddingForInitializationFunction();
asImpl().addForeignName();
- asImpl().addUniquePointer();
asImpl().addForeignFlags();
super::layout();
}
@@ -5015,11 +4971,8 @@
void addForeignName() {
CanType targetType = asImpl().getTargetType();
- B.add(getMangledTypeName(IGM, targetType));
- }
-
- void addUniquePointer() {
- B.addNullPointer(IGM.TypeMetadataPtrTy);
+ B.addRelativeAddress(getMangledTypeName(IGM, targetType,
+ /*relative addressed?*/ true));
}
void addInitializationFunction() {
@@ -5045,7 +4998,23 @@
IGF.Builder.CreateRetVoid();
- B.add(fn);
+ B.addRelativeAddress(fn);
+ }
+
+ void addPaddingForInitializationFunction() {
+ // The initialization function field is placed at the least offset of the
+ // record so it can be omitted when not needed. However, the metadata
+ // record is still pointer-aligned, so on 64 bit platforms we need to
+ // occupy the space to keep the rest of the record with the right layout.
+ switch (IGM.getPointerSize().getValue()) {
+ case 4:
+ break;
+ case 8:
+ B.addInt32(0);
+ break;
+ default:
+ llvm_unreachable("unsupported word size");
+ }
}
void noteAddressPoint() {
@@ -5127,7 +5096,7 @@
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
- B.add(emitValueWitnessTable(IGM, type));
+ B.add(emitValueWitnessTable(IGM, type, false));
}
void flagUnfilledFieldOffset() {
@@ -5156,7 +5125,7 @@
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
- B.add(emitValueWitnessTable(IGM, type));
+ B.add(emitValueWitnessTable(IGM, type, false));
}
void addPayloadSize() const {
diff --git a/lib/IRGen/GenMeta.h b/lib/IRGen/GenMeta.h
index 62af738..decfc83 100644
--- a/lib/IRGen/GenMeta.h
+++ b/lib/IRGen/GenMeta.h
@@ -258,7 +258,7 @@
void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
- llvm::Value *vwtable);
+ bool isVWTMutable);
/// Adjustment indices for the address points of various metadata.
/// Size is in words.
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index db8d946..902bcc7 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -323,19 +323,10 @@
// The Self type is abstract, so we can fulfill its metadata from
// the Self metadata parameter.
addSelfMetadataFulfillment(selfTy);
- } else {
- // If the Self type is concrete, we have a witness thunk with a
- // fully substituted Self type. The witness table parameter is not
- // used.
- //
- // FIXME: As above, we should fulfill the Self metadata and
- // conformance from our two special paramaters here. However, the
- // Self metadata will be inexact.
- //
- // For now, just fulfill the generic arguments of 'Self'.
- considerType(selfTy, IsInexact, Sources.size() - 1, MetadataPath());
}
+ considerType(selfTy, IsInexact, Sources.size() - 1, MetadataPath());
+
// The witness table for the Self : P conformance can be
// fulfilled from the Self witness table parameter.
Sources.emplace_back(MetadataSource::Kind::SelfWitnessTable,
diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp
index c120fcf..92db298 100644
--- a/lib/IRGen/GenStruct.cpp
+++ b/lib/IRGen/GenStruct.cpp
@@ -512,9 +512,9 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
- emitInitializeFieldOffsetVector(IGF, T, metadata, vwtable);
+ emitInitializeFieldOffsetVector(IGF, T, metadata, isVWTMutable);
}
};
diff --git a/lib/IRGen/GenTuple.cpp b/lib/IRGen/GenTuple.cpp
index 5b2e96a..470ff9e 100644
--- a/lib/IRGen/GenTuple.cpp
+++ b/lib/IRGen/GenTuple.cpp
@@ -343,7 +343,7 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
// Tuple value witness tables are instantiated by the runtime along with
// their metadata. We should never try to initialize one in the compiler.
diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp
index 84247a4..c8cea57 100644
--- a/lib/IRGen/GenValueWitness.cpp
+++ b/lib/IRGen/GenValueWitness.cpp
@@ -1063,17 +1063,28 @@
/// Emit a value-witness table for the given type, which is assumed to
/// be non-dependent.
llvm::Constant *irgen::emitValueWitnessTable(IRGenModule &IGM,
- CanType abstractType) {
+ CanType abstractType,
+ bool isPattern) {
// We shouldn't emit global value witness tables for generic type instances.
assert(!isa<BoundGenericType>(abstractType) &&
"emitting VWT for generic instance");
+ // We should never be making a pattern if the layout isn't fixed.
+ // The reverse can be true for types whose layout depends on
+ // resilient types.
+ assert((!isPattern || hasDependentValueWitnessTable(IGM, abstractType)) &&
+ "emitting VWT pattern for fixed-layout type");
+
ConstantInitBuilder builder(IGM);
auto witnesses = builder.beginArray(IGM.Int8PtrTy);
bool canBeConstant = false;
addValueWitnessesForAbstractType(IGM, witnesses, abstractType, canBeConstant);
+ // If this is just an instantiation pattern, we should never be modifying
+ // it in-place.
+ if (isPattern) canBeConstant = true;
+
auto addr = IGM.getAddrOfValueWitnessTable(abstractType,
witnesses.finishAndCreateFuture());
auto global = cast<llvm::GlobalVariable>(addr);
@@ -1163,25 +1174,6 @@
return layout;
}
-/// Emit the elements of a dependent value witness table template into a
-/// vector.
-void irgen::emitDependentValueWitnessTablePattern(IRGenModule &IGM,
- ConstantStructBuilder &B,
- CanType abstractType) {
- // We shouldn't emit global value witness tables for generic type instances.
- assert(!isa<BoundGenericType>(abstractType) &&
- "emitting VWT for generic instance");
-
- // We shouldn't emit global value witness tables for fixed-layout types.
- assert(hasDependentValueWitnessTable(IGM, abstractType) &&
- "emitting VWT pattern for fixed-layout type");
-
- bool canBeConstant = false;
- auto witnesses = B.beginArray(IGM.Int8PtrTy);
- addValueWitnessesForAbstractType(IGM, witnesses, abstractType, canBeConstant);
- witnesses.finishAndAddTo(B);
-}
-
FixedPacking TypeInfo::getFixedPacking(IRGenModule &IGM) const {
auto fixedTI = dyn_cast<FixedTypeInfo>(this);
diff --git a/lib/IRGen/GenValueWitness.h b/lib/IRGen/GenValueWitness.h
index db435a7..f12ca5d 100644
--- a/lib/IRGen/GenValueWitness.h
+++ b/lib/IRGen/GenValueWitness.h
@@ -37,16 +37,13 @@
/// dependent on its generic parameters.
bool hasDependentValueWitnessTable(IRGenModule &IGM, CanType ty);
- /// Emit a value-witness table for the given type, which is assumed
- /// to be non-dependent.
- llvm::Constant *emitValueWitnessTable(IRGenModule &IGM, CanType type);
-
- /// Emit the elements of a dependent value witness table template into a
- /// vector.
- void emitDependentValueWitnessTablePattern(IRGenModule &IGM,
- ConstantStructBuilder &B,
- CanType abstractType);
-
+ /// Emit a value-witness table for the given type.
+ ///
+ /// \param isPattern - true if the table just serves as an instantiation
+ /// pattern and does not need to be modifiable in-place (if the type
+ /// does not have static layout for some reason)
+ llvm::Constant *emitValueWitnessTable(IRGenModule &IGM, CanType type,
+ bool isPattern);
}
}
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 3da9183..201ec05 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -134,6 +134,7 @@
OutputFilename(OutputFilename),
TargetInfo(SwiftTargetInfo::get(*this)), DebugInfo(nullptr),
ModuleHash(nullptr), ObjCInterop(Context.LangOpts.EnableObjCInterop),
+ UseDarwinPreStableABIBit(Context.LangOpts.UseDarwinPreStableABIBit),
Types(*new TypeConverter(*this)) {
irgen.addGenModule(SF, this);
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 73ef85b..cebf099 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -413,6 +413,9 @@
/// Does the current target require Objective-C interoperation?
bool ObjCInterop = true;
+ /// Is the current target using the Darwin pre-stable ABI's class marker bit?
+ bool UseDarwinPreStableABIBit = true;
+
/// Should we add value names to local IR values?
bool EnableValueNames = false;
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index d91674d..5015f01 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -3754,13 +3754,32 @@
dbgname = getVarName(i, IsAnonymous);
# endif
- (void) Decl;
-
auto addr = type.allocateStack(*this, i->getElementType(), dbgname);
-
- emitDebugInfoForAllocStack(i, type, addr.getAddress().getAddress());
-
setLoweredStackAddress(i, addr);
+
+ // Generate Debug Info.
+ if (!Decl)
+ return;
+ emitDebugInfoForAllocStack(i, type, addr.getAddress().getAddress());
+
+ // To make it unambiguous whether a `var` binding has been initialized,
+ // zero-initialize the first pointer-sized field. LLDB uses this to
+ // recognize to detect uninitizialized variables. This can be removed once
+ // swiftc switches to @llvm.dbg.addr() intrinsics. This dead store will get
+ // optimized away when optimizations are enabled.
+ if (!Decl->getType()->getClassOrBoundGenericClass())
+ return;
+
+ auto *AI = dyn_cast<llvm::AllocaInst>(addr.getAddress().getAddress());
+ if (!AI)
+ return;
+
+ auto &DL = IGM.DataLayout;
+ if (DL.getTypeSizeInBits(AI->getAllocatedType()) < DL.getPointerSize())
+ return;
+ auto *BC = Builder.CreateBitCast(AI, IGM.OpaquePtrTy->getPointerTo());
+ Builder.CreateStore(llvm::ConstantPointerNull::get(IGM.OpaquePtrTy), BC,
+ IGM.getPointerAlignment());
}
static void
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index 5ad86c3..f707feb 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -36,9 +36,8 @@
using namespace swift;
using namespace swift::irgen;
-static GenericEnvironment *getGenericEnvironment(SILModule &Mod,
- CanSILFunctionType loweredTy) {
- return loweredTy->getGenericSignature()->createGenericEnvironment();
+static GenericEnvironment *getGenericEnvironment(CanSILFunctionType loweredTy) {
+ return loweredTy->getGenericSignature().getGenericEnvironment();
}
/// Utility to determine if this is a large loadable type
@@ -201,22 +200,16 @@
}
// Get the function type or the optional function type
-static SILFunctionType *getInnerFunctionType(SILType storageType) {
- CanType currCanType = storageType.getSwiftRValueType();
- if (SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer())) {
+static CanSILFunctionType getInnerFunctionType(SILType storageType) {
+ if (auto currSILFunctionType = storageType.getAs<SILFunctionType>()) {
return currSILFunctionType;
}
- OptionalTypeKind optKind;
- if (auto optionalType = currCanType.getAnyOptionalObjectType(optKind)) {
- assert(optKind != OptionalTypeKind::OTK_None &&
- "Expected Real Optional Type");
- if (auto *currSILFunctionType =
- dyn_cast<SILFunctionType>(optionalType.getPointer())) {
+ if (auto optionalType = storageType.getAnyOptionalObjectType()) {
+ if (auto currSILFunctionType = optionalType.getAs<SILFunctionType>()) {
return currSILFunctionType;
}
}
- return nullptr;
+ return CanSILFunctionType();
}
static SILType getNewOptionalFunctionType(GenericEnvironment *GenericEnv,
@@ -257,9 +250,6 @@
static bool modResultType(SILFunction *F, irgen::IRGenModule &Mod) {
GenericEnvironment *genEnv = F->getGenericEnvironment();
auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
- }
return shouldTransformResults(genEnv, loweredTy, Mod);
}
@@ -545,10 +535,6 @@
return visitInstr(applySite.getInstruction());
}
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
- auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
for (Operand &operand : applySite.getArgumentOperands()) {
SILValue currOperand = operand.get();
SILType silType = currOperand->getType();
@@ -573,10 +559,6 @@
// Check callee - need new generic env:
CanSILFunctionType origSILFunctionType = applySite.getSubstCalleeType();
GenericEnvironment *genEnvCallee = nullptr;
- if (origSILFunctionType->isPolymorphic()) {
- genEnvCallee = getGenericEnvironment(
- applySite.getModule(), CanSILFunctionType(origSILFunctionType));
- }
auto newSILFunctionType =
getNewSILFunctionType(genEnvCallee, origSILFunctionType, pass.Mod);
if (origSILFunctionType != newSILFunctionType) {
@@ -608,10 +590,8 @@
GenericEnvironment *genEnv = nullptr;
if (fnType->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(), fnType);
+ genEnv = getGenericEnvironment(fnType);
}
- Lowering::GenericContextScope GenericScope(
- instr->getModule().Types, fnType->getGenericSignature());
if (shouldTransformFunctionType(genEnv, fnType, pass.Mod)) {
pass.methodInstsToMod.push_back(instr);
return;
@@ -633,9 +613,11 @@
auto *F = arg->getFunction();
SILType storageType = arg->getType();
GenericEnvironment *genEnv = F->getGenericEnvironment();
- auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
+ CanType currCanType = storageType.getSwiftRValueType();
+ if (auto funcType = dyn_cast<SILFunctionType>(currCanType)) {
+ if (funcType->isPolymorphic()) {
+ genEnv = getGenericEnvironment(funcType);
+ }
}
SILType newSILType = getNewSILType(genEnv, storageType, Mod);
// We (currently) only care about function signatures
@@ -716,10 +698,6 @@
void LargeValueVisitor::visitResultTyInst(SingleValueInstruction *instr) {
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
- auto loweredTy = instr->getFunction()->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(), loweredTy);
- }
SILType currSILType = instr->getType().getObjectType();
SILType newSILType = getNewSILType(genEnv, currSILType, pass.Mod);
if (currSILType != newSILType) {
@@ -735,12 +713,10 @@
void LargeValueVisitor::visitTupleInst(SingleValueInstruction *instr) {
SILType currSILType = instr->getType().getObjectType();
- CanType currCanType = currSILType.getSwiftRValueType();
- if (auto funcType = dyn_cast<SILFunctionType>(currCanType)) {
- CanSILFunctionType canFuncType = CanSILFunctionType(funcType);
+ if (auto funcType = currSILType.getAs<SILFunctionType>()) {
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
- if (!genEnv && canFuncType->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(), canFuncType);
+ if (!genEnv && funcType->isPolymorphic()) {
+ genEnv = getGenericEnvironment(funcType);
}
auto newSILFunctionType =
getNewSILFunctionType(genEnv, funcType, pass.Mod);
@@ -785,10 +761,6 @@
static bool modNonFuncTypeResultType(SILFunction *F, irgen::IRGenModule &Mod) {
GenericEnvironment *genEnv = F->getGenericEnvironment();
auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
- }
-
return modNonFuncTypeResultType(genEnv, loweredTy, Mod);
}
@@ -967,12 +939,6 @@
SILType currType = unoptimizableLoad->getType().getObjectType();
GenericEnvironment *genEnv =
unoptimizableLoad->getFunction()->getGenericEnvironment();
- auto loweredTy =
- unoptimizableLoad->getFunction()->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv =
- getGenericEnvironment(unoptimizableLoad->getModule(), loweredTy);
- }
SILType newSILType = getNewSILType(genEnv, currType, Mod);
if (currType == newSILType) {
break;
@@ -1027,10 +993,6 @@
SILType currType = unoptimizableLoad->getType().getObjectType();
GenericEnvironment *genEnv =
userIns->getFunction()->getGenericEnvironment();
- auto loweredTy = userIns->getFunction()->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(userIns->getModule(), loweredTy);
- }
SILType newSILType = getNewSILType(genEnv, currType, pass.Mod);
if (currType == newSILType) {
break;
@@ -1150,9 +1112,6 @@
void LoadableStorageAllocation::insertIndirectReturnArgs() {
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
auto singleResult = loweredTy->getSingleResult();
SILType resultStorageType = singleResult.getSILStorageType();
auto canType = resultStorageType.getSwiftRValueType();
@@ -1177,10 +1136,6 @@
SILBuilderWithScope argBuilder(entry->begin());
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
- auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
for (SILArgument *arg : entry->getArguments()) {
SILType storageType = arg->getType();
@@ -1220,7 +1175,6 @@
}
void LoadableStorageAllocation::convertApplyResults() {
- auto &silModue = pass.F->getModule();
for (auto &BB : *pass.F) {
for (auto &II : BB) {
auto *currIns = &II;
@@ -1235,12 +1189,7 @@
continue;
}
CanSILFunctionType origSILFunctionType = applySite.getSubstCalleeType();
- Lowering::GenericContextScope GenericScope(
- silModue.Types, origSILFunctionType->getGenericSignature());
GenericEnvironment *genEnv = nullptr;
- if (origSILFunctionType->isPolymorphic()) {
- genEnv = getGenericEnvironment(silModue, origSILFunctionType);
- }
if (!shouldTransformResults(genEnv, origSILFunctionType, pass.Mod)) {
continue;
}
@@ -1248,14 +1197,12 @@
auto resultStorageType = singleResult.getSILStorageType();
if (!isLargeLoadableType(genEnv, resultStorageType, pass.Mod)) {
// Make sure it is a function type
- auto canType = resultStorageType.getSwiftRValueType();
- if (!isa<SILFunctionType>(canType)) {
- // Check if it is an optional funciton type
- OptionalTypeKind optKind;
- auto optionalType = canType.getAnyOptionalObjectType(optKind);
+ if (!resultStorageType.is<SILFunctionType>()) {
+ // Check if it is an optional function type
+ auto optionalType = resultStorageType.getAnyOptionalObjectType();
assert(optionalType &&
"Expected SILFunctionType or Optional for the result type");
- assert(dyn_cast<SILFunctionType>(optionalType.getPointer()) &&
+ assert(optionalType.is<SILFunctionType>() &&
"Expected a SILFunctionType inside the optional Type");
}
continue;
@@ -1288,10 +1235,6 @@
for (SILArgument *arg : entry->getArguments()) {
SILType storageType = arg->getType();
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
- auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
SILType newSILType = getNewSILType(genEnv, storageType, pass.Mod);
if (!isLargeLoadableType(genEnv, storageType, pass.Mod) &&
(newSILType != storageType)) {
@@ -1307,10 +1250,6 @@
void LoadableStorageAllocation::convertIndirectBasicBlockArgs() {
SILBasicBlock *entry = pass.F->getEntryBlock();
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
- auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
for (SILBasicBlock &BB : *pass.F) {
if (&BB == entry) {
// Already took care of function args
@@ -1570,10 +1509,6 @@
SILType currType = instr->getType().getObjectType();
GenericEnvironment *genEnv =
instr->getFunction()->getGenericEnvironment();
- auto loweredTy = instr->getFunction()->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(), loweredTy);
- }
SILType newSILType = getNewSILType(genEnv, currType, Mod);
if (currType == newSILType) {
allUsesAreReplaceable = false;
@@ -1596,7 +1531,7 @@
auto funcType = currSILType.castTo<SILFunctionType>();
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
if (!genEnv && funcType->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(), funcType);
+ genEnv = getGenericEnvironment(funcType);
}
auto newFnType = getNewSILFunctionType(genEnv, funcType, Mod);
SILType newSILType =
@@ -1667,10 +1602,7 @@
LoadableStorageAllocation &allocator) {
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
- auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
+
bool repeat = false;
llvm::SetVector<SILInstruction *> currentModApplies;
do {
@@ -1713,9 +1645,7 @@
loadArg->setOperand(newArg);
// If the load is of a function type - do not replace it.
- auto loadedType = loadArg->getType();
- auto canLoadedType = loadedType.getSwiftRValueType();
- if (dyn_cast<SILFunctionType>(canLoadedType.getPointer())) {
+ if (loadArg->getType().is<SILFunctionType>()) {
continue;
}
@@ -1757,9 +1687,7 @@
instr->getParent()->erase(instr);
// If the load is of a function type - do not replace it.
- auto loadedType = loadArg->getType();
- auto canLoadedType = loadedType.getSwiftRValueType();
- if (dyn_cast<SILFunctionType>(canLoadedType.getPointer())) {
+ if (loadArg->getType().is<SILFunctionType>()) {
continue;
}
@@ -1789,9 +1717,7 @@
allocateAndSetForArgumentOperand(pass, currOperand, applyInst);
} else if (auto *load = dyn_cast<LoadInst>(currOperandInstr)) {
// If the load is of a function type - do not replace it.
- auto loadedType = load->getType();
- auto canLoadedType = loadedType.getSwiftRValueType();
- if (dyn_cast<SILFunctionType>(canLoadedType.getPointer())) {
+ if (load->getType().is<SILFunctionType>()) {
continue;
}
@@ -1978,8 +1904,7 @@
auto currSILFunctionType = currSILType.castTo<SILFunctionType>();
GenericEnvironment *genEnvForMethod = nullptr;
if (currSILFunctionType->isPolymorphic()) {
- genEnvForMethod = getGenericEnvironment(
- instr->getModule(), CanSILFunctionType(currSILFunctionType));
+ genEnvForMethod = getGenericEnvironment(currSILFunctionType);
}
SILType newSILType = SILType::getPrimitiveObjectType(
getNewSILFunctionType(genEnvForMethod, currSILFunctionType, pass.Mod));
@@ -2068,9 +1993,6 @@
static bool rewriteFunctionReturn(StructLoweringState &pass) {
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
auto loweredTy = pass.F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(pass.F->getModule(), loweredTy);
- }
SILFunction *F = pass.F;
SILType resultTy = loweredTy->getAllResultsType();
SILType newSILType = getNewSILType(genEnv, resultTy, pass.Mod);
@@ -2100,8 +2022,7 @@
void LoadableByAddress::runOnFunction(SILFunction *F) {
CanSILFunctionType funcType = F->getLoweredFunctionType();
IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule(F);
- Lowering::GenericContextScope GenericScope(getModule()->Types,
- funcType->getGenericSignature());
+
if (F->isExternalDeclaration()) {
if (!modifiableFunction(funcType)) {
return;
@@ -2110,9 +2031,9 @@
GenericEnvironment *genEnv = F->getGenericEnvironment();
auto loweredTy = F->getLoweredFunctionType();
if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
+ genEnv = getGenericEnvironment(loweredTy);
}
- if (shouldTransformFunctionType(genEnv, F->getLoweredFunctionType(),
+ if (shouldTransformFunctionType(genEnv, loweredTy,
*currIRMod)) {
modFuncs.insert(F);
}
@@ -2159,11 +2080,10 @@
IRGenModule &Mod, SILBuilder &builder) {
SILType currSILType = op->getType();
if (auto funcType = currSILType.getAs<SILFunctionType>()) {
- CanSILFunctionType canFuncType = CanSILFunctionType(funcType);
GenericEnvironment *genEnv =
containingInstr->getFunction()->getGenericEnvironment();
- if (!genEnv && canFuncType->isPolymorphic()) {
- genEnv = getGenericEnvironment(containingInstr->getModule(), canFuncType);
+ if (!genEnv && funcType->isPolymorphic()) {
+ genEnv = getGenericEnvironment(funcType);
}
auto newFnType = getNewSILFunctionType(genEnv, funcType, Mod);
SILType newSILType = SILType::getPrimitiveObjectType(newFnType);
@@ -2186,25 +2106,6 @@
return op;
}
-static SmallVector<Substitution, 4>
-getNewSubs(SubstitutionList origSubs, swift::irgen::IRGenModule *currIRMod,
- swift::GenericEnvironment *genEnv) {
- SmallVector<Substitution, 4> newSubs;
- for (auto sub : origSubs) {
- Type origType = sub.getReplacement();
- CanType origCanType = origType->getCanonicalType();
- if (!origCanType->isLegalSILType()) {
- newSubs.push_back(sub);
- continue;
- }
- SILType origSILType = SILType::getPrimitiveObjectType(origCanType);
- SILType newSILType = getNewSILType(genEnv, origSILType, *currIRMod);
- Type newType = newSILType.getSwiftRValueType()->getRValueType();
- newSubs.push_back(Substitution(newType, sub.getConformances()));
- }
- return newSubs;
-}
-
void LoadableByAddress::recreateSingleApply(SILInstruction *applyInst) {
auto *F = applyInst->getFunction();
IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule(F);
@@ -2221,18 +2122,10 @@
}
}
CanSILFunctionType origSILFunctionType = applySite.getSubstCalleeType();
- auto origCanType = CanSILFunctionType(origSILFunctionType);
- Lowering::GenericContextScope GenericScope(
- getModule()->Types, origCanType->getGenericSignature());
GenericEnvironment *genEnv = nullptr;
- if (origSILFunctionType->isPolymorphic()) {
- genEnv = getGenericEnvironment(applyInst->getModule(),
- CanSILFunctionType(origSILFunctionType));
- }
CanSILFunctionType newSILFunctionType =
getNewSILFunctionType(genEnv, origSILFunctionType, *currIRMod);
- CanSILFunctionType newCanSILFuncType(newSILFunctionType);
- SILFunctionConventions newSILFunctionConventions(newCanSILFuncType,
+ SILFunctionConventions newSILFunctionConventions(newSILFunctionType,
*getModule());
SmallVector<SILValue, 8> callArgs;
SILBuilderWithScope applyBuilder(applyInst);
@@ -2240,15 +2133,14 @@
// Find the new alloc we created earlier.
// and pass it as first parameter:
if (applyInst->getKind() != SILInstructionKind::PartialApplyInst &&
- modNonFuncTypeResultType(genEnv, origCanType, *currIRMod) &&
+ modNonFuncTypeResultType(genEnv, origSILFunctionType, *currIRMod) &&
modifiableApply(applySite, *getIRGenModule())) {
assert(allApplyRetToAllocMap.find(applyInst) !=
allApplyRetToAllocMap.end());
auto newAlloc = allApplyRetToAllocMap.find(applyInst)->second;
callArgs.push_back(newAlloc);
}
- SmallVector<Substitution, 4> newSubs =
- getNewSubs(applySite.getSubstitutions(), currIRMod, genEnv);
+
// Collect arg operands
for (Operand &operand : applySite.getArgumentOperands()) {
SILValue currOperand = operand.get();
@@ -2261,7 +2153,8 @@
case SILInstructionKind::ApplyInst: {
auto *castedApply = cast<ApplyInst>(applyInst);
SILValue newApply =
- applyBuilder.createApply(castedApply->getLoc(), callee, newSubs,
+ applyBuilder.createApply(castedApply->getLoc(), callee,
+ applySite.getSubstitutions(),
callArgs, castedApply->isNonThrowing());
castedApply->replaceAllUsesWith(newApply);
break;
@@ -2269,7 +2162,8 @@
case SILInstructionKind::TryApplyInst: {
auto *castedApply = cast<TryApplyInst>(applyInst);
applyBuilder.createTryApply(
- castedApply->getLoc(), callee, newSubs, callArgs,
+ castedApply->getLoc(), callee,
+ applySite.getSubstitutions(), callArgs,
castedApply->getNormalBB(), castedApply->getErrorBB());
break;
}
@@ -2277,13 +2171,12 @@
auto *castedApply = cast<PartialApplyInst>(applyInst);
// Change the type of the Closure
auto partialApplyConvention = castedApply->getType()
- .getSwiftRValueType()
- ->getAs<SILFunctionType>()
+ .getAs<SILFunctionType>()
->getCalleeConvention();
auto newApply =
applyBuilder.createPartialApply(castedApply->getLoc(), callee,
- newSubs, callArgs,
+ applySite.getSubstitutions(), callArgs,
partialApplyConvention);
castedApply->replaceAllUsesWith(newApply);
break;
@@ -2320,16 +2213,9 @@
for (auto *enumInstr : uncheckedEnumDataOfFunc) {
SILBuilderWithScope enumBuilder(enumInstr);
SILFunction *F = enumInstr->getFunction();
- CanSILFunctionType funcType = F->getLoweredFunctionType();
IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule(F);
- Lowering::GenericContextScope GenericScope(getModule()->Types,
- funcType->getGenericSignature());
SILType origType = enumInstr->getType();
GenericEnvironment *genEnv = F->getGenericEnvironment();
- auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
- }
SILType newType = getNewSILType(genEnv, origType, *currIRMod);
auto caseTy = enumInstr->getOperand()->getType().getEnumElementType(
enumInstr->getElement(), F->getModule());
@@ -2354,16 +2240,9 @@
for (auto *enumInstr : uncheckedTakeEnumDataAddrOfFunc) {
SILBuilderWithScope enumBuilder(enumInstr);
SILFunction *F = enumInstr->getFunction();
- CanSILFunctionType funcType = F->getLoweredFunctionType();
IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule(F);
- Lowering::GenericContextScope GenericScope(getModule()->Types,
- funcType->getGenericSignature());
SILType origType = enumInstr->getType();
GenericEnvironment *genEnv = F->getGenericEnvironment();
- auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
- }
SILType newType = getNewSILType(genEnv, origType, *currIRMod);
auto caseTy = enumInstr->getOperand()->getType().getEnumElementType(
enumInstr->getElement(), F->getModule());
@@ -2410,15 +2289,8 @@
currSILType = thinToPointer->getOperand()->getType();
}
auto currSILFunctionType = currSILType.castTo<SILFunctionType>();
- Lowering::GenericContextScope GenericScope(
- getModule()->Types,
- currSILFunctionType->getGenericSignature());
GenericEnvironment *genEnv =
convInstr->getFunction()->getGenericEnvironment();
- auto loweredTy = convInstr->getFunction()->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(convInstr->getModule(), loweredTy);
- }
CanSILFunctionType newFnType =
getNewSILFunctionType(genEnv, currSILFunctionType, *currIRMod);
SILType newType = SILType::getPrimitiveObjectType(newFnType);
@@ -2458,14 +2330,8 @@
getIRGenModule()->IRGen.getGenModule(builtinInstr->getFunction());
auto *F = builtinInstr->getFunction();
GenericEnvironment *genEnv = F->getGenericEnvironment();
- auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
- }
auto resultTy = builtinInstr->getType();
auto newResultTy = getNewSILType(genEnv, resultTy, *currIRMod);
- auto newSubs =
- getNewSubs(builtinInstr->getSubstitutions(), currIRMod, genEnv);
llvm::SmallVector<SILValue, 5> newArgs;
for (auto oldArg : builtinInstr->getArguments()) {
@@ -2474,7 +2340,8 @@
SILBuilderWithScope builtinBuilder(builtinInstr);
auto *newInstr = builtinBuilder.createBuiltin(
- builtinInstr->getLoc(), builtinInstr->getName(), newResultTy, newSubs,
+ builtinInstr->getLoc(), builtinInstr->getName(), newResultTy,
+ builtinInstr->getSubstitutions(),
newArgs);
builtinInstr->replaceAllUsesWith(newInstr);
builtinInstr->getParent()->erase(builtinInstr);
@@ -2484,12 +2351,9 @@
void LoadableByAddress::updateLoweredTypes(SILFunction *F) {
IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule(F);
CanSILFunctionType funcType = F->getLoweredFunctionType();
- Lowering::GenericContextScope GenericScope(getModule()->Types,
- funcType->getGenericSignature());
GenericEnvironment *genEnv = F->getGenericEnvironment();
- auto loweredTy = F->getLoweredFunctionType();
- if (!genEnv && loweredTy->isPolymorphic()) {
- genEnv = getGenericEnvironment(F->getModule(), loweredTy);
+ if (!genEnv && funcType->isPolymorphic()) {
+ genEnv = getGenericEnvironment(funcType);
}
auto newFuncTy = getNewSILFunctionType(genEnv, funcType, *currIRMod);
F->rewriteLoweredTypeUnsafe(newFuncTy);
@@ -2557,40 +2421,39 @@
} else if (auto *CFI = dyn_cast<ConvertFunctionInst>(&I)) {
SILValue val = CFI->getConverted();
SILType currType = val->getType();
- CanType currCanType = currType.getSwiftRValueType();
- auto *fType = dyn_cast<SILFunctionType>(currCanType.getPointer());
+ auto fType = currType.getAs<SILFunctionType>();
assert(fType && "Expected SILFunctionType");
- if (modifiableFunction(CanSILFunctionType(fType))) {
+ if (modifiableFunction(fType)) {
conversionInstrs.insert(CFI);
}
} else if (auto *TTI = dyn_cast<ThinToThickFunctionInst>(&I)) {
- CanType canType = TTI->getCallee()->getType().getSwiftRValueType();
- auto *fType = canType->castTo<SILFunctionType>();
+ auto canType = TTI->getCallee()->getType();
+ auto fType = canType.castTo<SILFunctionType>();
- if (modifiableFunction(CanSILFunctionType(fType)))
+ if (modifiableFunction(fType))
conversionInstrs.insert(TTI);
} else if (auto *LI = dyn_cast<LoadInst>(&I)) {
SILType currType = LI->getType();
- if (auto *fType = getInnerFunctionType(currType)) {
- if (modifiableFunction(CanSILFunctionType(fType))) {
+ if (auto fType = getInnerFunctionType(currType)) {
+ if (modifiableFunction(fType)) {
// need to re-create these loads: re-write type cache
loadInstrsOfFunc.insert(LI);
}
}
} else if (auto *UED = dyn_cast<UncheckedEnumDataInst>(&I)) {
SILType currType = UED->getType();
- if (auto *fType = getInnerFunctionType(currType)) {
- if (modifiableFunction(CanSILFunctionType(fType))) {
+ if (auto fType = getInnerFunctionType(currType)) {
+ if (modifiableFunction(fType)) {
// need to re-create these loads: re-write type cache
uncheckedEnumDataOfFunc.insert(UED);
}
}
} else if (auto *UED = dyn_cast<UncheckedTakeEnumDataAddrInst>(&I)) {
SILType currType = UED->getType();
- if (auto *fType = getInnerFunctionType(currType)) {
- if (modifiableFunction(CanSILFunctionType(fType))) {
+ if (auto fType = getInnerFunctionType(currType)) {
+ if (modifiableFunction(fType)) {
// need to re-create these loads: re-write type cache
uncheckedTakeEnumDataAddrOfFunc.insert(UED);
}
diff --git a/lib/IRGen/ResilientTypeInfo.h b/lib/IRGen/ResilientTypeInfo.h
index 7edc2d9..0cd02c1 100644
--- a/lib/IRGen/ResilientTypeInfo.h
+++ b/lib/IRGen/ResilientTypeInfo.h
@@ -157,7 +157,7 @@
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const override {
// Resilient value types and archetypes always refer to an existing type.
// A witness table should never be independently initialized for one.
diff --git a/lib/IRGen/TypeInfo.h b/lib/IRGen/TypeInfo.h
index e1370f2..907bb89 100644
--- a/lib/IRGen/TypeInfo.h
+++ b/lib/IRGen/TypeInfo.h
@@ -392,7 +392,7 @@
/// for fixed-size types.
virtual void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
- llvm::Value *vwtable,
+ bool isVWTMutable,
SILType T) const = 0;
/// Get the tag of a single payload enum with a payload of this type (\p T) e.g
diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp
index 92c478d..60871f3 100644
--- a/lib/Parse/Lexer.cpp
+++ b/lib/Parse/Lexer.cpp
@@ -2119,6 +2119,8 @@
case '\n':
case '\r':
+ assert(TriviaRetention != TriviaRetentionMode::WithTrivia &&
+ "newlines should be eaten by lexTrivia as LeadingTrivia");
NextToken.setAtStartOfLine(true);
goto Restart; // Skip whitespace.
@@ -2287,7 +2289,7 @@
return L.peekNextToken();
}
-void Lexer::lexTrivia(syntax::TriviaList &Pieces, bool IsForTrailingTrivia) {
+void Lexer::lexTrivia(syntax::Trivia &Pieces, bool IsForTrailingTrivia) {
if (TriviaRetention == TriviaRetentionMode::WithoutTrivia)
return;
@@ -2298,46 +2300,34 @@
// TODO: Handle invalid UTF8 sequence which is skipped in lexImpl().
switch (*CurPtr++) {
case '\n':
+ if (IsForTrailingTrivia)
+ break;
+ NextToken.setAtStartOfLine(true);
+ Pieces.appendOrSquash(TriviaPiece::newlines(1));
+ goto Restart;
case '\r':
if (IsForTrailingTrivia)
break;
NextToken.setAtStartOfLine(true);
- LLVM_FALLTHROUGH;
- case ' ':
- case '\t':
- case '\v':
- case '\f': {
- auto Char = CurPtr[-1];
- // Consume consective same characters.
- while (*CurPtr == Char)
+ if (CurPtr[0] == '\n') {
+ Pieces.appendOrSquash(TriviaPiece::carriageReturnLineFeeds(1));
++CurPtr;
-
- auto Length = CurPtr - TriviaStart;
- switch (Char) {
- case ' ':
- Pieces.push_back(TriviaPiece::spaces(Length));
- break;
- case '\n':
- // FIXME: CR+LF shoud form one trivia piece
- Pieces.push_back(TriviaPiece::newlines(Length));
- break;
- case '\r':
- Pieces.push_back(TriviaPiece::carriageReturns(Length));
- break;
- case '\t':
- Pieces.push_back(TriviaPiece::tabs(Length));
- break;
- case '\v':
- Pieces.push_back(TriviaPiece::verticalTabs(Length));
- break;
- case '\f':
- Pieces.push_back(TriviaPiece::formfeeds(Length));
- break;
- default:
- llvm_unreachable("Invalid character for whitespace trivia");
+ } else {
+ Pieces.appendOrSquash(TriviaPiece::carriageReturns(1));
}
goto Restart;
- }
+ case ' ':
+ Pieces.appendOrSquash(TriviaPiece::spaces(1));
+ goto Restart;
+ case '\t':
+ Pieces.appendOrSquash(TriviaPiece::tabs(1));
+ goto Restart;
+ case '\v':
+ Pieces.appendOrSquash(TriviaPiece::verticalTabs(1));
+ goto Restart;
+ case '\f':
+ Pieces.appendOrSquash(TriviaPiece::formfeeds(1));
+ goto Restart;
case '/':
if (IsForTrailingTrivia || isKeepingComments()) {
// Don't lex comments as trailing trivias (for now).
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 96333bd..d391b9c 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3789,6 +3789,10 @@
// Properties in protocols use sufficiently limited syntax that we have a
// special parsing loop for them. SIL mode uses the same syntax.
if (Flags.contains(PD_InProtocol) || isInSILMode()) {
+ if (Tok.is(tok::r_brace)) {
+ // Give syntax node an empty statement list.
+ SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+ }
while (Tok.isNot(tok::r_brace)) {
if (Tok.is(tok::eof))
return true;
@@ -3863,13 +3867,14 @@
return false;
}
-
// Otherwise, we have a normal var or subscript declaration, parse the full
// complement of specifiers, along with their bodies.
// If the body is completely empty, preserve it. This is at best a getter with
// an implicit fallthrough off the end.
if (Tok.is(tok::r_brace)) {
+ // Give syntax node an empty statement list.
+ SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
diagnose(Tok, diag::computed_property_no_accessors);
return true;
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 01ea2c7..7a49db4 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -57,6 +57,7 @@
return makeParserCodeCompletionResult<Expr>();
if (pattern.isNull())
return nullptr;
+ SyntaxContext->setCreateSyntax(SyntaxKind::UnresolvedPatternExpr);
return makeParserResult(new (Context) UnresolvedPatternExpr(pattern.get()));
}
@@ -1211,8 +1212,8 @@
SmallVector<TypeLoc, 8> locArgs;
for (auto ty : args)
locArgs.push_back(ty);
- Result = makeParserResult(new (Context) UnresolvedSpecializeExpr(
- Result.get(), LAngleLoc, Context.AllocateCopy(locArgs), RAngleLoc));
+ Result = makeParserResult(UnresolvedSpecializeExpr::create(Context,
+ Result.get(), LAngleLoc, locArgs, RAngleLoc));
}
continue;
@@ -1546,6 +1547,13 @@
? VarDecl::Specifier::Let
: VarDecl::Specifier::Var;
auto pattern = createBindingFromPattern(loc, name, specifier);
+ if (SyntaxContext->isEnabled()) {
+ PatternSyntax PatternNode =
+ SyntaxFactory::makeIdentifierPattern(SyntaxContext->popToken());
+ ExprSyntax ExprNode =
+ SyntaxFactory::makeUnresolvedPatternExpr(PatternNode);
+ SyntaxContext->addSyntax(ExprNode);
+ }
Result = makeParserResult(new (Context) UnresolvedPatternExpr(pattern));
break;
}
@@ -2207,9 +2215,8 @@
SmallVector<TypeLoc, 8> locArgs;
for (auto ty : args)
locArgs.push_back(ty);
- E = new (Context) UnresolvedSpecializeExpr(E, LAngleLoc,
- Context.AllocateCopy(locArgs),
- RAngleLoc);
+ E = UnresolvedSpecializeExpr::create(Context, E, LAngleLoc, locArgs,
+ RAngleLoc);
}
return E;
}
@@ -2780,8 +2787,7 @@
// If the closure includes a capture list, create an AST node for it as well.
Expr *result = closure;
if (!captureList.empty())
- result = new (Context) CaptureListExpr(Context.AllocateCopy(captureList),
- closure);
+ result = CaptureListExpr::create(Context, captureList, closure);
return makeParserResult(Status, result);
}
diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp
index 7d1e365..59d05ee 100644
--- a/lib/Parse/ParsePattern.cpp
+++ b/lib/Parse/ParsePattern.cpp
@@ -848,6 +848,7 @@
return parsePatternTuple();
case tok::kw__:
+ PatternCtx.setCreateSyntax(SyntaxKind::WildcardPattern);
return makeParserResult(new (Context) AnyPattern(consumeToken(tok::kw__)));
case tok::identifier: {
@@ -874,6 +875,7 @@
case tok::kw_var:
case tok::kw_let: {
+ PatternCtx.setCreateSyntax(SyntaxKind::ValueBindingPattern);
bool isLet = Tok.is(tok::kw_let);
SourceLoc varLoc = consumeToken();
@@ -956,6 +958,8 @@
/// pattern-tuple-body:
/// pattern-tuple-element (',' pattern-tuple-body)*
ParserResult<Pattern> Parser::parsePatternTuple() {
+ SyntaxParsingContext TuplePatternCtxt(SyntaxContext,
+ SyntaxKind::TuplePattern);
StructureMarkerRAII ParsingPatternTuple(*this, Tok);
SourceLoc LPLoc = consumeToken(tok::l_paren);
SourceLoc RPLoc;
@@ -966,7 +970,7 @@
parseList(tok::r_paren, LPLoc, RPLoc,
/*AllowSepAfterLast=*/false,
diag::expected_rparen_tuple_pattern_list,
- SyntaxKind::Unknown,
+ SyntaxKind::TuplePatternElementList,
[&] () -> ParserStatus {
// Parse the pattern tuple element.
ParserStatus EltStatus;
@@ -994,10 +998,13 @@
ParserResult<Pattern> Parser::
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
bool isOptional) {
+ if (!Tok.is(tok::colon))
+ return result;
// Parse an optional type annotation.
- if (!consumeIf(tok::colon))
- return result;
+ SyntaxParsingContext TypeAnnotationCtxt(SyntaxContext,
+ SyntaxKind::TypeAnnotation);
+ consumeToken(tok::colon);
Pattern *P;
if (result.isNull())
@@ -1032,9 +1039,11 @@
// parse pattern nodes for productions shared by pattern and expression
// grammar. For short-term ease of initial implementation, we always go
// through the expr parser for ambiguous productions.
+ SyntaxParsingContext PatternCtx(SyntaxContext, SyntaxContextKind::Pattern);
// Parse productions that can only be patterns.
if (Tok.isAny(tok::kw_var, tok::kw_let)) {
+ PatternCtx.setCreateSyntax(SyntaxKind::ValueBindingPattern);
assert(Tok.isAny(tok::kw_let, tok::kw_var) && "expects var or let");
bool isLet = Tok.is(tok::kw_let);
SourceLoc varLoc = consumeToken();
@@ -1044,6 +1053,7 @@
// matching-pattern ::= 'is' type
if (Tok.is(tok::kw_is)) {
+ PatternCtx.setCreateSyntax(SyntaxKind::IsTypePattern);
SourceLoc isLoc = consumeToken(tok::kw_is);
ParserResult<TypeRepr> castType = parseType();
if (castType.isNull() || castType.hasCodeCompletion())
@@ -1062,7 +1072,14 @@
return makeParserCodeCompletionStatus();
if (subExpr.isNull())
return nullptr;
-
+
+ if (SyntaxContext->isEnabled()) {
+ if (auto UPES = PatternCtx.popIf<UnresolvedPatternExprSyntax>()) {
+ PatternCtx.addSyntax(UPES->getPattern());
+ } else {
+ PatternCtx.setCreateSyntax(SyntaxKind::ExpressionPattern);
+ }
+ }
// The most common case here is to parse something that was a lexically
// obvious pattern, which will come back wrapped in an immediate
// UnresolvedPatternExpr. Transform this now to simplify later code.
@@ -1148,4 +1165,3 @@
return canParseType();
return true;
}
-
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 9a685c6..131218d 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -569,12 +569,15 @@
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
return parseStmtContinue();
- case tok::kw_fallthrough:
+ case tok::kw_fallthrough: {
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
+
+ SyntaxContext->setCreateSyntax(SyntaxKind::FallthroughStmt);
return makeParserResult(
new (Context) FallthroughStmt(consumeToken(tok::kw_fallthrough)));
}
+ }
}
/// parseBraceItemList - A brace enclosed expression/statement/decl list. For
@@ -615,6 +618,7 @@
/// 'break' identifier?
///
ParserResult<Stmt> Parser::parseStmtBreak() {
+ SyntaxContext->setCreateSyntax(SyntaxKind::BreakStmt);
SourceLoc Loc = consumeToken(tok::kw_break);
SourceLoc TargetLoc;
Identifier Target;
@@ -637,6 +641,7 @@
/// 'continue' identifier?
///
ParserResult<Stmt> Parser::parseStmtContinue() {
+ SyntaxContext->setCreateSyntax(SyntaxKind::ContinueStmt);
SourceLoc Loc = consumeToken(tok::kw_continue);
SourceLoc TargetLoc;
Identifier Target;
@@ -660,7 +665,7 @@
/// 'return' expr?
///
ParserResult<Stmt> Parser::parseStmtReturn(SourceLoc tryLoc) {
- SyntaxParsingContext LocalContext(SyntaxContext, SyntaxKind::ReturnStmt);
+ SyntaxContext->setCreateSyntax(SyntaxKind::ReturnStmt);
SourceLoc ReturnLoc = consumeToken(tok::kw_return);
if (Tok.is(tok::code_complete)) {
@@ -725,6 +730,7 @@
/// 'throw' expr
///
ParserResult<Stmt> Parser::parseStmtThrow(SourceLoc tryLoc) {
+ SyntaxContext->setCreateSyntax(SyntaxKind::ThrowStmt);
SourceLoc throwLoc = consumeToken(tok::kw_throw);
SourceLoc exprLoc;
if (Tok.isNot(tok::eof))
@@ -759,6 +765,7 @@
/// 'defer' brace-stmt
///
ParserResult<Stmt> Parser::parseStmtDefer() {
+ SyntaxContext->setCreateSyntax(SyntaxKind::DeferStmt);
SourceLoc DeferLoc = consumeToken(tok::kw_defer);
// Macro expand out the defer into a closure and call, which we can typecheck
@@ -991,7 +998,10 @@
VD->setHasNonPatternBindingInit();
// Parse the optional 'where' guard.
- if (P.consumeIf(tok::kw_where, result.WhereLoc)) {
+ if (P.Tok.is(tok::kw_where)) {
+ SyntaxParsingContext WhereClauseCtxt(P.SyntaxContext,
+ SyntaxKind::WhereClause);
+ result.WhereLoc = P.consumeToken(tok::kw_where);
SourceLoc startOfGuard = P.Tok.getLoc();
auto diagKind = [=]() -> Diag<> {
@@ -1073,6 +1083,8 @@
// #available(...)
ParserResult<PoundAvailableInfo> Parser::parseStmtConditionPoundAvailable() {
+ SyntaxParsingContext ConditonCtxt(SyntaxContext,
+ SyntaxKind::AvailabilityCondition);
SourceLoc PoundLoc = consumeToken(tok::pound_available);
if (!Tok.isFollowingLParen()) {
@@ -1184,6 +1196,175 @@
return Status;
}
+ParserStatus
+Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
+ Diag<> DefaultID, StmtKind ParentKind,
+ StringRef &BindingKindStr) {
+ ParserStatus Status;
+
+ // Parse a leading #available condition if present.
+ if (Tok.is(tok::pound_available)) {
+ auto res = parseStmtConditionPoundAvailable();
+ if (res.isNull() || res.hasCodeCompletion()) {
+ Status |= res;
+ return Status;
+ }
+ BindingKindStr = StringRef();
+ result.push_back({res.get()});
+ return Status;
+ }
+
+ // Handle code completion after the #.
+ if (Tok.is(tok::pound) && peekToken().is(tok::code_complete)) {
+ consumeToken(); // '#' token.
+ auto CodeCompletionPos = consumeToken();
+ auto Expr = new (Context) CodeCompletionExpr(CodeCompletionPos);
+ if (CodeCompletion)
+ CodeCompletion->completeAfterPound(Expr, ParentKind);
+ result.push_back(Expr);
+ Status.setHasCodeCompletion();
+ return Status;
+ }
+
+ // Parse the basic expression case. If we have a leading let/var/case
+ // keyword or an assignment, then we know this is a binding.
+ if (Tok.isNot(tok::kw_let, tok::kw_var, tok::kw_case)) {
+ // If we lack it, then this is theoretically a boolean condition.
+ // However, we also need to handle migrating from Swift 2 syntax, in
+ // which a comma followed by an expression could actually be a pattern
+ // clause followed by a binding. Determine what we have by checking for a
+ // syntactically valid pattern followed by an '=', which can never be a
+ // boolean condition.
+ //
+ // However, if this is the first clause, and we see "x = y", then this is
+ // almost certainly a typo for '==' and definitely not a continuation of
+ // another clause, so parse it as an expression. This also avoids
+ // lookahead + backtracking on simple if conditions that are obviously
+ // boolean conditions.
+ auto isBooleanExpr = [&]() -> bool {
+ Parser::BacktrackingScope Backtrack(*this);
+ return !canParseTypedPattern() || Tok.isNot(tok::equal);
+ };
+
+ if (BindingKindStr.empty() || isBooleanExpr()) {
+ auto diagID = result.empty() ? DefaultID :
+ diag::expected_expr_conditional;
+ auto BoolExpr = parseExprBasic(diagID);
+ Status |= BoolExpr;
+ if (BoolExpr.isNull())
+ return Status;
+ result.push_back(BoolExpr.get());
+ BindingKindStr = StringRef();
+ return Status;
+ }
+ }
+
+ SyntaxParsingContext ConditionCtxt(SyntaxContext);
+
+ SourceLoc IntroducerLoc;
+ if (Tok.isAny(tok::kw_let, tok::kw_var, tok::kw_case)) {
+ BindingKindStr = Tok.getText();
+ IntroducerLoc = consumeToken();
+ } else {
+ // If we lack the leading let/var/case keyword, then we're here because
+ // the user wrote something like "if let x = foo(), y = bar() {". Fix
+ // this by inserting a new 'let' keyword before y.
+ IntroducerLoc = Tok.getLoc();
+ assert(!BindingKindStr.empty() &&
+ "Shouldn't get here without a leading binding");
+ diagnose(Tok.getLoc(), diag::expected_binding_keyword, BindingKindStr)
+ .fixItInsert(Tok.getLoc(), BindingKindStr.str()+" ");
+ }
+
+ // We're parsing a conditional binding.
+ assert(CurDeclContext->isLocalContext() &&
+ "conditional binding in non-local context?!");
+
+ ParserResult<Pattern> ThePattern;
+
+ if (BindingKindStr == "case") {
+ ConditionCtxt.setCreateSyntax(SyntaxKind::MatchingPatternCondition);
+ // In our recursive parse, remember that we're in a matching pattern.
+ llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
+ T(InVarOrLetPattern, IVOLP_InMatchingPattern);
+ ThePattern = parseMatchingPattern(/*isExprBasic*/ true);
+ } else if ((BindingKindStr == "let" || BindingKindStr == "var") &&
+ Tok.is(tok::kw_case)) {
+ ConditionCtxt.setCreateSyntax(SyntaxKind::Unknown);
+ // If will probably be a common typo to write "if let case" instead of
+ // "if case let" so detect this and produce a nice fixit.
+ diagnose(IntroducerLoc, diag::wrong_condition_case_location,
+ BindingKindStr)
+ .fixItRemove(IntroducerLoc)
+ .fixItInsertAfter(Tok.getLoc(), " " + BindingKindStr.str());
+
+ consumeToken(tok::kw_case);
+
+ bool wasLet = BindingKindStr == "let";
+
+ // In our recursive parse, remember that we're in a var/let pattern.
+ llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
+ T(InVarOrLetPattern, wasLet ? IVOLP_InLet : IVOLP_InVar);
+
+ BindingKindStr = "case";
+ ThePattern = parseMatchingPattern(/*isExprBasic*/ true);
+
+ if (ThePattern.isNonNull()) {
+ auto *P = new (Context) VarPattern(IntroducerLoc, wasLet,
+ ThePattern.get(), /*impl*/false);
+ ThePattern = makeParserResult(P);
+ }
+
+ } else {
+ ConditionCtxt.setCreateSyntax(SyntaxKind::OptionalBindingCondition);
+ // Otherwise, this is an implicit optional binding "if let".
+ ThePattern = parseMatchingPatternAsLetOrVar(BindingKindStr == "let",
+ IntroducerLoc,
+ /*isExprBasic*/ true);
+ // The let/var pattern is part of the statement.
+ if (Pattern *P = ThePattern.getPtrOrNull())
+ P->setImplicit();
+ }
+
+ ThePattern = parseOptionalPatternTypeAnnotation(ThePattern,
+ BindingKindStr != "case");
+ Status |= ThePattern;
+
+ if (ThePattern.isNull() || ThePattern.hasCodeCompletion())
+ return Status;
+
+ // Conditional bindings must have an initializer.
+ Expr *Init;
+ if (Tok.is(tok::equal)) {
+ SyntaxParsingContext InitCtxt(SyntaxContext, SyntaxKind::InitializerClause);
+ consumeToken();
+ ParserResult<Expr> InitExpr
+ = parseExprBasic(diag::expected_expr_conditional_var);
+ Status |= InitExpr;
+ if (InitExpr.isNull())
+ return Status;
+ Init = InitExpr.get();
+
+ } else {
+ // Although we require an initializer, recover by parsing as if it were
+ // merely omitted.
+ diagnose(Tok, diag::conditional_var_initializer_required);
+ Init = new (Context) ErrorExpr(ThePattern.get()->getEndLoc());
+ }
+
+ result.push_back({IntroducerLoc, ThePattern.get(), Init});
+ IntroducerLoc = SourceLoc();
+
+ // Add variable bindings from the pattern to our current scope and mark
+ // them as being having a non-pattern-binding initializer.
+ ThePattern.get()->forEachVariable([&](VarDecl *VD) {
+ if (VD->hasName())
+ addToScope(VD);
+ VD->setHasNonPatternBindingInit();
+ });
+ return Status;
+}
+
/// Parse the condition of an 'if' or 'while'.
///
/// condition:
@@ -1198,16 +1379,32 @@
///
ParserStatus Parser::parseStmtCondition(StmtCondition &Condition,
Diag<> DefaultID, StmtKind ParentKind) {
+ SyntaxParsingContext ConditionListCtxt(SyntaxContext,
+ SyntaxKind::ConditionElementList);
ParserStatus Status;
Condition = StmtCondition();
SmallVector<StmtConditionElement, 4> result;
- // This little helper function is used to consume a separator comma if
- // present, it returns false if it isn't there. It also gracefully handles
- // the case when the user used && instead of comma, since that is a common
- // error.
- auto consumeSeparatorComma = [&]() -> bool {
+ // For error recovery purposes, keep track of the disposition of the last
+ // pattern binding we saw ('let', 'var', or 'case').
+ StringRef BindingKindStr;
+
+ // We have a simple comma separated list of clauses, but also need to handle
+ // a variety of common errors situations (including migrating from Swift 2
+ // syntax).
+ while (true) {
+ SyntaxParsingContext ConditionElementCtxt(SyntaxContext,
+ SyntaxKind::ConditionElement);
+ Status |= parseStmtConditionElement(result, DefaultID, ParentKind,
+ BindingKindStr);
+ if (Status.shouldStopParsing())
+ break;
+
+ // If a comma exists consume it and succeed.
+ if (consumeIf(tok::comma))
+ continue;
+
// If we have an "&&" token followed by a continuation of the statement
// condition, then fixit the "&&" to "," and keep going.
if (Tok.isAny(tok::oper_binary_spaced, tok::oper_binary_unspaced) &&
@@ -1215,7 +1412,7 @@
diagnose(Tok, diag::expected_comma_stmtcondition)
.fixItReplaceChars(getEndOfPreviousLoc(), Tok.getRange().getEnd(), ",");
consumeToken();
- return true;
+ continue;
}
// Boolean conditions are separated by commas, not the 'where' keyword, as
@@ -1224,182 +1421,11 @@
diagnose(Tok, diag::expected_comma_stmtcondition)
.fixItReplaceChars(getEndOfPreviousLoc(), Tok.getRange().getEnd(), ",");
consumeToken();
- return true;
- }
-
- // Otherwise, if a comma exists consume it and succeed.
- return consumeIf(tok::comma);
- };
-
-
- // For error recovery purposes, keep track of the disposition of the last
- // pattern binding we saw ('let', 'var', or 'case').
- StringRef BindingKindStr;
-
- // We have a simple comma separated list of clauses, but also need to handle
- // a variety of common errors situations (including migrating from Swift 2
- // syntax).
- bool isFirstIteration = true;
- while (isFirstIteration || consumeSeparatorComma()) {
- isFirstIteration = false;
-
- // Parse a leading #available condition if present.
- if (Tok.is(tok::pound_available)) {
- auto res = parseStmtConditionPoundAvailable();
- if (res.isNull() || res.hasCodeCompletion()) {
- Status |= res;
- return Status;
- }
-
- result.push_back({res.get()});
- BindingKindStr = StringRef();
continue;
}
- // Handle code completion after the #.
- if (Tok.is(tok::pound) && peekToken().is(tok::code_complete)) {
- consumeToken(); // '#' token.
- auto CodeCompletionPos = consumeToken();
- auto Expr = new (Context) CodeCompletionExpr(CodeCompletionPos);
- if (CodeCompletion)
- CodeCompletion->completeAfterPound(Expr, ParentKind);
- result.push_back(Expr);
- Status.setHasCodeCompletion();
- return Status;
- }
-
- // Parse the basic expression case. If we have a leading let/var/case
- // keyword or an assignment, then we know this is a binding.
- if (Tok.isNot(tok::kw_let, tok::kw_var, tok::kw_case)) {
- // If we lack it, then this is theoretically a boolean condition.
- // However, we also need to handle migrating from Swift 2 syntax, in
- // which a comma followed by an expression could actually be a pattern
- // clause followed by a binding. Determine what we have by checking for a
- // syntactically valid pattern followed by an '=', which can never be a
- // boolean condition.
- //
- // However, if this is the first clause, and we see "x = y", then this is
- // almost certainly a typo for '==' and definitely not a continuation of
- // another clause, so parse it as an expression. This also avoids
- // lookahead + backtracking on simple if conditions that are obviously
- // boolean conditions.
- auto isBooleanExpr = [&]() -> bool {
- Parser::BacktrackingScope Backtrack(*this);
- return !canParseTypedPattern() || Tok.isNot(tok::equal);
- };
-
- if (BindingKindStr.empty() || isBooleanExpr()) {
- auto diagID = result.empty() ? DefaultID :
- diag::expected_expr_conditional;
- auto BoolExpr = parseExprBasic(diagID);
- Status |= BoolExpr;
- if (BoolExpr.isNull())
- return Status;
- result.push_back(BoolExpr.get());
- BindingKindStr = StringRef();
- continue;
- }
- }
-
- SourceLoc IntroducerLoc;
- if (Tok.isAny(tok::kw_let, tok::kw_var, tok::kw_case)) {
- BindingKindStr = Tok.getText();
- IntroducerLoc = consumeToken();
- } else {
- // If we lack the leading let/var/case keyword, then we're here because
- // the user wrote something like "if let x = foo(), y = bar() {". Fix
- // this by inserting a new 'let' keyword before y.
- IntroducerLoc = Tok.getLoc();
- assert(!BindingKindStr.empty() &&
- "Shouldn't get here without a leading binding");
- diagnose(Tok.getLoc(), diag::expected_binding_keyword, BindingKindStr)
- .fixItInsert(Tok.getLoc(), BindingKindStr.str()+" ");
- }
-
-
- // We're parsing a conditional binding.
- assert(CurDeclContext->isLocalContext() &&
- "conditional binding in non-local context?!");
-
- ParserResult<Pattern> ThePattern;
-
- if (BindingKindStr == "case") {
- // In our recursive parse, remember that we're in a matching pattern.
- llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
- T(InVarOrLetPattern, IVOLP_InMatchingPattern);
- ThePattern = parseMatchingPattern(/*isExprBasic*/ true);
- } else if ((BindingKindStr == "let" || BindingKindStr == "var") &&
- Tok.is(tok::kw_case)) {
- // If will probably be a common typo to write "if let case" instead of
- // "if case let" so detect this and produce a nice fixit.
- diagnose(IntroducerLoc, diag::wrong_condition_case_location,
- BindingKindStr)
- .fixItRemove(IntroducerLoc)
- .fixItInsertAfter(Tok.getLoc(), " " + BindingKindStr.str());
-
- consumeToken(tok::kw_case);
-
- bool wasLet = BindingKindStr == "let";
-
- // In our recursive parse, remember that we're in a var/let pattern.
- llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
- T(InVarOrLetPattern, wasLet ? IVOLP_InLet : IVOLP_InVar);
-
- BindingKindStr = "case";
- ThePattern = parseMatchingPattern(/*isExprBasic*/ true);
-
- if (ThePattern.isNonNull()) {
- auto *P = new (Context) VarPattern(IntroducerLoc, wasLet,
- ThePattern.get(), /*impl*/false);
- ThePattern = makeParserResult(P);
- }
-
- } else {
- // Otherwise, this is an implicit optional binding "if let".
- ThePattern = parseMatchingPatternAsLetOrVar(BindingKindStr == "let",
- IntroducerLoc,
- /*isExprBasic*/ true);
- // The let/var pattern is part of the statement.
- if (Pattern *P = ThePattern.getPtrOrNull())
- P->setImplicit();
- }
-
- ThePattern = parseOptionalPatternTypeAnnotation(ThePattern,
- BindingKindStr != "case");
- Status |= ThePattern;
-
- if (ThePattern.isNull() || ThePattern.hasCodeCompletion())
- return Status;
-
- // Conditional bindings must have an initializer.
- Expr *Init;
- if (consumeIf(tok::equal)) {
- ParserResult<Expr> InitExpr
- = parseExprBasic(diag::expected_expr_conditional_var);
- Status |= InitExpr;
- if (InitExpr.isNull())
- return Status;
- Init = InitExpr.get();
-
- } else {
- // Although we require an initializer, recover by parsing as if it were
- // merely omitted.
- diagnose(Tok, diag::conditional_var_initializer_required);
- Init = new (Context) ErrorExpr(ThePattern.get()->getEndLoc());
- }
-
- result.push_back({IntroducerLoc, ThePattern.get(), Init});
- IntroducerLoc = SourceLoc();
-
- // Add variable bindings from the pattern to our current scope and mark
- // them as being having a non-pattern-binding initializer.
- ThePattern.get()->forEachVariable([&](VarDecl *VD) {
- if (VD->hasName())
- addToScope(VD);
- VD->setHasNonPatternBindingInit();
- });
-
- } while (consumeSeparatorComma());
+ break;
+ };
Condition = Context.AllocateCopy(result);
return Status;
@@ -1412,6 +1438,7 @@
/// 'else' stmt-brace
/// 'else' stmt-if
ParserResult<Stmt> Parser::parseStmtIf(LabeledStmtInfo LabelInfo) {
+ SyntaxContext->setCreateSyntax(SyntaxKind::IfStmt);
SourceLoc IfLoc = consumeToken(tok::kw_if);
ParserStatus Status;
@@ -1472,10 +1499,12 @@
ParserResult<Stmt> ElseBody;
if (Tok.is(tok::kw_else)) {
ElseLoc = consumeToken(tok::kw_else);
- if (Tok.is(tok::kw_if))
+ if (Tok.is(tok::kw_if)) {
+ SyntaxParsingContext ElseIfCtxt(SyntaxContext, SyntaxKind::IfStmt);
ElseBody = parseStmtIf(LabeledStmtInfo());
- else
+ } else {
ElseBody = parseBraceItemList(diag::expected_lbrace_after_else);
+ }
Status |= ElseBody;
}
@@ -1489,6 +1518,7 @@
/// 'guard' condition 'else' stmt-brace
///
ParserResult<Stmt> Parser::parseStmtGuard() {
+ SyntaxContext->setCreateSyntax(SyntaxKind::GuardStmt);
SourceLoc GuardLoc = consumeToken(tok::kw_guard);
ParserStatus Status;
@@ -1615,6 +1645,7 @@
/// stmt-repeat:
/// (identifier ':')? 'repeat' stmt-brace 'while' expr
ParserResult<Stmt> Parser::parseStmtRepeat(LabeledStmtInfo labelInfo) {
+ SyntaxContext->setCreateSyntax(SyntaxKind::RepeatWhileStmt);
SourceLoc repeatLoc = consumeToken(tok::kw_repeat);
ParserStatus status;
@@ -1658,6 +1689,7 @@
/// (identifier ':')? 'do' stmt-brace
/// (identifier ':')? 'do' stmt-brace stmt-catch+
ParserResult<Stmt> Parser::parseStmtDo(LabeledStmtInfo labelInfo) {
+ SyntaxContext->setCreateSyntax(SyntaxKind::DoStmt);
SourceLoc doLoc = consumeToken(tok::kw_do);
ParserStatus status;
@@ -1671,6 +1703,8 @@
// If the next token is 'catch', this is a 'do'/'catch' statement.
if (Tok.is(tok::kw_catch)) {
+ SyntaxParsingContext CatchListCtxt(SyntaxContext,
+ SyntaxKind::CatchClauseList);
// Parse 'catch' clauses
SmallVector<CatchStmt*, 4> allClauses;
do {
@@ -1736,6 +1770,7 @@
/// This routine promises to return a non-null result unless there was
/// a code-completion token in the pattern.
ParserResult<CatchStmt> Parser::parseStmtCatch() {
+ SyntaxParsingContext CatchClauseCtxt(SyntaxContext, SyntaxKind::CatchClause);
// A catch block has its own scope for variables bound out of the pattern.
Scope S(this, ScopeKind::CatchVars);
@@ -1799,6 +1834,7 @@
/// (identifier ':')? 'for' pattern 'in' expr-basic \
/// ('where' expr-basic)? stmt-brace
ParserResult<Stmt> Parser::parseStmtForEach(LabeledStmtInfo LabelInfo) {
+ SyntaxContext->setCreateSyntax(SyntaxKind::ForInStmt);
SourceLoc ForLoc = consumeToken(tok::kw_for);
ParserStatus Status;
ParserResult<Pattern> pattern;
@@ -1894,7 +1930,10 @@
// Parse the 'where' expression if present.
ParserResult<Expr> Where;
- if (consumeIf(tok::kw_where)) {
+ if (Tok.is(tok::kw_where)) {
+ SyntaxParsingContext WhereClauseCtxt(SyntaxContext,
+ SyntaxKind::WhereClause);
+ consumeToken();
Where = parseExprBasic(diag::expected_foreach_where_expr);
if (Where.isNull())
Where = makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc()));
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 70d52bb..f09cf19 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -845,6 +845,8 @@
return SyntaxKind::FunctionParameter;
case SyntaxKind::TupleTypeElementList:
return SyntaxKind::TupleTypeElement;
+ case SyntaxKind::TuplePatternElementList:
+ return SyntaxKind::TuplePatternElement;
default:
return SyntaxKind::Unknown;
}
diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp
index 43f9a26..8dc3d5b 100644
--- a/lib/SIL/SILBuilder.cpp
+++ b/lib/SIL/SILBuilder.cpp
@@ -417,8 +417,9 @@
while (I && I->getNumOperands() == 1 &&
I->getNumTypeDependentOperands() == 0) {
- // All the open instructions are single-value instructions.
- auto SVI = dyn_cast<SingleValueInstruction>(I->getOperand(0));
+ // All the open instructions are single-value instructions. Operands may
+ // be null when code is being transformed.
+ auto SVI = dyn_cast_or_null<SingleValueInstruction>(I->getOperand(0));
// Within SimplifyCFG this function may be called for an instruction
// within unreachable code. And within an unreachable block it can happen
// that defs do not dominate uses (because there is no dominance defined).
diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp
index 7d00386..d5a0e78 100644
--- a/lib/SIL/SILInstructions.cpp
+++ b/lib/SIL/SILInstructions.cpp
@@ -373,11 +373,9 @@
SubstitutionList Substitutions,
ArrayRef<SILValue> Args,
SILModule &M) {
- void *Buffer = M.allocateInst(
- sizeof(BuiltinInst)
- + decltype(Operands)::getExtraSize(Args.size())
- + sizeof(Substitution) * Substitutions.size(),
- alignof(BuiltinInst));
+ auto Size = totalSizeToAlloc<swift::Operand, Substitution>(Args.size(),
+ Substitutions.size());
+ auto Buffer = M.allocateInst(Size, alignof(BuiltinInst));
return ::new (Buffer) BuiltinInst(Loc, Name, ReturnType, Substitutions,
Args);
}
@@ -385,12 +383,17 @@
BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name,
SILType ReturnType, SubstitutionList Subs,
ArrayRef<SILValue> Args)
- : InstructionBase(Loc, ReturnType), Name(Name),
- NumSubstitutions(Subs.size()), Operands(this, Args) {
- static_assert(IsTriviallyCopyable<Substitution>::value,
- "assuming Substitution is trivially copyable");
- memcpy(getSubstitutionsStorage(), Subs.begin(),
- sizeof(Substitution) * Subs.size());
+ : InstructionBase(Loc, ReturnType), Name(Name) {
+ SILInstruction::Bits.BuiltinInst.NumSubstitutions = Subs.size();
+ assert(SILInstruction::Bits.BuiltinInst.NumSubstitutions == Subs.size() &&
+ "Truncation");
+ SILInstruction::Bits.BuiltinInst.NumOperands = Args.size();
+ Operand *dynamicSlot = getTrailingObjects<Operand>();
+ for (auto value : Args) {
+ new (dynamicSlot++) Operand(this, value);
+ }
+ std::uninitialized_copy(Subs.begin(), Subs.end(),
+ getTrailingObjects<Substitution>());
}
InitBlockStorageHeaderInst *
@@ -736,8 +739,9 @@
StringLiteralInst::StringLiteralInst(SILDebugLocation Loc, StringRef Text,
Encoding encoding, SILType Ty)
- : InstructionBase(Loc, Ty), Length(Text.size()),
- TheEncoding(encoding) {
+ : InstructionBase(Loc, Ty) {
+ SILInstruction::Bits.StringLiteralInst.TheEncoding = unsigned(encoding);
+ SILInstruction::Bits.StringLiteralInst.Length = Text.size();
memcpy(getTrailingObjects<char>(), Text.data(), Text.size());
}
@@ -752,16 +756,18 @@
}
uint64_t StringLiteralInst::getCodeUnitCount() {
- if (TheEncoding == Encoding::UTF16)
+ auto E = unsigned(Encoding::UTF16);
+ if (SILInstruction::Bits.StringLiteralInst.TheEncoding == E)
return unicode::getUTF16Length(getValue());
- return Length;
+ return SILInstruction::Bits.StringLiteralInst.Length;
}
ConstStringLiteralInst::ConstStringLiteralInst(SILDebugLocation Loc,
StringRef Text,
Encoding encoding, SILType Ty)
- : InstructionBase(Loc, Ty),
- Length(Text.size()), TheEncoding(encoding) {
+ : InstructionBase(Loc, Ty) {
+ SILInstruction::Bits.ConstStringLiteralInst.TheEncoding = unsigned(encoding);
+ SILInstruction::Bits.ConstStringLiteralInst.Length = Text.size();
memcpy(getTrailingObjects<char>(), Text.data(), Text.size());
}
@@ -777,9 +783,10 @@
}
uint64_t ConstStringLiteralInst::getCodeUnitCount() {
- if (TheEncoding == Encoding::UTF16)
+ auto E = unsigned(Encoding::UTF16);
+ if (SILInstruction::Bits.ConstStringLiteralInst.TheEncoding == E)
return unicode::getUTF16Length(getValue());
- return Length;
+ return SILInstruction::Bits.ConstStringLiteralInst.Length;
}
StoreInst::StoreInst(
@@ -902,15 +909,19 @@
StructInst *StructInst::create(SILDebugLocation Loc, SILType Ty,
ArrayRef<SILValue> Elements, SILModule &M) {
- void *Buffer = M.allocateInst(sizeof(StructInst) +
- decltype(Operands)::getExtraSize(Elements.size()),
- alignof(StructInst));
+ auto Size = totalSizeToAlloc<swift::Operand>(Elements.size());
+ auto Buffer = M.allocateInst(Size, alignof(StructInst));
return ::new(Buffer) StructInst(Loc, Ty, Elements);
}
StructInst::StructInst(SILDebugLocation Loc, SILType Ty,
ArrayRef<SILValue> Elems)
- : InstructionBase(Loc, Ty), Operands(this, Elems) {
+ : InstructionBase(Loc, Ty) {
+ SILInstruction::Bits.StructInst.NumOperands = Elems.size();
+ Operand *dynamicSlot = getTrailingObjects<Operand>();
+ for (auto value : Elems) {
+ new (dynamicSlot++) Operand(this, value);
+ }
assert(!Ty.getStructOrBoundGenericStruct()->hasUnreferenceableStorage());
}
@@ -930,15 +941,20 @@
TupleInst *TupleInst::create(SILDebugLocation Loc, SILType Ty,
ArrayRef<SILValue> Elements, SILModule &M) {
- void *Buffer = M.allocateInst(sizeof(TupleInst) +
- decltype(Operands)::getExtraSize(Elements.size()),
- alignof(TupleInst));
+ auto Size = totalSizeToAlloc<swift::Operand>(Elements.size());
+ auto Buffer = M.allocateInst(Size, alignof(TupleInst));
return ::new(Buffer) TupleInst(Loc, Ty, Elements);
}
TupleInst::TupleInst(SILDebugLocation Loc, SILType Ty,
ArrayRef<SILValue> Elems)
- : InstructionBase(Loc, Ty), Operands(this, Elems) {}
+ : InstructionBase(Loc, Ty) {
+ SILInstruction::Bits.TupleInst.NumOperands = Elems.size();
+ Operand *dynamicSlot = getTrailingObjects<Operand>();
+ for (auto value : Elems) {
+ new (dynamicSlot++) Operand(this, value);
+ }
+}
MetatypeInst::MetatypeInst(SILDebugLocation Loc, SILType Metatype,
ArrayRef<SILValue> TypeDependentOperands)
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 0a9af39..b644ab7 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -104,6 +104,7 @@
DEF_COL(ID::SILUndef, RED)
DEF_COL(ID::SILBasicBlock, GREEN)
DEF_COL(ID::SSAValue, MAGENTA)
+ DEF_COL(ID::Null, YELLOW)
}
OS.resetColor();
OS.changeColor(Color);
@@ -128,6 +129,7 @@
return;
case ID::SILBasicBlock: OS << "bb"; break;
case ID::SSAValue: OS << '%'; break;
+ case ID::Null: OS << "<<NULL OPERAND>>"; return;
}
OS << Number;
}
@@ -509,10 +511,10 @@
}
SILValuePrinterInfo getIDAndType(SILValue V) {
- return {Ctx.getID(V), V->getType()};
+ return {Ctx.getID(V), V ? V->getType() : SILType()};
}
SILValuePrinterInfo getIDAndTypeAndOwnership(SILValue V) {
- return {Ctx.getID(V), V->getType(), V.getOwnershipKind()};
+ return {Ctx.getID(V), V ? V->getType() : SILType(), V.getOwnershipKind()};
}
//===--------------------------------------------------------------------===//
@@ -1081,7 +1083,11 @@
interleave(AI->getArguments(),
[&](const SILValue &arg) { *this << Ctx.getID(arg); },
[&] { *this << ", "; });
- *this << ") : " << AI->getCallee()->getType();
+ *this << ") : ";
+ if (auto callee = AI->getCallee())
+ *this << callee->getType();
+ else
+ *this << "<<NULL CALLEE>>";
}
void visitApplyInst(ApplyInst *AI) {
@@ -2975,6 +2981,9 @@
}
ID SILPrintContext::getID(const SILNode *node) {
+ if (node == nullptr)
+ return {ID::Null, ~0U};
+
if (isa<SILUndef>(node))
return {ID::SILUndef, 0};
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index e508a2d..2c4d895 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -4975,16 +4975,14 @@
}
// Create the tuple shuffle.
- ArrayRef<int> mapping = tc.Context.AllocateCopy(sources);
- auto callerDefaultArgsCopy = tc.Context.AllocateCopy(callerDefaultArgs);
return
- cs.cacheType(new (tc.Context) TupleShuffleExpr(
- expr, mapping,
+ cs.cacheType(TupleShuffleExpr::create(tc.Context,
+ expr, sources,
TupleShuffleExpr::TupleToTuple,
callee,
- tc.Context.AllocateCopy(variadicArgs),
+ variadicArgs,
arrayType,
- callerDefaultArgsCopy,
+ callerDefaultArgs,
toSugarType));
}
@@ -5073,13 +5071,13 @@
Type destSugarTy = hasInit? toTuple
: TupleType::get(sugarFields, tc.Context);
- return cs.cacheType(new (tc.Context) TupleShuffleExpr(expr,
- tc.Context.AllocateCopy(elements),
+ return cs.cacheType(TupleShuffleExpr::create(tc.Context, expr,
+ elements,
TupleShuffleExpr::ScalarToTuple,
callee,
- tc.Context.AllocateCopy(variadicArgs),
+ variadicArgs,
arrayType,
- tc.Context.AllocateCopy(callerDefaultArgs),
+ callerDefaultArgs,
destSugarTy));
}
@@ -5215,8 +5213,8 @@
new (ctx) OpaqueValueExpr(expr->getLoc(),
fromType));
- auto *result =
- cs.cacheType(new (ctx) ErasureExpr(archetypeVal, toType, conformances));
+ auto *result = cs.cacheType(ErasureExpr::create(ctx, archetypeVal, toType,
+ conformances));
return cs.cacheType(
new (ctx) OpenExistentialExpr(expr, archetypeVal, result,
cs.getType(result)));
@@ -5238,7 +5236,7 @@
}
}
- return cs.cacheType(new (ctx) ErasureExpr(expr, toType, conformances));
+ return cs.cacheType(ErasureExpr::create(ctx, expr, toType, conformances));
}
/// Given that the given expression is an implicit conversion added
@@ -5704,17 +5702,10 @@
}
// Create the tuple shuffle.
- ArrayRef<int> mapping = tc.Context.AllocateCopy(sources);
- auto callerDefaultArgsCopy = tc.Context.AllocateCopy(callerDefaultArgs);
- return
- cs.cacheType(new (tc.Context) TupleShuffleExpr(
- arg, mapping,
- typeImpact,
- callee,
- tc.Context.AllocateCopy(variadicArgs),
- sliceType,
- callerDefaultArgsCopy,
- paramType));
+ return cs.cacheType(TupleShuffleExpr::create(tc.Context, arg, sources,
+ typeImpact, callee, variadicArgs,
+ sliceType, callerDefaultArgs,
+ paramType));
}
static ClosureExpr *getClosureLiteralExpr(Expr *expr) {
diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h
index b8f3794..23a3bbd 100644
--- a/lib/Sema/ConstraintLocator.h
+++ b/lib/Sema/ConstraintLocator.h
@@ -231,8 +231,6 @@
llvm_unreachable("Unhandled PathElementKind in switch.");
}
- template<unsigned N> struct incomplete;
-
/// \brief One element in the path of a locator, which can include both
/// a kind (PathElementKind) and a value used to describe specific
/// kinds further (e.g., the position of a tuple element).
diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp
index 7a6bbea..d5b6ab6 100644
--- a/lib/Sema/DerivedConformanceEquatableHashable.cpp
+++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp
@@ -745,34 +745,34 @@
return integerExpr;
}
-/// Returns a new assignment expression that mixes the hash value of an
+/// Returns a new assignment expression that combines the hash value of an
/// expression into a variable.
/// \p C The AST context.
-/// \p resultVar The variable into which the hash value will be mixed.
-/// \p exprToHash The expression whose hash value should be mixed in.
-/// \return The expression that mixes the hash value into the result variable.
-static Expr* mixInHashExpr_hashValue(ASTContext &C,
- VarDecl* resultVar,
- Expr *exprToHash) {
+/// \p resultVar The variable into which the hash value will be combined.
+/// \p exprToHash The expression whose hash value should be combined.
+/// \return The expression that combines the hash value into the variable.
+static Expr* combineHashValuesAssignmentExpr(ASTContext &C,
+ VarDecl* resultVar,
+ Expr *exprToHash) {
// <exprToHash>.hashValue
auto hashValueExpr = new (C) UnresolvedDotExpr(exprToHash, SourceLoc(),
C.Id_hashValue, DeclNameLoc(),
/*implicit*/ true);
- // _mixForSynthesizedHashValue(result, <exprToHash>.hashValue)
- auto mixinFunc = C.getMixForSynthesizedHashValueDecl();
- auto mixinFuncExpr = new (C) DeclRefExpr(mixinFunc, DeclNameLoc(),
- /*implicit*/ true);
+ // _combineHashValues(result, <exprToHash>.hashValue)
+ auto combineFunc = C.getCombineHashValuesDecl();
+ auto combineFuncExpr = new (C) DeclRefExpr(combineFunc, DeclNameLoc(),
+ /*implicit*/ true);
auto rhsResultExpr = new (C) DeclRefExpr(resultVar, DeclNameLoc(),
/*implicit*/ true);
- auto mixinResultExpr = CallExpr::createImplicit(
- C, mixinFuncExpr, { rhsResultExpr, hashValueExpr }, {});
+ auto combineResultExpr = CallExpr::createImplicit(
+ C, combineFuncExpr, { rhsResultExpr, hashValueExpr }, {});
- // result = _mixForSynthesizedHashValue(result, <exprToHash>.hashValue)
+ // result = _combineHashValues(result, <exprToHash>.hashValue)
auto lhsResultExpr = new (C) DeclRefExpr(resultVar, DeclNameLoc(),
/*implicit*/ true);
auto assignExpr = new (C) AssignExpr(lhsResultExpr, SourceLoc(),
- mixinResultExpr, /*implicit*/ true);
+ combineResultExpr, /*implicit*/ true);
return assignExpr;
}
@@ -853,9 +853,9 @@
// If the enum has no associated values, we use the ordinal alone as the
// hash value, because that is sufficient for a good distribution. If any
- // case do have associated values, then the ordinal is used as the first
- // term mixed into _mixForSynthesizedHashValue, and the final result after
- // mixing in the payload is passed to _mixInt to improve the distribution.
+ // case does have associated values, then the ordinal is used as the first
+ // term combined into _combineHashValues, and the final result after
+ // combining the payload is passed to _mixInt to improve the distribution.
// result = <ordinal>
{
@@ -868,13 +868,14 @@
}
if (!hasNoAssociatedValues) {
- // Generate a sequence of expressions that mix the payload's hash values
- // into result.
+ // Generate a sequence of expressions that combine the payload's hash
+ // values into result.
for (auto payloadVar : payloadVars) {
auto payloadVarRef = new (C) DeclRefExpr(payloadVar, DeclNameLoc(),
/*implicit*/ true);
- // result = _mixForSynthesizedHashValue(result, <payloadVar>.hashValue)
- auto mixExpr = mixInHashExpr_hashValue(C, resultVar, payloadVarRef);
+ // result = _combineHashValues(result, <payloadVar>.hashValue)
+ auto mixExpr = combineHashValuesAssignmentExpr(C, resultVar,
+ payloadVarRef);
mixExpressions.emplace_back(ASTNode(mixExpr));
}
@@ -953,7 +954,7 @@
auto storedProperties =
structDecl->getStoredProperties(/*skipInaccessible=*/true);
- // For each stored property, generate a statement that mixes its hash value
+ // For each stored property, generate a statement that combines its hash value
// into the result.
for (auto propertyDecl : storedProperties) {
auto propertyRef = new (C) DeclRefExpr(propertyDecl, DeclNameLoc(),
@@ -962,8 +963,9 @@
/*implicit*/ true);
auto selfPropertyExpr = new (C) DotSyntaxCallExpr(propertyRef, SourceLoc(),
selfRef);
- // result = _mixForSynthesizedHashValue(result, <property>.hashValue)
- auto mixExpr = mixInHashExpr_hashValue(C, resultVar, selfPropertyExpr);
+ // result = _combineHashValues(result, <property>.hashValue)
+ auto mixExpr = combineHashValuesAssignmentExpr(C, resultVar,
+ selfPropertyExpr);
statements.emplace_back(ASTNode(mixExpr));
}
@@ -1014,11 +1016,11 @@
// result = 0
// case B(let a0):
// result = 1
- // result = _mixForSynthesizedHashValue(result, a0.hashValue)
+ // result = _combineHashValues(result, a0.hashValue)
// case C(let a0, let a1):
// result = 2
- // result = _mixForSynthesizedHashValue(result, a0.hashValue)
- // result = _mixForSynthesizedHashValue(result, a1.hashValue)
+ // result = _combineHashValues(result, a0.hashValue)
+ // result = _combineHashValues(result, a1.hashValue)
// }
// result = _mixInt(result)
// return result
@@ -1030,8 +1032,8 @@
// var y: String
// @derived var hashValue: Int {
// var result: Int = 0
- // result = _mixForSynthesizedHashValue(result, x.hashValue)
- // result = _mixForSynthesizedHashValue(result, y.hashValue)
+ // result = _combineHashValues(result, x.hashValue)
+ // result = _combineHashValues(result, y.hashValue)
// result = _mixInt(result)
// return result
// }
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 06718f0..e100ab9 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -1307,6 +1307,13 @@
secondType = req.getSecondType();
}
+ // Don't do further checking on error types.
+ if (firstType->hasError() || (secondType && secondType->hasError())) {
+ // Another requirement will fail later; just continue.
+ valid = false;
+ continue;
+ }
+
bool requirementFailure = false;
if (listener && !listener->shouldCheck(kind, firstType, secondType))
continue;
diff --git a/lib/Sema/TypeCheckProtocol.h b/lib/Sema/TypeCheckProtocol.h
index ed3df98..375dd9d 100644
--- a/lib/Sema/TypeCheckProtocol.h
+++ b/lib/Sema/TypeCheckProtocol.h
@@ -139,7 +139,7 @@
#ifndef NDEBUG
LLVM_ATTRIBUTE_USED
#endif
- void dump();
+ void dump() const;
};
class RequirementEnvironment;
@@ -707,6 +707,12 @@
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved,
ValueDecl *req);
+ /// Infer associated type witnesses for the given associated type.
+ InferredAssociatedTypesByWitnesses inferTypeWitnessesViaAssociatedType(
+ ConformanceChecker &checker,
+ const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved,
+ AssociatedTypeDecl *assocType);
+
/// Infer associated type witnesses for all relevant value requirements.
///
/// \param assocTypes The set of associated types we're interested in.
@@ -728,12 +734,30 @@
/// known to the compiler.
Type computeDerivedTypeWitness(AssociatedTypeDecl *assocType);
+ /// Compute a type witness without using a specific potential witness,
+ /// e.g., using a fixed type (from a refined protocol), default type
+ /// on an associated type, or deriving the type.
+ ///
+ /// \param allowDerived Whether to allow "derived" type witnesses.
+ Type computeAbstractTypeWitness(AssociatedTypeDecl *assocType,
+ bool allowDerived);
+
/// Substitute the current type witnesses into the given interface type.
Type substCurrentTypeWitnesses(Type type);
+ /// Retrieve substitution options with a tentative type witness
+ /// operation that queries the current set of type witnesses.
+ SubstOptions getSubstOptionsWithCurrentTypeWitnesses();
+
/// Check whether the current set of type witnesses meets the
/// requirements of the protocol.
- bool checkCurrentTypeWitnesses();
+ bool checkCurrentTypeWitnesses(
+ const SmallVectorImpl<std::pair<ValueDecl *, ValueDecl *>>
+ &valueWitnesses);
+
+ /// Check the current type witnesses against the
+ /// requirements of the given constrained extension.
+ bool checkConstrainedExtension(ExtensionDecl *ext);
/// Top-level operation to find solutions for the given unresolved
/// associated types.
diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp
index bc785b4..ffb1263 100644
--- a/lib/Sema/TypeCheckProtocolInference.cpp
+++ b/lib/Sema/TypeCheckProtocolInference.cpp
@@ -63,7 +63,7 @@
out << ")";
}
-void InferredTypeWitnessesSolution::dump() {
+void InferredTypeWitnessesSolution::dump() const {
llvm::errs() << "Type Witnesses:\n";
for (auto &typeWitness : TypeWitnesses) {
llvm::errs() << " " << typeWitness.first->getName() << " := ";
@@ -394,9 +394,21 @@
if (!req)
continue;
- // We only look at value witnesses.
- if (isa<AssociatedTypeDecl>(req))
+ // Infer type witnesses for associated types.
+ if (auto assocType = dyn_cast<AssociatedTypeDecl>(req)) {
+ // If this is not one of the associated types we are trying to infer,
+ // just continue.
+ if (assocTypes.count(assocType) == 0)
+ continue;
+
+ auto reqInferred = inferTypeWitnessesViaAssociatedType(checker,
+ assocTypes,
+ assocType);
+ if (!reqInferred.empty())
+ result.push_back({req, std::move(reqInferred)});
+
continue;
+ }
// Skip operator requirements, because they match globally and
// therefore tend to cause deduction mismatches.
@@ -429,7 +441,8 @@
// Infer associated types from the potential value witnesses for
// this requirement.
- auto reqInferred = inferTypeWitnessesViaValueWitnesses(checker, assocTypes, req);
+ auto reqInferred =
+ inferTypeWitnessesViaValueWitnesses(checker, assocTypes, req);
if (reqInferred.empty())
continue;
@@ -526,6 +539,63 @@
return type;
}
+InferredAssociatedTypesByWitnesses
+AssociatedTypeInference::inferTypeWitnessesViaAssociatedType(
+ ConformanceChecker &checker,
+ const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved,
+ AssociatedTypeDecl *assocType) {
+ auto &tc = checker.TC;
+
+ // Form the default name _Default_Foo.
+ Identifier defaultName;
+ {
+ SmallString<32> defaultNameStr;
+ {
+ llvm::raw_svector_ostream out(defaultNameStr);
+ out << "_Default_";
+ out << assocType->getName().str();
+ }
+
+ defaultName = tc.Context.getIdentifier(defaultNameStr);
+ }
+
+ // Look for types with the given default name that have appropriate
+ // @_implements attributes.
+ InferredAssociatedTypesByWitnesses result;
+ auto lookupOptions = defaultMemberTypeLookupOptions;
+ lookupOptions -= NameLookupFlags::PerformConformanceCheck;
+ for (auto candidate : tc.lookupMember(dc, adoptee, defaultName,
+ lookupOptions)) {
+ // We want type declarations.
+ auto typeDecl = dyn_cast<TypeDecl>(candidate.getValueDecl());
+ if (!typeDecl || isa<AssociatedTypeDecl>(typeDecl))
+ continue;
+
+ // We only find these within a protocol extension.
+ auto defaultProto = typeDecl->getDeclContext()
+ ->getAsProtocolOrProtocolExtensionContext();
+ if (!defaultProto)
+ continue;
+
+ // Determine the witness type.
+ Type witnessType = getWitnessTypeForMatching(tc, conformance, typeDecl);
+ if (!witnessType) continue;
+
+ if (auto witnessMetaType = witnessType->getAs<AnyMetatypeType>())
+ witnessType = witnessMetaType->getInstanceType();
+ else
+ continue;
+
+ // Add this result.
+ InferredAssociatedTypesByWitness inferred;
+ inferred.Witness = typeDecl;
+ inferred.Inferred.push_back({assocType, witnessType});
+ result.push_back(std::move(inferred));
+ }
+
+ return result;
+}
+
/// Attempt to resolve a type witness via a specific value witness.
InferredAssociatedTypesByWitness
AssociatedTypeInference::inferTypeWitnessesViaValueWitness(ValueDecl *req,
@@ -787,6 +857,42 @@
return derivedType;
}
+Type
+AssociatedTypeInference::computeAbstractTypeWitness(
+ AssociatedTypeDecl *assocType,
+ bool allowDerived) {
+ // We don't have a type witness for this associated type, so go
+ // looking for more options.
+ if (Type concreteType = computeFixedTypeWitness(assocType))
+ return concreteType;
+
+ // If we can form a default type, do so.
+ if (Type defaultType = computeDefaultTypeWitness(assocType))
+ return defaultType;
+
+ // If we can derive a type witness, do so.
+ if (allowDerived) {
+ if (Type derivedType = computeDerivedTypeWitness(assocType))
+ return derivedType;
+ }
+
+ // If there is a generic parameter of the named type, use that.
+ if (auto gpList = dc->getGenericParamsOfContext()) {
+ GenericTypeParamDecl *foundGP = nullptr;
+ for (auto gp : *gpList) {
+ if (gp->getName() == assocType->getName()) {
+ foundGP = gp;
+ break;
+ }
+ }
+
+ if (foundGP)
+ return dc->mapTypeIntoContext(foundGP->getDeclaredInterfaceType());
+ }
+
+ return Type();
+}
+
Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) {
// Local function that folds dependent member types with non-dependent
// bases into actual member references.
@@ -898,7 +1004,44 @@
}
}
-bool AssociatedTypeInference::checkCurrentTypeWitnesses() {
+SubstOptions
+AssociatedTypeInference::getSubstOptionsWithCurrentTypeWitnesses() {
+ SubstOptions options(None);
+ AssociatedTypeInference *self = this;
+ options.getTentativeTypeWitness =
+ [self](const NormalProtocolConformance *conformance,
+ AssociatedTypeDecl *assocType) -> TypeBase * {
+ auto thisProto = self->conformance->getProtocol();
+ if (conformance == self->conformance) {
+ // Okay: we have the associated type we need.
+ } else if (conformance->getType()->isEqual(
+ self->conformance->getType()) &&
+ thisProto->inheritsFrom(conformance->getProtocol())) {
+ // Find an associated type with the same name in the given
+ // protocol.
+ AssociatedTypeDecl *foundAssocType = nullptr;
+ for (auto result : thisProto->lookupDirect(
+ assocType->getName(),
+ /*ignoreNewExtensions=*/true)) {
+ foundAssocType = dyn_cast<AssociatedTypeDecl>(result);
+ if (foundAssocType) break;
+ }
+
+ if (!foundAssocType) return nullptr;
+ assocType = foundAssocType;
+ } else {
+ return nullptr;
+ }
+
+ Type type = self->typeWitnesses.begin(assocType)->first;
+ return type->mapTypeOutOfContext().getPointer();
+ };
+ return options;
+}
+
+bool AssociatedTypeInference::checkCurrentTypeWitnesses(
+ const SmallVectorImpl<std::pair<ValueDecl *, ValueDecl *>>
+ &valueWitnesses) {
// Fold the dependent member types within this type.
for (auto assocType : proto->getAssociatedTypeMembers()) {
if (conformance->hasTypeWitness(assocType))
@@ -924,15 +1067,7 @@
if (!proto->isRequirementSignatureComputed()) return false;
// Check any same-type requirements in the protocol's requirement signature.
- SubstOptions options(None);
- options.getTentativeTypeWitness =
- [&](const NormalProtocolConformance *conformance,
- AssociatedTypeDecl *assocType) -> TypeBase * {
- if (conformance != this->conformance) return nullptr;
-
- auto type = typeWitnesses.begin(assocType)->first;
- return type->mapTypeOutOfContext().getPointer();
- };
+ SubstOptions options = getSubstOptionsWithCurrentTypeWitnesses();
auto typeInContext = dc->mapTypeIntoContext(adoptee);
@@ -959,12 +1094,55 @@
case RequirementCheckResult::Success:
case RequirementCheckResult::SubstitutionFailure:
- return false;
+ break;
+ }
+
+ // Check for extra requirements in the constrained extensions that supply
+ // defaults.
+ SmallPtrSet<ExtensionDecl *, 4> checkedExtensions;
+ for (const auto &valueWitness : valueWitnesses) {
+ // We only perform this additional checking for default associated types.
+ if (!isa<TypeDecl>(valueWitness.first)) continue;
+
+ auto witness = valueWitness.second;
+ if (!witness) continue;
+
+ auto ext = dyn_cast<ExtensionDecl>(witness->getDeclContext());
+ if (!ext) continue;
+
+ if (!ext->isConstrainedExtension()) continue;
+ if (!checkedExtensions.insert(ext).second) continue;
+
+ if (checkConstrainedExtension(ext)) return true;
}
return false;
}
+bool AssociatedTypeInference::checkConstrainedExtension(ExtensionDecl *ext) {
+ auto typeInContext = dc->mapTypeIntoContext(adoptee);
+ auto subs = typeInContext->getContextSubstitutions(ext);
+
+ SubstOptions options = getSubstOptionsWithCurrentTypeWitnesses();
+ switch (tc.checkGenericArguments(
+ dc, SourceLoc(), SourceLoc(), adoptee,
+ ext->getGenericSignature()->getGenericParams(),
+ ext->getGenericSignature()->getRequirements(),
+ QueryTypeSubstitutionMap{subs},
+ LookUpConformanceInModule(ext->getModuleContext()),
+ nullptr, ConformanceCheckFlags::InExpression,
+ nullptr,
+ options)) {
+ case RequirementCheckResult::Success:
+ case RequirementCheckResult::SubstitutionFailure:
+ return false;
+
+ case RequirementCheckResult::Failure:
+ case RequirementCheckResult::UnsatisfiedDependency:
+ return true;
+ }
+}
+
void AssociatedTypeInference::findSolutions(
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes,
SmallVectorImpl<InferredTypeWitnessesSolution> &solutions) {
@@ -1008,65 +1186,26 @@
continue;
}
- // We don't have a type witness for this associated type, so go
- // looking for more options.
- if (Type concreteType = computeFixedTypeWitness(assocType)) {
- if (concreteType->hasError()) {
+ // Try to compute the type without the aid of a specific potential
+ // witness.
+ if (Type type = computeAbstractTypeWitness(assocType,
+ /*allowDerived=*/true)) {
+ if (type->hasError()) {
recordMissing();
return;
}
- typeWitnesses.insert(assocType, {concreteType, reqDepth});
+ typeWitnesses.insert(assocType, {type, reqDepth});
continue;
}
- // If we can form a default type, do so.
- if (Type defaultType = computeDefaultTypeWitness(assocType)) {
- if (defaultType->hasError()) {
- recordMissing();
- return;
- }
-
- typeWitnesses.insert(assocType, {defaultType, reqDepth});
- continue;
- }
-
- // If we can derive a type witness, do so.
- if (Type derivedType = computeDerivedTypeWitness(assocType)) {
- if (derivedType->hasError()) {
- recordMissing();
- return;
- }
-
- typeWitnesses.insert(assocType, {derivedType, reqDepth});
- continue;
- }
-
- // If there is a generic parameter of the named type, use that.
- if (auto gpList = dc->getGenericParamsOfContext()) {
- GenericTypeParamDecl *foundGP = nullptr;
- for (auto gp : *gpList) {
- if (gp->getName() == assocType->getName()) {
- foundGP = gp;
- break;
- }
- }
-
- if (foundGP) {
- auto gpType = dc->mapTypeIntoContext(
- foundGP->getDeclaredInterfaceType());
- typeWitnesses.insert(assocType, {gpType, reqDepth});
- continue;
- }
- }
-
// The solution is incomplete.
recordMissing();
return;
}
/// Check the current set of type witnesses.
- bool invalid = checkCurrentTypeWitnesses();
+ bool invalid = checkCurrentTypeWitnesses(valueWitnesses);
// Determine whether there is already a solution with the same
// bindings.
@@ -1109,17 +1248,50 @@
// looking for solutions involving each one.
const auto &inferredReq = inferred[reqDepth];
for (const auto &witnessReq : inferredReq.second) {
+ llvm::SaveAndRestore<unsigned> savedNumTypeWitnesses(numTypeWitnesses);
+
+ // If we inferred a type witness via a default, try both with and without
+ // the default.
+ if (isa<TypeDecl>(inferredReq.first)) {
+ // Recurse without considering this type.
+ valueWitnesses.push_back({inferredReq.first, nullptr});
+ findSolutionsRec(unresolvedAssocTypes, solutions, nonViableSolutions,
+ valueWitnesses, numTypeWitnesses,
+ numValueWitnessesInProtocolExtensions, reqDepth + 1);
+ valueWitnesses.pop_back();
+
+ ++numTypeWitnesses;
+ for (const auto &typeWitness : witnessReq.Inferred) {
+ auto known = typeWitnesses.begin(typeWitness.first);
+ if (known != typeWitnesses.end()) continue;
+
+ // Enter a new scope for the type witnesses hash table.
+ TypeWitnessesScope typeWitnessesScope(typeWitnesses);
+ typeWitnesses.insert(typeWitness.first, {typeWitness.second, reqDepth});
+
+ valueWitnesses.push_back({inferredReq.first, witnessReq.Witness});
+ findSolutionsRec(unresolvedAssocTypes, solutions, nonViableSolutions,
+ valueWitnesses, numTypeWitnesses,
+ numValueWitnessesInProtocolExtensions, reqDepth + 1);
+ valueWitnesses.pop_back();
+ }
+
+ continue;
+ }
+
// Enter a new scope for the type witnesses hash table.
TypeWitnessesScope typeWitnessesScope(typeWitnesses);
- llvm::SaveAndRestore<unsigned> savedNumTypeWitnesses(numTypeWitnesses);
// Record this value witness, popping it when we exit the current scope.
valueWitnesses.push_back({inferredReq.first, witnessReq.Witness});
- if (witnessReq.Witness->getDeclContext()->getAsProtocolExtensionContext())
+ if (!isa<TypeDecl>(inferredReq.first) &&
+ witnessReq.Witness->getDeclContext()->getAsProtocolExtensionContext())
++numValueWitnessesInProtocolExtensions;
SWIFT_DEFER {
- if (witnessReq.Witness->getDeclContext()->getAsProtocolExtensionContext())
+ if (!isa<TypeDecl>(inferredReq.first) &&
+ witnessReq.Witness->getDeclContext()->getAsProtocolExtensionContext())
--numValueWitnessesInProtocolExtensions;
+
valueWitnesses.pop_back();
};
@@ -1130,7 +1302,11 @@
// conflicts, there is no solution.
auto known = typeWitnesses.begin(typeWitness.first);
if (known != typeWitnesses.end()) {
- // If witnesses for two difference requirements inferred the same
+ // Don't overwrite a defaulted associated type witness.
+ if (isa<TypeDecl>(valueWitnesses[known->second].second))
+ continue;
+
+ // If witnesses for two different requirements inferred the same
// type, we're okay.
if (known->first->isEqual(typeWitness.second))
continue;
@@ -1192,6 +1368,22 @@
// consider these unordered since neither extension's generic signature
// is a superset of the other.
+ // If one of the declarations is null, it implies that we're working with
+ // a skipped associated type default. Prefer that default to something
+ // that came from a protocol extension.
+ if (!decl1 || !decl2) {
+ if (!decl1 &&
+ decl2 && decl2->getDeclContext()->getAsProtocolExtensionContext())
+ return Comparison::Worse;
+
+ if (!decl2 &&
+ decl1 && decl1->getDeclContext()->getAsProtocolExtensionContext())
+ return Comparison::Better;
+
+ return Comparison::Unordered;
+ }
+
+
// If the witnesses come from the same decl context, score normally.
auto dc1 = decl1->getDeclContext();
auto dc2 = decl2->getDeclContext();
diff --git a/lib/Syntax/README.md b/lib/Syntax/README.md
index e3488e3..7d1e914 100644
--- a/lib/Syntax/README.md
+++ b/lib/Syntax/README.md
@@ -425,7 +425,7 @@
auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
// This ReturnStmtSyntax is floating, with no root.
-auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, Integer,
+auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, Integer,
/*Semicolon=*/ None);
auto RightBrace = SyntaxFactory::makeLeftBraceToken({}, {});
@@ -466,7 +466,7 @@
A couple of interesting points and reminders:
- All strong references point downward in the tree.
-- One `SyntaxData` for each `RawSyntax`.
+- One `SyntaxData` for each `RawSyntax`.
Remember, a `SyntaxData` is essentially a `RawSyntax` with a parent pointer
and cached `SyntaxData` children.
- Parent pointers are omitted here but there are weak references pointing
@@ -530,14 +530,11 @@
## Adding new Syntax Nodes
Here's a handy checklist when implementing a production in the grammar.
-- Check that the corresponding `lib/AST` node has `SourceLocs` for all terms. If
- it doesn't, [file a Swift bug][NewSwiftBug] and fix that first.
- - **Add the `Syntax` bug label!**
- Check if it's not already being worked on, and then
- [file a Swift bug][NewSwiftBug], noting which grammar productions
- are affected.
+ [file a Swift bug](https://bugs.swift.org/secure/CreateIssue!default.jspa),
+ noting which grammar productions are affected.
- **Add the `Syntax` bug label!**
-- Create the `${KIND}` entry in the appropriate Python file (Expr, Stmt,
+- Create the `${KIND}` entry in the appropriate Python file (Expr, Stmt,
Pattern, etc.).
- Add C++ unit tests for `with` APIs for all layout elements
(e.g. `withLeftTypeIdentifier(...)`).
@@ -558,4 +555,47 @@
- check for a zero-diff print with `-round-trip-parse`
- Update `lib/Syntax/Status.md` if applicable.
-[NewSwiftBug]: https://bugs.swift.org/secure/CreateIssue!default.jspa)
+## Try libSyntax in Xcode
+
+Here's how to build a Swift command line tool in Xcode using libSyntax:
+1. Download the latest open source toolchain from swift.org:
+ [Trunk Development (master)](https://swift.org/download/#snapshots).
+2. Run the downloaded package installer.
+3. Start Xcode and specify the just-installed toolchain to use in
+`Xcode->Toolchains->Swift Development Snapshot...`
+4. Create a new Swift command line tool project in Xcode.
+5. In the project's build setting, specify two variables:
+ - Runpath search paths: `$(TOOLCHAIN_DIR)/usr/lib/swift/macosx`
+ - Library search paths: `$(TOOLCHAIN_DIR)/usr/lib/swift/macosx`
+6. Now, in `main.swift`, we can `import SwiftSyntax` and experiment with its APIs.
+ For example, the following code snippet renames every function called `foo` to `bar`.
+
+```swift
+import Foundation
+import SwiftSyntax
+
+class Renamer: SyntaxRewriter {
+ override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax {
+ if node.identifier.text == "foo" {
+ return super.visit(node.withIdentifier(SyntaxFactory.makeIdentifier("bar")))
+ } else {
+ return super.visit(node)
+ }
+ }
+}
+
+// Parse a .swift file
+let currentFile = URL(fileURLWithPath: "/tmp/test.swift")
+let currentFileContents = try String(contentsOf: currentFile)
+let parsed = try Syntax.parse(currentFile)
+
+// Print the original file
+print("\n//======== Original =========\n")
+print(parsed)
+
+let R = Renamer()
+
+// Print the file after renaming
+print("\n//======== Renamed =========\n")
+print(R.visit(parsed))
+```
diff --git a/lib/Syntax/Status.md b/lib/Syntax/Status.md
index eb2460d..8a66126 100644
--- a/lib/Syntax/Status.md
+++ b/lib/Syntax/Status.md
@@ -91,33 +91,34 @@
### Done:
* BraceStmt
* ReturnStmt
-
-### Not-started (UnknownStmt):
* DeferStmt
- * IfStmt
- * GuardStmt
- * WhileStmt
* DoStmt
- * DoCatchStmt
* RepeatWhileStmt
- * ForEachStmt
- * SwitchStmt
- * CaseStmt
- * CatchStmt
* BreakStmt
* ContinueStmt
* FallthroughStmt
- * FailStmt
* ThrowStmt
+### Not-started (UnknownStmt):
+ * IfStmt
+ * GuardStmt
+ * WhileStmt
+ * ForEachStmt
+ * SwitchStmt
+
## Pattern
-### Not-started:
- * ParenPattern
+### Done:
+ * IdentifierPattern
+ * WildcardPattern
* TuplePattern
- * NamedPattern
- * AnyPattern
- * TypedPattern
- * VarPattern
+ * ExpressionPattern
+ * ValueBindingPattern
+ * IsTypePattern
+
+### Not-started:
+ * AsTypePattern
+ * OptionalPattern
+ * EnumCasePattern
## TypeRepr
### Done:
diff --git a/lib/Syntax/SyntaxFactory.cpp.gyb b/lib/Syntax/SyntaxFactory.cpp.gyb
index d811d0a..80a51fb 100644
--- a/lib/Syntax/SyntaxFactory.cpp.gyb
+++ b/lib/Syntax/SyntaxFactory.cpp.gyb
@@ -110,50 +110,13 @@
static std::pair<bool, std::function<bool(const Syntax&)>>
ChildrenConditions[${child_count}] = {
% for child in node.children:
+% check = check_child_condition(child)
% if child.is_optional:
% option = "true"
% else:
% option = "false"
-% if child.token_choices:
- { ${option},
- [](const Syntax &S) {
- // check ${child.name}.
- if (auto Tok = S.getAs<TokenSyntax>()) {
- auto Kind = Tok->getTokenKind();
-% tok_checks = []
-% for choice in child.token_choices:
-% tok_checks.append("Kind == tok::%s" % choice.kind)
-% end
-% all_checks = ' || '.join(tok_checks)
- return ${all_checks};
- }
- return false;
- }
- },
-% elif child.text_choices:
- { ${option},
- [](const Syntax &S) {
- // check ${child.name}.
- if (auto Tok = S.getAs<TokenSyntax>()) {
- auto Text = Tok->getText();
-% tok_checks = []
-% for choice in child.text_choices:
-% tok_checks.append("Text == \"%s\"" % choice)
-% end
-% all_checks = ' || '.join(tok_checks)
- return ${all_checks};
- }
- return false;
- }
- },
-% else:
- { ${option},
- [](const Syntax &S) {
- // check ${child.name}.
- return S.getAs<${child.type_name}>().hasValue();
- }
- },
% end
+ { ${option}, ${check} },
% end
};
Optional<Syntax> Parameters[${child_count}];
diff --git a/lib/Syntax/SyntaxNodes.cpp.gyb b/lib/Syntax/SyntaxNodes.cpp.gyb
index 9b51cf9..753f70c 100644
--- a/lib/Syntax/SyntaxNodes.cpp.gyb
+++ b/lib/Syntax/SyntaxNodes.cpp.gyb
@@ -41,9 +41,18 @@
% token_kind = child.main_token().kind
% choices = ", ".join("\"%s\"" % choice
% for choice in child.text_choices)
- syntax_assert_child_token_text(raw, ${child.name},
+ syntax_assert_child_token_text(raw, ${child.name},
tok::${token_kind}, ${choices});
% end
+% if child.node_choices:
+#ifndef NDEBUG
+ {
+ auto child = make<Syntax>(raw->getChild(Cursor::${child.name}));
+% content = check_child_condition(child) + '(child)'
+ assert(${content});
+ }
+#endif
+% end
% end
}
% end
diff --git a/lib/Syntax/Trivia.cpp b/lib/Syntax/Trivia.cpp
index a2f49f1..e144e30 100644
--- a/lib/Syntax/Trivia.cpp
+++ b/lib/Syntax/Trivia.cpp
@@ -58,6 +58,9 @@
case TriviaKind::CarriageReturn:
OS << "carriage_return " << Count;
break;
+ case TriviaKind::CarriageReturnLineFeed:
+ OS << "carriage_return_line_feed " << Count;
+ break;
case TriviaKind::LineComment:
OS << "line_comment" << Text.str();
break;
@@ -101,7 +104,10 @@
break;
case TriviaKind::Newline:
case TriviaKind::CarriageReturn:
- Pos.addNewlines(Count);
+ Pos.addNewlines(Count, 1);
+ break;
+ case TriviaKind::CarriageReturnLineFeed:
+ Pos.addNewlines(Count, 2);
break;
case TriviaKind::Space:
case TriviaKind::Backtick:
@@ -113,6 +119,29 @@
}
}
+bool TriviaPiece::trySquash(const TriviaPiece &Next) {
+ if (Kind != Next.Kind) { return false; }
+
+ switch (Kind) {
+ case TriviaKind::Space:
+ case TriviaKind::Tab:
+ case TriviaKind::VerticalTab:
+ case TriviaKind::Formfeed:
+ case TriviaKind::Newline:
+ case TriviaKind::CarriageReturn:
+ case TriviaKind::CarriageReturnLineFeed:
+ Count += Next.Count;
+ return true;
+ case TriviaKind::LineComment:
+ case TriviaKind::BlockComment:
+ case TriviaKind::DocLineComment:
+ case TriviaKind::DocBlockComment:
+ case TriviaKind::GarbageText:
+ case TriviaKind::Backtick:
+ return false;
+ }
+}
+
void TriviaPiece::print(llvm::raw_ostream &OS) const {
switch (Kind) {
case TriviaKind::Space:
@@ -133,6 +162,11 @@
case TriviaKind::CarriageReturn:
printRepeated(OS, '\r', Count);
break;
+ case TriviaKind::CarriageReturnLineFeed:
+ for (unsigned i = 0; i < Count; i++) {
+ OS << "\r\n";
+ }
+ break;
case TriviaKind::LineComment:
case TriviaKind::BlockComment:
case TriviaKind::DocLineComment:
@@ -148,6 +182,17 @@
#pragma mark - Trivia collection
+void Trivia::appendOrSquash(const TriviaPiece &Next) {
+ if (Pieces.size() > 0) {
+ TriviaPiece &last = Pieces.back();
+ if (last.trySquash(Next)) {
+ return;
+ }
+ }
+
+ push_back(Next);
+}
+
Trivia Trivia::appending(const Trivia &Other) const {
auto NewPieces = Pieces;
std::copy(Other.begin(), Other.end(), std::back_inserter(NewPieces));
diff --git a/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb b/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb
index 75b39d1..00e5940 100644
--- a/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb
+++ b/stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb
@@ -506,11 +506,6 @@
let first = extractedResult[i].value
let second = extractedResult[extractedResult.index(after: i)].value
let result = lessImpl(second, first)
- if result {
- print("yep ** Result should be true \(result)")
- } else {
- print("yep ** Test passed result is false")
- }
expectFalse(result)
}
}
diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp
index d0de9e3..d2a55bb 100644
--- a/stdlib/public/Reflection/TypeLowering.cpp
+++ b/stdlib/public/Reflection/TypeLowering.cpp
@@ -975,7 +975,7 @@
// further.
if (CaseTI != nullptr) {
// Below logic should match the runtime function
- // swift_initEnumValueWitnessTableSinglePayload().
+ // swift_initEnumMetadataSinglePayload().
NumExtraInhabitants = CaseTI->getNumExtraInhabitants();
if (NumExtraInhabitants >= NoPayloadCases) {
// Extra inhabitants can encode all no-payload cases.
diff --git a/stdlib/public/core/Flatten.swift b/stdlib/public/core/Flatten.swift
index 9a2733c..a3c806c 100644
--- a/stdlib/public/core/Flatten.swift
+++ b/stdlib/public/core/Flatten.swift
@@ -566,7 +566,7 @@
}
// @available(*, deprecated, renamed: "FlattenCollection.Index")
-public typealias FlattenCollectionIndex<T> = FlattenCollection<T>.Index where T : BidirectionalCollection, T.Element : BidirectionalCollection
+public typealias FlattenCollectionIndex<T> = FlattenCollection<T>.Index where T : Collection, T.Element : Collection
@available(*, deprecated, renamed: "FlattenCollection.Index")
public typealias FlattenBidirectionalCollectionIndex<T> = FlattenCollection<T>.Index where T : BidirectionalCollection, T.Element : BidirectionalCollection
@available(*, deprecated, renamed: "FlattenCollection")
diff --git a/stdlib/public/core/Hashing.swift b/stdlib/public/core/Hashing.swift
index 5a4ca72..116ba67 100644
--- a/stdlib/public/core/Hashing.swift
+++ b/stdlib/public/core/Hashing.swift
@@ -188,13 +188,21 @@
/// Returns a new value that combines the two given hash values.
///
+/// Combining is performed using [a hash function][ref] described by T.C. Hoad
+/// and J. Zobel, which is also adopted in the Boost C++ libraries.
+///
/// This function is used by synthesized implementations of `hashValue` to
/// combine the hash values of individual `struct` fields and associated values
/// of `enum`s. It is factored out into a standard library function so that the
/// specific hashing logic can be refined without requiring major changes to the
/// code that creates the synthesized AST nodes.
+///
+/// [ref]: http://goanna.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf
@_transparent
public // @testable
-func _mixForSynthesizedHashValue(_ oldValue: Int, _ nextValue: Int) -> Int {
- return 31 &* oldValue &+ nextValue
+func _combineHashValues(_ firstValue: Int, _ secondValue: Int) -> Int {
+ let magic = 0x9e3779b9 as UInt // Based on the golden ratio.
+ var x = UInt(bitPattern: firstValue)
+ x ^= UInt(bitPattern: secondValue) &+ magic &+ (x &<< 6) &+ (x &>> 2)
+ return Int(bitPattern: x)
}
diff --git a/stdlib/public/core/RandomAccessCollection.swift b/stdlib/public/core/RandomAccessCollection.swift
index aff7d21..079f965 100644
--- a/stdlib/public/core/RandomAccessCollection.swift
+++ b/stdlib/public/core/RandomAccessCollection.swift
@@ -166,6 +166,13 @@
}
}
+// Provides an alternative default associated type witness for Indices
+// for random access collections with strideable indices.
+extension RandomAccessCollection where Index : Strideable, Index.Stride == Int {
+ @_implements(Collection, Indices)
+ public typealias _Default_Indices = CountableRange<Index>
+}
+
extension RandomAccessCollection
where Index : Strideable,
Index.Stride == Int,
diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift
index deaf468..accf446 100644
--- a/stdlib/public/core/Sequence.swift
+++ b/stdlib/public/core/Sequence.swift
@@ -612,6 +612,13 @@
) -> (Iterator,UnsafeMutableBufferPointer<Element>.Index)
}
+// Provides a default associated type witness for Iterator when the
+// Self type is both a Sequence and an Iterator.
+extension Sequence where Self: IteratorProtocol {
+ // @_implements(Sequence, Iterator)
+ public typealias _Default_Iterator = Self
+}
+
/// A default makeIterator() function for `IteratorProtocol` instances that
/// are declared to conform to `Sequence`
extension Sequence where Self.Iterator == Self {
@@ -622,7 +629,6 @@
}
}
-
/// A sequence that lazily consumes and drops `n` elements from an underlying
/// `Base` iterator before possibly returning the first available element.
///
diff --git a/stdlib/public/core/SwiftNativeNSArray.swift b/stdlib/public/core/SwiftNativeNSArray.swift
index aa57fcb..5189acc 100644
--- a/stdlib/public/core/SwiftNativeNSArray.swift
+++ b/stdlib/public/core/SwiftNativeNSArray.swift
@@ -262,6 +262,7 @@
#else
// Empty shim version for non-objc platforms.
@_versioned
+@_fixed_layout
internal class _SwiftNativeNSArrayWithContiguousStorage {
@_inlineable
@_versioned
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index 44dff74..5d88134 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -1,6 +1,11 @@
set(swift_runtime_compile_flags ${SWIFT_RUNTIME_CORE_CXX_FLAGS})
set(swift_runtime_linker_flags ${SWIFT_RUNTIME_CORE_LINK_FLAGS})
+if(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT)
+ list(APPEND swift_runtime_compile_flags
+ "-DSWIFT_DARWIN_ENABLE_STABLE_ABI_BIT=1")
+endif()
+
if(SWIFT_RUNTIME_CLOBBER_FREED_OBJECTS)
list(APPEND swift_runtime_compile_flags
"-DSWIFT_RUNTIME_CLOBBER_FREED_OBJECTS=1")
diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp
index 21eef71..e547848 100644
--- a/stdlib/public/runtime/Enum.cpp
+++ b/stdlib/public/runtime/Enum.cpp
@@ -26,10 +26,45 @@
using namespace swift;
+static EnumValueWitnessTable *getMutableVWTableForInit(EnumMetadata *self,
+ EnumLayoutFlags flags) {
+ auto oldTable =
+ static_cast<const EnumValueWitnessTable *>(self->getValueWitnesses());
+
+ // If we can alter the existing table in-place, do so.
+ if (isValueWitnessTableMutable(flags))
+ return const_cast<EnumValueWitnessTable*>(oldTable);
+
+ // Otherwise, allocate permanent memory for it and copy the existing table.
+ void *memory = allocateMetadata(sizeof(EnumValueWitnessTable),
+ alignof(EnumValueWitnessTable));
+ auto newTable = new (memory) EnumValueWitnessTable(*oldTable);
+ self->setValueWitnesses(newTable);
+
+ return newTable;
+}
+
void
-swift::swift_initEnumValueWitnessTableSinglePayload(ValueWitnessTable *vwtable,
- const TypeLayout *payloadLayout,
- unsigned emptyCases) {
+swift::swift_initEnumMetadataSingleCase(EnumMetadata *self,
+ EnumLayoutFlags layoutFlags,
+ const TypeLayout *payloadLayout) {
+ auto vwtable = getMutableVWTableForInit(self, layoutFlags);
+
+ vwtable->size = payloadLayout->size;
+ vwtable->stride = payloadLayout->stride;
+ vwtable->flags = payloadLayout->flags.withEnumWitnesses(true);
+
+ if (payloadLayout->flags.hasExtraInhabitants()) {
+ auto ew = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
+ ew->extraInhabitantFlags = payloadLayout->getExtraInhabitantFlags();
+ }
+}
+
+void
+swift::swift_initEnumMetadataSinglePayload(EnumMetadata *self,
+ EnumLayoutFlags layoutFlags,
+ const TypeLayout *payloadLayout,
+ unsigned emptyCases) {
size_t payloadSize = payloadLayout->size;
unsigned payloadNumExtraInhabitants
= payloadLayout->getNumExtraInhabitants();
@@ -47,6 +82,8 @@
emptyCases - payloadNumExtraInhabitants,
1 /*payload case*/);
}
+
+ auto vwtable = getMutableVWTableForInit(self, layoutFlags);
size_t align = payloadLayout->flags.getAlignment();
vwtable->size = size;
@@ -128,8 +165,8 @@
}
void
-swift::swift_initEnumMetadataMultiPayload(ValueWitnessTable *vwtable,
- EnumMetadata *enumType,
+swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
+ EnumLayoutFlags layoutFlags,
unsigned numPayloads,
const TypeLayout * const *payloadLayouts) {
// Accumulate the layout requirements of the payloads.
@@ -151,7 +188,9 @@
unsigned totalSize = payloadSize + getNumTagBytes(payloadSize,
enumType->Description->Enum.getNumEmptyCases(),
numPayloads);
-
+
+ auto vwtable = getMutableVWTableForInit(enumType, layoutFlags);
+
// Set up the layout info in the vwtable.
vwtable->size = totalSize;
vwtable->flags = ValueWitnessFlags()
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index 2e2ba73..1fb82aa 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -1278,25 +1278,57 @@
/*** Structs ***************************************************************/
/***************************************************************************/
+static ValueWitnessTable *getMutableVWTableForInit(StructMetadata *self,
+ StructLayoutFlags flags,
+ bool hasExtraInhabitants) {
+ auto oldTable = self->getValueWitnesses();
+
+ // If we can alter the existing table in-place, do so.
+ if (isValueWitnessTableMutable(flags))
+ return const_cast<ValueWitnessTable*>(oldTable);
+
+ // Otherwise, allocate permanent memory for it and copy the existing table.
+ ValueWitnessTable *newTable;
+ if (hasExtraInhabitants) {
+ void *memory = allocateMetadata(sizeof(ExtraInhabitantsValueWitnessTable),
+ alignof(ExtraInhabitantsValueWitnessTable));
+ newTable = new (memory) ExtraInhabitantsValueWitnessTable(
+ *static_cast<const ExtraInhabitantsValueWitnessTable*>(oldTable));
+ } else {
+ void *memory = allocateMetadata(sizeof(ValueWitnessTable),
+ alignof(ValueWitnessTable));
+ newTable = new (memory) ValueWitnessTable(*oldTable);
+ }
+ self->setValueWitnesses(newTable);
+
+ return newTable;
+}
+
/// Initialize the value witness table and struct field offset vector for a
/// struct, using the "Universal" layout strategy.
-void swift::swift_initStructMetadata_UniversalStrategy(size_t numFields,
+void swift::swift_initStructMetadata(StructMetadata *structType,
+ StructLayoutFlags layoutFlags,
+ size_t numFields,
const TypeLayout * const *fieldTypes,
- size_t *fieldOffsets,
- ValueWitnessTable *vwtable) {
+ size_t *fieldOffsets) {
auto layout = BasicLayout::initialForValueType();
performBasicLayout(layout, fieldTypes, numFields,
[&](size_t i, const TypeLayout *fieldType, size_t offset) {
assignUnlessEqual(fieldOffsets[i], offset);
});
+ bool hasExtraInhabitants = fieldTypes[0]->flags.hasExtraInhabitants();
+
+ auto vwtable =
+ getMutableVWTableForInit(structType, layoutFlags, hasExtraInhabitants);
+
vwtable->size = layout.size;
vwtable->flags = layout.flags;
vwtable->stride = layout.stride;
// We have extra inhabitants if the first element does.
// FIXME: generalize this.
- if (fieldTypes[0]->flags.hasExtraInhabitants()) {
+ if (hasExtraInhabitants) {
vwtable->flags = vwtable->flags.withExtraInhabitants(true);
auto xiVWT = cast<ExtraInhabitantsValueWitnessTable>(vwtable);
xiVWT->extraInhabitantFlags = fieldTypes[0]->getExtraInhabitantFlags();
@@ -2464,14 +2496,15 @@
const ForeignTypeMetadata *
swift::swift_getForeignTypeMetadata(ForeignTypeMetadata *nonUnique) {
// Fast path: check the invasive cache.
- if (auto unique = nonUnique->getCachedUniqueMetadata()) {
- return unique;
+ auto cache = nonUnique->getCacheValue();
+ if (cache.isInitialized()) {
+ return cache.getCachedUniqueMetadata();
}
// Okay, check the global map.
auto &foreignTypes = ForeignTypes.get();
GlobalString key(nonUnique->getName());
- bool hasInit = nonUnique->hasInitializationFunction();
+ bool hasInit = cache.hasInitializationFunction();
const ForeignTypeMetadata *uniqueMetadata;
bool inserted;
@@ -2900,3 +2933,6 @@
std::memory_order_relaxed);
}
+void *swift::allocateMetadata(size_t size, size_t alignment) {
+ return MetadataAllocator().Allocate(size, alignment);
+}
diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h
index 0e350e7..fd48475 100644
--- a/stdlib/public/runtime/Private.h
+++ b/stdlib/public/runtime/Private.h
@@ -193,6 +193,8 @@
#endif
}
+ void *allocateMetadata(size_t size, size_t align);
+
} // end namespace swift
#endif /* SWIFT_RUNTIME_PRIVATE_H */
diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm
index 9b1c7d1..6860b99 100644
--- a/stdlib/public/runtime/SwiftObject.mm
+++ b/stdlib/public/runtime/SwiftObject.mm
@@ -443,7 +443,7 @@
bool swift::usesNativeSwiftReferenceCounting(const ClassMetadata *theClass) {
#if SWIFT_OBJC_INTEROP
if (!theClass->isTypeMetadata()) return false;
- return (theClass->getFlags() & ClassFlags::UsesSwift1Refcounting);
+ return (theClass->getFlags() & ClassFlags::UsesSwiftRefcounting);
#else
return true;
#endif
diff --git a/test/DebugInfo/uninitialized.swift b/test/DebugInfo/uninitialized.swift
new file mode 100644
index 0000000..ca3549e
--- /dev/null
+++ b/test/DebugInfo/uninitialized.swift
@@ -0,0 +1,11 @@
+// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
+class MyClass {}
+
+// CHECK: define {{.*}} @_T013uninitialized1fyyF
+public func f() {
+ var object: MyClass
+ // CHECK: %[[OBJ:.*]] = alloca %[[T:.*]]*, align
+ // CHECK: call void @llvm.dbg.declare(metadata %[[T]]** %[[OBJ]],
+ // CHECK: %[[BC:.*]] = bitcast %[[T]]** %[[OBJ]] to %swift.opaque**, !dbg
+ // CHECK: store %swift.opaque* null, %swift.opaque** %[[BC]], align {{.*}}, !dbg
+}
diff --git a/test/IRGen/cf.sil b/test/IRGen/cf.sil
index 24e5e00..18af675 100644
--- a/test/IRGen/cf.sil
+++ b/test/IRGen/cf.sil
@@ -7,11 +7,18 @@
// CHECK: [[REFRIGERATOR:%TSo14CCRefrigeratorC]] = type
// CHECK: [[OBJC:%objc_object]] = type
-// CHECK: [[REFRIGERATOR_NAME:@.*]] = private unnamed_addr constant [20 x i8] c"So14CCRefrigeratorC\00"
+// CHECK: [[REFRIGERATOR_NAME:@.*]] = private constant [20 x i8] c"So14CCRefrigeratorC\00"
-// CHECK-32: @_T0So14CCRefrigeratorCN = linkonce_odr hidden global <{ {{.*}} }> <{ i8* getelementptr inbounds ([20 x i8], [20 x i8]* [[REFRIGERATOR_NAME]], i32 0, i32 0), [[TYPE]]* null, i32 0, i8** @_T0BOWV, i32 16, [[TYPE]]* null, i8* null, i8* null, i8* null }>
+// CHECK-32: @_T0So14CCRefrigeratorCN = linkonce_odr hidden global <{ {{.*}} }> <{
+// CHECK-32-SAME: [[REFRIGERATOR_NAME]] to i32
+// CHECK-32-SAME: i32 0,
+// CHECK-32-SAME: i8** @_T0BOWV, i32 16, [[TYPE]]* null, i8* null, i8* null, i8* null }>
-// CHECK-64: @_T0So14CCRefrigeratorCN = linkonce_odr hidden global <{ {{.*}} }> <{ i8* getelementptr inbounds ([20 x i8], [20 x i8]* [[REFRIGERATOR_NAME]], i64 0, i64 0), [[TYPE]]* null, i64 0, i8** @_T0BOWV, i64 16, [[TYPE]]* null, i8* null, i8* null, i8* null }>
+// CHECK-64: @_T0So14CCRefrigeratorCN = linkonce_odr hidden global <{ {{.*}} }> <{
+// CHECK-64-SAME: i32 0,
+// CHECK-64-SAME: i32 trunc {{.*}} [[REFRIGERATOR_NAME]] to i64
+// CHECK-64-SAME: i64 0,
+// CHECK-64-SAME: i8** @_T0BOWV, i64 16, [[TYPE]]* null, i8* null, i8* null, i8* null }>
sil_stage canonical
@@ -35,5 +42,5 @@
// CHECK-NEXT: ret void
// CHECK: define linkonce_odr hidden [[TYPE]]* @_T0So14CCRefrigeratorCMa()
-// CHECK-32: call [[TYPE]]* @swift_getForeignTypeMetadata([[TYPE]]* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ({{.*}}* @_T0So14CCRefrigeratorCN to i8*), i32 16) to [[TYPE]]*))
-// CHECK-64: call [[TYPE]]* @swift_getForeignTypeMetadata([[TYPE]]* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ({{.*}}* @_T0So14CCRefrigeratorCN to i8*), i64 32) to [[TYPE]]*))
+// CHECK-32: call [[TYPE]]* @swift_getForeignTypeMetadata([[TYPE]]* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ({{.*}}* @_T0So14CCRefrigeratorCN to i8*), i32 12) to [[TYPE]]*))
+// CHECK-64: call [[TYPE]]* @swift_getForeignTypeMetadata([[TYPE]]* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ({{.*}}* @_T0So14CCRefrigeratorCN to i8*), i64 24) to [[TYPE]]*))
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index 78308d6..236c5c3 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -26,6 +26,8 @@
// CHECK: @_T016class_resilience14ResilientChildCMo = {{(protected )?}}global [[INT]] 0
+// CHECK: @_T016class_resilience16FixedLayoutChildCMo = {{(protected )?}}global [[INT]] 0
+
// CHECK: @_T016class_resilience21ResilientGenericChildCMo = {{(protected )?}}global [[INT]] 0
// CHECK: @_T016class_resilience17MyResilientParentCMo = {{(protected )?}}constant [[INT]] {{52|80}}
@@ -103,6 +105,14 @@
public let field: Int32 = 0
}
+// Superclass is resilient, but the class is fixed-layout.
+// This simulates a user app subclassing a class in a resilient
+// framework. In this case, we still want to emit a base offset
+// global.
+
+@_fixed_layout public class FixedLayoutChild : ResilientOutsideParent {
+ public let field: Int32 = 0
+}
// Superclass is resilient, so the number of fields and their
// offsets is not known at compile time
@@ -303,6 +313,27 @@
// CHECK: ret void
+// CHECK-LABEL: define private void @initialize_metadata_FixedLayoutChild(i8*)
+
+// Get the superclass...
+
+// CHECK: [[SUPER:%.*]] = call %swift.type* @_T015resilient_class22ResilientOutsideParentCMa()
+// CHECK: [[SUPER_ADDR:%.*]] = bitcast %swift.type* [[SUPER]] to i8*
+// CHECK: [[SIZE_TMP:%.*]] = getelementptr inbounds i8, i8* [[SUPER_ADDR]], i32 {{36|56}}
+// CHECK: [[SIZE_ADDR:%.*]] = bitcast i8* [[SIZE_TMP]] to i32*
+// CHECK: [[SIZE:%.*]] = load i32, i32* [[SIZE_ADDR]]
+
+// Initialize class metadata base offset...
+// CHECK: store [[INT]] {{.*}}, [[INT]]* @_T016class_resilience16FixedLayoutChildCMo
+
+// Initialize the superclass field...
+// CHECK: store %swift.type* [[SUPER]], %swift.type** getelementptr inbounds ({{.*}})
+
+// Relocate metadata if necessary...
+// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 1)
+
+// CHECK: ret void
+
// CHECK-LABEL: define private %swift.type* @create_generic_metadata_ResilientGenericChild(%swift.type_pattern*, i8**)
// Get the superclass...
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index 142114c..ef5ddd7 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -105,6 +105,11 @@
// implementations which are used if the instance has extra inhabitants.
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private constant [7 x i8] c"value\00\00"
+// CHECK: @_T04enum16DynamicSingletonOWV =
+// CHECK-SAME: i8* null
+// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum16DynamicSingletonOwxs to i8*)
+// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum16DynamicSingletonOwxg to i8*)
+
// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [25 x i8] c"4enum16DynamicSingletonO\00"
// CHECK: @_T04enum16DynamicSingletonOMn = hidden constant <{ {{.*}} i32 }> <{
// CHECK-SAME: [25 x i8]* [[DYNAMICSINGLETON_NAME]]
@@ -128,12 +133,10 @@
// CHECK-SAME: i32 1
// CHECK-SAME: }>
-// CHECK: @_T04enum16DynamicSingletonOMP = internal global <{ {{.*}}, [18 x i8*] }> <{
+// CHECK: @_T04enum16DynamicSingletonOMP = internal global <{ {{.*}}, %swift.type* }> <{
// CHECK-SAME: %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSingleton
+// CHECK-SAME: [18 x i8*]* @_T04enum16DynamicSingletonOWV
// CHECK-SAME: @_T04enum16DynamicSingletonOMn
-// CHECK-SAME: i8* null
-// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum16DynamicSingletonOwxs to i8*)
-// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum16DynamicSingletonOwxg to i8*)
// -- No-payload enums have extra inhabitants in
// their value witness table.
@@ -171,13 +174,15 @@
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum19SinglePayloadNestedOwxg to i8*)
// CHECK-SAME: ]
-
-// CHECK: @_T04enum20DynamicSinglePayloadOMP = internal global <{ {{.*}}, [18 x i8*] }> <{
-// CHECK-SAME: %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload
+// CHECK: @_T04enum20DynamicSinglePayloadOWV = internal constant [18 x i8*] [
// CHECK-SAME: i8* null
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxs to i8*)
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxg to i8*)
+// CHECK: @_T04enum20DynamicSinglePayloadOMP = internal global <{ {{.*}}, %swift.type* }> <{
+// CHECK-SAME: %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload
+// CHECK-SAME: [18 x i8*]* @_T04enum20DynamicSinglePayloadOWV
+
// CHECK: @_T04enum18MultiPayloadNestedOWV = internal constant [18 x i8*] [
// -- size
// CHECK-32-SAME: i8* inttoptr ([[WORD]] 5 to i8*),
@@ -2682,8 +2687,7 @@
return %tuple : $()
}
-// -- Fill function for dynamic singleton. The value witness table flags just
-// get copied over from the element.
+// -- Fill function for dynamic singleton.
// CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSingleton(%swift.type_pattern*, i8**) {{.*}} {
// CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type**
// CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]],
@@ -2692,48 +2696,17 @@
// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 2
// CHECK: [[T0:%.*]] = bitcast %swift.type* [[T]] to i8*
// CHECK: store i8* [[T0]], i8** [[T1]]
-// CHECK: [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3
-// CHECK: [[T0:%.*]] = bitcast i8** [[VWT]] to i8*
-// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 -1
-// CHECK: store i8* [[T0]], i8** [[T1]]
// CHECK: [[T_VWTS:%.*]] = bitcast %swift.type* [[T]] to i8***
// CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[T_VWTS]], [[WORD]] -1
// CHECK: [[T_VWT:%.*]] = load i8**, i8*** [[T_VWT_ADDR]]
// CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 9
-// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK: [[T_SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 0
-// CHECK: [[T_SIZE:%.*]] = load i8*, i8** [[T_SIZE_ADDR]]
-// CHECK: store i8* [[T_SIZE]], i8** [[SIZE_ADDR]]
-// CHECK: [[STRIDE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 11
-// CHECK: [[T_STRIDE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 2
-// CHECK: [[T_STRIDE:%.*]] = load i8*, i8** [[T_STRIDE_ADDR]]
-// CHECK: store i8* [[T_STRIDE]], i8** [[STRIDE_ADDR]]
-// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 10
-// CHECK: [[T_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 1
-// CHECK: [[T_FLAGS:%.*]] = load i8*, i8** [[T_FLAGS_ADDR]]
-// CHECK: [[T_FLAGS_INT:%.*]] = ptrtoint i8* [[T_FLAGS]] to [[WORD]]
-// CHECK: [[T_FLAGS_INT_2:%.*]] = or [[WORD]] [[T_FLAGS_INT]], 2097152
-// CHECK: [[T_FLAGS_2:%.*]] = inttoptr [[WORD]] [[T_FLAGS_INT_2]] to i8*
-// CHECK: store i8* [[T_FLAGS_2]], i8** [[FLAGS_ADDR]]
-// -- Test the 'has extra inhabitants' bit and carry over the extra inhabitants
-// flag if set.
-// CHECK: [[T_FLAGS_VAL:%.*]] = ptrtoint i8* [[T_FLAGS]] to [[WORD]]
-// CHECK: [[XI_FLAG:%.*]] = and [[WORD]] [[T_FLAGS_VAL]], 262144
-// CHECK: [[XI_BIT:%.*]] = icmp ne [[WORD]] [[XI_FLAG]], 0
-// CHECK: br i1 [[XI_BIT]], label %[[HAS_XI:[0-9]+]], label %[[HAS_NO_XI:[0-9]+]]
-// CHECK: ; <label>:[[HAS_XI]]
-// CHECK: [[XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 12
-// CHECK: [[T_XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 3
-// CHECK: [[T_XI_FLAGS:%.*]] = load i8*, i8** [[T_XI_FLAGS_ADDR]]
-// CHECK: store i8* [[T_XI_FLAGS]], i8** [[XI_FLAGS_ADDR]]
-// CHECK: br label %[[HAS_NO_XI]]
-// CHECK: ; <label>:[[HAS_NO_XI]]
+// CHECK: call void @swift_initEnumMetadataSingleCase(%swift.type* [[METADATA]], [[WORD]] 0, i8** [[T_LAYOUT]])
// CHECK: ret %swift.type* [[METADATA]]
// -- Fill function for dynamic single-payload. Call into the runtime to
// calculate the size.
// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} {
-// CHECK: call void @swift_initEnumValueWitnessTableSinglePayload
+// CHECK: call void @swift_initEnumMetadataSinglePayload(%swift.type* [[METADATA]], [[WORD]] 0, i8** [[T_LAYOUT]], i32 3)
// CHECK-64-LABEL: define linkonce_odr hidden void @_T04enum17StructWithWeakVarVwxs(%swift.opaque* noalias %dest, i32 %index, %swift.type* %StructWithWeakVar)
// -- TODO: some pointless masking here.
diff --git a/test/IRGen/enum_dynamic_multi_payload.sil b/test/IRGen/enum_dynamic_multi_payload.sil
index 53f5215..fea6b26 100644
--- a/test/IRGen/enum_dynamic_multi_payload.sil
+++ b/test/IRGen/enum_dynamic_multi_payload.sil
@@ -437,4 +437,4 @@
// CHECK-NEXT: [[LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[VALUE_WITNESSES]], i32 9
// CHECK-NEXT: store i8** [[LAYOUT]], {{.*}} [[BUF1]]
-// CHECK: call void @swift_initEnumMetadataMultiPayload(i8** {{%.*}}, %swift.type* [[METADATA]], {{i(32|64)}} 2, i8*** [[BUF0]])
+// CHECK: call void @swift_initEnumMetadataMultiPayload(%swift.type* [[METADATA]], {{i(32|64)}} 0, {{i(32|64)}} 2, i8*** [[BUF0]])
diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift
index f82ffc3..14eb805 100644
--- a/test/IRGen/enum_resilience.swift
+++ b/test/IRGen/enum_resilience.swift
@@ -262,3 +262,4 @@
}
// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*)
+// CHECK: call void @swift_initEnumMetadataMultiPayload(%swift.type* {{.*}}, [[INT]] 256, [[INT]] 2, i8*** {{.*}})
diff --git a/test/IRGen/foreign_types.sil b/test/IRGen/foreign_types.sil
index 64d9669..89ef81f 100644
--- a/test/IRGen/foreign_types.sil
+++ b/test/IRGen/foreign_types.sil
@@ -4,9 +4,8 @@
import c_layout
// CHECK-LABEL: @_T0SC14HasNestedUnionV18__Unnamed_struct_sVN = linkonce_odr hidden global
-// CHECK-SAME: i8* getelementptr inbounds
-// CHECK-SAME: %swift.type* null,
-// CHECK-SAME: [[INT:i[0-9]+]] 0,
+// CHECK-SAME: [[INT:i[0-9]+]] sub ([[INT]] ptrtoint
+// CHECK-SAME: [[INT]] 0,
// CHECK-SAME: @_T0SC14HasNestedUnionV18__Unnamed_struct_sVWV
// CHECK-SAME: [[INT]] 1,
// CHECK-SAME: @_T0SC14HasNestedUnionV18__Unnamed_struct_sVMn
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index 6234bd8..6006411 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -6,7 +6,16 @@
// -- Generic structs with dynamic layout contain the vwtable pattern as part
// of the metadata pattern, and no independent vwtable symbol
-// CHECK-NOT: @_T015generic_structs13SingleDynamicVWV
+// CHECK: @_T015generic_structs13SingleDynamicVWV = internal constant
+// CHECK-SAME: i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @_T015generic_structs13SingleDynamicVwCP to i8*),
+// -- ...
+// -- placeholder for size, flags, stride
+// CHECK-SAME: i8* null, i8* null, i8* null
+// -- extra inhabitants
+// CHECK-SAME: i8* null,
+// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T015generic_structs13SingleDynamicVwxs to i8*),
+// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T015generic_structs13SingleDynamicVwxg to i8*)]
+
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [34 x i8] c"15generic_structs13SingleDynamicV\00"
// CHECK: [[SINGLEDYNAMIC_FIELDS:@.*]] = private constant [3 x i8] c"x\00\00"
@@ -35,23 +44,13 @@
// CHECK: @_T015generic_structs13SingleDynamicVMP = internal global <{ {{.*}} }> <{
// -- template header
// CHECK-SAME: %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_SingleDynamic,
-// CHECK-SAME: i32 168, i16 1, i16 16, [{{[0-9]+}} x i8*] zeroinitializer,
-// -- placeholder for vwtable pointer
-// CHECK-SAME: i8* null,
+// CHECK-SAME: i32 48, i16 1, i16 16, [{{[0-9]+}} x i8*] zeroinitializer,
+// -- vwtable pointer
+// CHECK-SAME: @_T015generic_structs13SingleDynamicVWV
// -- address point
// CHECK-SAME: i64 1, {{.*}}* @_T015generic_structs13SingleDynamicVMn
// -- field offset vector; generic parameter vector
-// CHECK-SAME: i64 0, %swift.type* null,
-// -- tail-allocated vwtable pattern
-// CHECK-SAME: i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @_T015generic_structs13SingleDynamicVwCP to i8*),
-// -- ...
-// -- placeholder for size, flags, stride
-// CHECK-SAME: i8* null, i8* null, i8* null
-// -- extra inhabitants
-// CHECK-SAME: i8* null,
-// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T015generic_structs13SingleDynamicVwxs to i8*),
-// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T015generic_structs13SingleDynamicVwxg to i8*)] }>
-// CHECK-NOT: @_T015generic_structs13SingleDynamicVWV
+// CHECK-SAME: i64 0, %swift.type* null }>
// -- Nominal type descriptor for generic struct with protocol requirements
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
@@ -82,8 +81,7 @@
// CHECK: @_T015generic_structs23DynamicWithRequirementsVMP = internal global <{ {{.*}} }> <{
// -- field offset vector; generic parameter vector
-// CHECK: i64 0, i64 0, %swift.type* null, %swift.type* null, i8** null, i8** null,
-// CHECK: }>
+// CHECK: i64 0, i64 0, %swift.type* null, %swift.type* null, i8** null, i8** null }>
// -- Fixed-layout struct metadata contains fixed field offsets
// CHECK: @_T015generic_structs6IntishVMf = internal constant <{ {{.*}} i64 }> <{
@@ -219,16 +217,11 @@
// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 3
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8*
// CHECK: store i8* [[T0]], i8** [[T1]], align 8
-// Fill vwtable reference.
-// CHECK: [[VWTABLE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 4
-// CHECK: [[VWTABLE_VAL:%.*]] = bitcast i8** [[VWTABLE_ADDR]] to i8*
-// CHECK: [[VWTABLE_SLOT_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 -1
-// CHECK: store i8* [[VWTABLE_VAL]], i8** [[VWTABLE_SLOT_ADDR]], align 8
// Lay out fields.
// CHECK: [[T0:%.*]] = bitcast %swift.type* [[METADATA]] to i64*
// CHECK: [[T1:%.*]] = getelementptr inbounds i64, i64* [[T0]], i64 2
// CHECK: [[T2:%.*]] = getelementptr inbounds i8**, i8*** [[TYPES:%.*]], i32 0
-// CHECK: call void @swift_initStructMetadata_UniversalStrategy(i64 1, i8*** [[TYPES]], i64* [[T1]], i8** [[VWTABLE_ADDR]])
+// CHECK: call void @swift_initStructMetadata(%swift.type* [[METADATA]], i64 0, i64 1, i8*** [[TYPES]], i64* [[T1]])
// CHECK: ret %swift.type* [[METADATA]]
// CHECK: }
diff --git a/test/IRGen/generic_types.swift b/test/IRGen/generic_types.swift
index bf3eb6f..8a28b8f 100644
--- a/test/IRGen/generic_types.swift
+++ b/test/IRGen/generic_types.swift
@@ -23,8 +23,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
-// CHECK-SAME: i64 1,
-// CHECK-SAME: i32 3,
+// CHECK-SAME: i64 {{1|2}},
+// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
@@ -52,8 +52,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
-// CHECK-SAME: i64 1,
-// CHECK-SAME: i32 3,
+// CHECK-SAME: i64 {{1|2}},
+// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
@@ -74,8 +74,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
-// CHECK-SAME: i64 1,
-// CHECK-SAME: i32 3,
+// CHECK-SAME: i64 {{1|2}},
+// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
@@ -96,8 +96,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
-// CHECK-SAME: i64 1,
-// CHECK-SAME: i32 3,
+// CHECK-SAME: i64 {{1|2}},
+// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
diff --git a/test/IRGen/indirect_return.swift b/test/IRGen/indirect_return.swift
index 1633bd5..147df3a 100644
--- a/test/IRGen/indirect_return.swift
+++ b/test/IRGen/indirect_return.swift
@@ -9,3 +9,18 @@
// CHECK: call %swift.opaque* {{%.*}}(%swift.opaque* noalias %0, %swift.opaque* noalias [[T1]], %swift.type* %T)
return p.pointee
}
+
+
+protocol Number {}
+extension Int: Number {}
+
+// Make sure that the absence of the sret attribute matches.
+// CHECK: define hidden swiftcc void @_T015indirect_return3fooSS_S2SAA6Number_pAaC_ptyF(<{ %TSS, %TSS, %TSS }>* noalias nocapture
+func foo() -> (String, String, String, Number, Number) {
+ return ("1", "2", "3", 42, 7)
+}
+// CHECK-LABEL: define{{.*}}testCall
+func testCall() {
+// CHECK: call swiftcc void @_T015indirect_return3fooSS_S2SAA6Number_pAaC_ptyF(<{ %TSS, %TSS, %TSS }>* noalias nocapture %{{.*}}
+ print(foo())
+}
diff --git a/test/IRGen/ivar_destroyer.sil b/test/IRGen/ivar_destroyer.sil
index d26c81c..e8014e8 100644
--- a/test/IRGen/ivar_destroyer.sil
+++ b/test/IRGen/ivar_destroyer.sil
@@ -14,8 +14,8 @@
// \ CHECK: [[TYPE]]* bitcast (i64* getelementptr inbounds (<{ {{.*}} }>, <{ {{.*}} }>* @_T014ivar_destroyer11TrivialBaseCMf, i32 0, i32 2) to [[TYPE]]*),
// \ CHECK: [[OPAQUE]]* @_objc_empty_cache,
// \ CHECK: [[OPAQUE]]* null,
-// \ CHECK: i64 add (i64 ptrtoint ({{.*}}* @_DATA__TtC14ivar_destroyer17NonTrivialDerived to i64), i64 1),
-// \ CHECK: i32 3,
+// \ CHECK: i64 add (i64 ptrtoint ({{.*}}* @_DATA__TtC14ivar_destroyer17NonTrivialDerived to i64), i64 {{1|2}}),
+// \ CHECK: i32 2,
// \ CHECK: i32 0,
// \ CHECK: i32 24,
// \ CHECK: i16 7,
diff --git a/test/IRGen/objc_attr_NSManaged.sil b/test/IRGen/objc_attr_NSManaged.sil
index 98c08c2..cafd182 100644
--- a/test/IRGen/objc_attr_NSManaged.sil
+++ b/test/IRGen/objc_attr_NSManaged.sil
@@ -27,7 +27,7 @@
// The getter/setter should not show up in the Swift metadata.
/* FIXME: sil_vtable parser picks the wrong 'init' overload. Both vtable entries
ought to be nonnull here. rdar://problem/19572342 */
-// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 1), i32 1, i32 0, i32 8, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoC7bellsOnACSi_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }>
+// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 {{1|2}}), i32 0, i32 0, i32 8, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoC7bellsOnACSi_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }>
@objc class SwiftGizmo : Gizmo {
@objc @NSManaged var x: X
diff --git a/test/IRGen/struct_resilience.swift b/test/IRGen/struct_resilience.swift
index 85105ca..a06fbd6 100644
--- a/test/IRGen/struct_resilience.swift
+++ b/test/IRGen/struct_resilience.swift
@@ -170,7 +170,6 @@
// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_StructWithResilientStorage(i8*)
// CHECK: [[FIELDS:%.*]] = alloca [4 x i8**]
-// CHECK: [[VWT:%.*]] = load i8**, i8*** getelementptr inbounds ({{.*}} @_T017struct_resilience26StructWithResilientStorageVMf{{.*}}, [[INT]] -1)
// CHECK: [[FIELDS_ADDR:%.*]] = getelementptr inbounds [4 x i8**], [4 x i8**]* [[FIELDS]], i32 0, i32 0
@@ -195,6 +194,6 @@
// CHECK: [[FIELD_4:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 3
// CHECK: store i8** [[SIZE_AND_ALIGNMENT:%.*]], i8*** [[FIELD_4]]
-// CHECK: call void @swift_initStructMetadata_UniversalStrategy([[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* {{.*}}, i8** [[VWT]])
+// CHECK: call void @swift_initStructMetadata(%swift.type* {{.*}}, [[INT]] 256, [[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* {{.*}})
// CHECK: store atomic %swift.type* {{.*}} @_T017struct_resilience26StructWithResilientStorageVMf{{.*}}, %swift.type** @_T017struct_resilience26StructWithResilientStorageVML release,
// CHECK: ret void
diff --git a/test/IRGen/vtable.sil b/test/IRGen/vtable.sil
index 3234030..dc451a0 100644
--- a/test/IRGen/vtable.sil
+++ b/test/IRGen/vtable.sil
@@ -26,8 +26,8 @@
// CHECK-objc: %objc_class* @"OBJC_CLASS_$_SwiftObject",
// CHECK-objc: %swift.opaque* @_objc_empty_cache,
// CHECK-objc: %swift.opaque* null,
-// CHECK-objc: i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @_DATA__TtC6vtable1C to i64), i64 1),
-// CHECK-objc: i32 3, i32 0, i32 16, i16 7, i16 0,
+// CHECK-objc: i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @_DATA__TtC6vtable1C to i64), i64 {{1|2}}),
+// CHECK-objc: i32 2, i32 0, i32 16, i16 7, i16 0,
// CHECK-objc: i32 112, i32 16,
// CHECK-objc: @_T06vtable1CCMn
// CHECK-objc: [[C]]* (%swift.type*)* @_T06vtable1CCACycACmcfC,
@@ -42,7 +42,7 @@
// CHECK-native: %swift.opaque* null,
// CHECK-native: %swift.opaque* null,
// CHECK-native: i64 1,
-// CHECK-native: i32 3, i32 0, i32 16, i16 7, i16 0,
+// CHECK-native: i32 2, i32 0, i32 16, i16 7, i16 0,
// CHECK-native: i32 112, i32 16,
// CHECK-native: @_T06vtable1CCMn
// CHECK-native: [[C]]* (%swift.type*)* @_T06vtable1CCACycACmcfC,
diff --git a/test/IRGen/witness_method.sil b/test/IRGen/witness_method.sil
index 3669da7..09cd5e3 100644
--- a/test/IRGen/witness_method.sil
+++ b/test/IRGen/witness_method.sil
@@ -110,7 +110,7 @@
func disrupt() -> GrowthHack
}
-// CHECK-LABEL: define{{( protected)?}} swiftcc void @classArchetypeWitnessMethod(%swift.type* %CoverSheet, %T14witness_method9TPSReportC** noalias nocapture swiftself dereferenceable({{4|8}}), %swift.type* %Self, i8** %SelfWitnessTable)
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @classArchetypeWitnessMethod(%T14witness_method9TPSReportC** noalias nocapture swiftself dereferenceable({{4|8}}), %swift.type* %Self, i8** %SelfWitnessTable)
sil @classArchetypeWitnessMethod : $@convention(witness_method: Strategy) <T><CoverSheet where T : TPSReport<CoverSheet>> (@in_guaranteed T) -> () {
entry(%self : $*T):
diff --git a/test/Interpreter/enforce_exclusive_access.swift b/test/Interpreter/enforce_exclusive_access.swift
index 40fd5bf..3d17b75 100644
--- a/test/Interpreter/enforce_exclusive_access.swift
+++ b/test/Interpreter/enforce_exclusive_access.swift
@@ -104,66 +104,6 @@
globalX = X() // no-trap
}
-// FIXME: This should be covered by static diagnostics.
-// Once this radar is fixed, confirm that a it is covered by a static diagnostic
-// (-verify) test in exclusivity_static_diagnostics.sil.
-// <rdar://problem/32061282> Enforce exclusive access in noescape closures.
-//
-//ExclusiveAccessTestSuite.test("ClosureCaptureModifyModify")
-//.skip(.custom(
-// { _isFastAssertConfiguration() },
-// reason: "this trap is not guaranteed to happen in -Ounchecked"))
-// .crashOutputMatches("Previous access (a modification) started at")
-// .crashOutputMatches("Current access (a modification) started at")
-// .code
-//{
-// var x = X()
-// modifyAndPerform(&x) {
-// expectCrashLater()
-// x.i = 12
-// }
-//}
-
-// FIXME: This should be covered by static diagnostics.
-// Once this radar is fixed, confirm that a it is covered by a static diagnostic
-// (-verify) test in exclusivity_static_diagnostics.sil.
-// <rdar://problem/32061282> Enforce exclusive access in noescape closures.
-//
-//ExclusiveAccessTestSuite.test("ClosureCaptureReadModify")
-//.skip(.custom(
-// { _isFastAssertConfiguration() },
-// reason: "this trap is not guaranteed to happen in -Ounchecked"))
-// .crashOutputMatches("Previous access (a read) started at")
-// .crashOutputMatches("Current access (a modification) started at")
-// .code
-//{
-// var x = X()
-// modifyAndPerform(&x) {
-// expectCrashLater()
-// _blackHole(x.i)
-// }
-//}
-
-// FIXME: This should be covered by static diagnostics.
-// Once this radar is fixed, confirm that a it is covered by a static diagnostic
-// (-verify) test in exclusivity_static_diagnostics.sil.
-// <rdar://problem/32061282> Enforce exclusive access in noescape closures.
-//
-//ExclusiveAccessTestSuite.test("ClosureCaptureModifyRead")
-//.skip(.custom(
-// { _isFastAssertConfiguration() },
-// reason: "this trap is not guaranteed to happen in -Ounchecked"))
-// .crashOutputMatches("Previous access (a modification) started at")
-// .crashOutputMatches("Current access (a read) started at")
-// .code
-//{
-// var x = X()
-// readAndPerform(&x) {
-// expectCrashLater()
-// x.i = 12
-// }
-//}
-
ExclusiveAccessTestSuite.test("ClosureCaptureReadRead") {
var x = X()
readAndPerform(&x) {
@@ -301,4 +241,27 @@
doOne { modifyAndPerform(&x, closure: c) }
}
+class ClassWithStoredProperty {
+ var f = 7
+}
+
+// FIXME: This should trap with a modify/modify violation at run time.
+ExclusiveAccessTestSuite.test("KeyPathClassStoredProp")
+ .skip(.custom(
+ { _isFastAssertConfiguration() },
+ reason: "this trap is not guaranteed to happen in -Ounchecked"))
+// .crashOutputMatches("Previous access (a modification) started at")
+// .crashOutputMatches("Current access (a modification) started at")
+ .code
+{
+ let getF = \ClassWithStoredProperty.f
+ let c = ClassWithStoredProperty()
+
+// expectCrashLater()
+ modifyAndPerform(&c[keyPath: getF]) {
+ c[keyPath: getF] = 12
+ }
+}
+
+
runAllTests()
diff --git a/test/Interpreter/functions.swift b/test/Interpreter/functions.swift
index 891948b..9238a20 100644
--- a/test/Interpreter/functions.swift
+++ b/test/Interpreter/functions.swift
@@ -42,3 +42,13 @@
foo(D())
// CHECK: Right
bar(D())
+
+protocol Number {}
+extension Int: Number {}
+
+func foo() -> (String, String, String, Number, Number) {
+ return ("1", "2", "3", 42, 7)
+}
+
+// CHECK: ("1", "2", "3", 42, 7)
+print(foo())
diff --git a/test/Interpreter/protocol_extensions.swift b/test/Interpreter/protocol_extensions.swift
index ab001b7..1b15052 100644
--- a/test/Interpreter/protocol_extensions.swift
+++ b/test/Interpreter/protocol_extensions.swift
@@ -315,6 +315,8 @@
class SelfMetadataDerived : SelfMetadataBase {}
+class SelfMetadataGeneric<T> : SelfMetadataTest {}
+
func testSelfMetadata<T : SelfMetadataTest>(_ x: T, _ t: T.T) -> [Any.Type] {
return [x.staticTypeOfSelf(),
x.staticTypeOfSelfTakesT(t),
@@ -348,6 +350,16 @@
expectTrue(SelfMetadataDerived.self == result[2])
expectTrue(SelfMetadataDerived.self == result[3])
}
+
+ // Make sure the calling convention works out if 'Self' is a generic
+ // class too.
+ do {
+ let result = testSelfMetadata(SelfMetadataGeneric<Int>(), 0)
+ expectTrue(SelfMetadataGeneric<Int>.self == result[0])
+ expectTrue(SelfMetadataGeneric<Int>.self == result[1])
+ expectTrue(SelfMetadataGeneric<Int>.self == result[2])
+ expectTrue(SelfMetadataGeneric<Int>.self == result[3])
+ }
}
runAllTests()
diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift
index e6c6408..41e7f26 100644
--- a/test/SILGen/default_arguments.swift
+++ b/test/SILGen/default_arguments.swift
@@ -12,7 +12,7 @@
// CHECK-LABEL: sil hidden @_T017default_arguments7defarg11i1d1sySi_SdSStFfA_ : $@convention(thin) () -> Int
// CHECK: [[INT:%[0-9]+]] = metatype $@thin Int.Type
// CHECK: [[LIT:%[0-9]+]] = integer_literal $Builtin.Int2048, 17
-// CHECK: [[CVT:%[0-9]+]] = function_ref @_T0Si22_builtinIntegerLiteralSiBi2048__tcfC
+// CHECK: [[CVT:%[0-9]+]] = function_ref @_T0Si22_builtinIntegerLiteralSiBi{{[_0-9]*}}__tcfC
// CHECK: [[RESULT:%[0-9]+]] = apply [[CVT]]([[LIT]], [[INT]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
// CHECK: return [[RESULT]] : $Int
@@ -30,7 +30,7 @@
func testDefaultArg1() {
// CHECK: [[FLOAT64:%[0-9]+]] = metatype $@thin Double.Type
// CHECK: [[FLOATLIT:%[0-9]+]] = float_literal $Builtin.FPIEEE{{64|80}}, {{0x4009000000000000|0x4000C800000000000000}}
- // CHECK: [[LITFN:%[0-9]+]] = function_ref @_T0Sd20_builtinFloatLiteralSdBf80__tcfC
+ // CHECK: [[LITFN:%[0-9]+]] = function_ref @_T0Sd20_builtinFloatLiteralSdBf{{[_0-9]*}}__tcfC
// CHECK: [[FLOATVAL:%[0-9]+]] = apply [[LITFN]]([[FLOATLIT]], [[FLOAT64]])
// CHECK: [[DEF0FN:%[0-9]+]] = function_ref @_T017default_arguments7defarg1{{.*}}A_
// CHECK: [[DEF0:%[0-9]+]] = apply [[DEF0FN]]()
@@ -47,7 +47,7 @@
func testDefaultArg2() {
// CHECK: [[INT64:%[0-9]+]] = metatype $@thin Int.Type
// CHECK: [[INTLIT:%[0-9]+]] = integer_literal $Builtin.Int2048, 5
-// CHECK: [[LITFN:%[0-9]+]] = function_ref @_T0Si22_builtinIntegerLiteralSiBi2048__tcfC
+// CHECK: [[LITFN:%[0-9]+]] = function_ref @_T0Si22_builtinIntegerLiteralSiBi{{[_0-9]*}}__tcfC
// CHECK: [[I:%[0-9]+]] = apply [[LITFN]]([[INTLIT]], [[INT64]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
// CHECK: [[DFN:%[0-9]+]] = function_ref @_T017default_arguments7defarg2{{.*}}A0_ : $@convention(thin) () -> Double
// CHECK: [[D:%[0-9]+]] = apply [[DFN]]() : $@convention(thin) () -> Double
diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.swift b/test/SILOptimizer/exclusivity_static_diagnostics.swift
index 6c0a94c..99a0d25 100644
--- a/test/SILOptimizer/exclusivity_static_diagnostics.swift
+++ b/test/SILOptimizer/exclusivity_static_diagnostics.swift
@@ -64,6 +64,7 @@
class ClassWithFinalStoredProp {
final var s1: StructWithMutatingMethodThatTakesSelfInout = StructWithMutatingMethodThatTakesSelfInout()
final var s2: StructWithMutatingMethodThatTakesSelfInout = StructWithMutatingMethodThatTakesSelfInout()
+ final var i = 7
func callMutatingMethodThatTakesClassStoredPropInout() {
s1.mutate(&s2.f) // no-warning
@@ -195,6 +196,13 @@
}
}
+func callsTakesInoutAndNoEscapeClosureWithRead() {
+ var local = 5
+ takesInoutAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}}
+ _ = local // expected-note {{conflicting access is here}}
+ }
+}
+
func takesInoutAndNoEscapeClosureThatThrows<T>(_ p: inout T, _ c: () throws -> ()) { }
func callsTakesInoutAndNoEscapeClosureThatThrowsWithNonThrowingClosure() {
@@ -252,8 +260,15 @@
}
+// Calling this with an inout expression for the first parameter performs a
+// read access for the duration of a call
func takesUnsafePointerAndNoEscapeClosure<T>(_ p: UnsafePointer<T>, _ c: () -> ()) { }
+// Calling this with an inout expression for the first parameter performs a
+// modify access for the duration of a call
+func takesUnsafeMutablePointerAndNoEscapeClosure<T>(_ p: UnsafeMutablePointer<T>, _ c: () -> ()) { }
+
+
func callsTakesUnsafePointerAndNoEscapeClosure() {
var local = 1
takesUnsafePointerAndNoEscapeClosure(&local) { // expected-note {{conflicting access is here}}
@@ -261,6 +276,24 @@
}
}
+func callsTakesUnsafePointerAndNoEscapeClosureThatReads() {
+ var local = 1
+
+ // Overlapping reads
+ takesUnsafePointerAndNoEscapeClosure(&local) {
+ _ = local // no-error
+ }
+}
+
+func callsTakesUnsafeMutablePointerAndNoEscapeClosureThatReads() {
+ var local = 1
+
+ // Overlapping modify and read
+ takesUnsafeMutablePointerAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}}
+ _ = local // expected-note {{conflicting access is here}}
+ }
+
+}
func takesThrowingAutoClosureReturningGeneric<T: Equatable>(_ : @autoclosure () throws -> T) { }
func takesInoutAndClosure<T>(_: inout T, _ : () -> ()) { }
@@ -468,3 +501,29 @@
// expected-note@-2{{conflicting access is here}}
}
}
+
+
+func testForLoopCausesReadAccess() {
+ var a: [Int] = [1]
+ takesInoutAndNoEscapeClosure(&a) { // expected-error {{overlapping accesses to 'a', but modification requires exclusive access; consider copying to a local variable}}
+ for _ in a { // expected-note {{conflicting access is here}}
+ }
+ }
+}
+
+func testKeyPathStructField() {
+ let getF = \StructWithField.f
+ var local = StructWithField()
+ takesInoutAndNoEscapeClosure(&local[keyPath: getF]) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}}
+ local.f = 17 // expected-note {{conflicting access is here}}
+ }
+}
+
+func testKeyPathWithClassFinalStoredProperty() {
+ let getI = \ClassWithFinalStoredProp.i
+ let local = ClassWithFinalStoredProp()
+
+ // Ideally we would diagnose statically here, but it is not required by the
+ // model.
+ takesTwoInouts(&local[keyPath: getI], &local[keyPath: getI])
+}
diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds
index 0a0f4ce..394bf76 100644
--- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds
+++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds
@@ -34,6 +34,7 @@
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><IdentifierExpr>bar2</IdentifierExpr>(<FunctionCallArgument>a : <IdentifierExpr>bar2</IdentifierExpr>(<FunctionCallArgument>a: <IntegerLiteralExpr>1</IntegerLiteralExpr>, </FunctionCallArgument><FunctionCallArgument>b: <IntegerLiteralExpr>2</IntegerLiteralExpr>, </FunctionCallArgument><FunctionCallArgument>c: <IntegerLiteralExpr>3</IntegerLiteralExpr></FunctionCallArgument>), </FunctionCallArgument><FunctionCallArgument>b: <IntegerLiteralExpr>2</IntegerLiteralExpr>, </FunctionCallArgument><FunctionCallArgument>c: <IntegerLiteralExpr>3</IntegerLiteralExpr></FunctionCallArgument>)</SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a : <IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a: <IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a: <IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>)</FunctionCallArgument>)</FunctionCallArgument>)</SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><IdentifierExpr>bar4</IdentifierExpr>(<FunctionCallArgument><IdentifierExpr>bar4</IdentifierExpr>(<FunctionCallArgument><IdentifierExpr>bar4</IdentifierExpr>(<FunctionCallArgument><IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>)</FunctionCallArgument>)</FunctionCallArgument>)</SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
+ _ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><DictionaryExpr>[:]</DictionaryExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><ArrayExpr>[<ArrayElement><IntegerLiteralExpr>1</IntegerLiteralExpr>, </ArrayElement><ArrayElement><IntegerLiteralExpr>2</IntegerLiteralExpr>, </ArrayElement><ArrayElement><IntegerLiteralExpr>3</IntegerLiteralExpr>, </ArrayElement><ArrayElement><IntegerLiteralExpr>4</IntegerLiteralExpr></ArrayElement>]</ArrayExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><DictionaryExpr>[<DictionaryElement><IntegerLiteralExpr>1</IntegerLiteralExpr>:<IntegerLiteralExpr>1</IntegerLiteralExpr>, </DictionaryElement><DictionaryElement><IntegerLiteralExpr>2</IntegerLiteralExpr>:<IntegerLiteralExpr>2</IntegerLiteralExpr>, </DictionaryElement><DictionaryElement><IntegerLiteralExpr>3</IntegerLiteralExpr>:<IntegerLiteralExpr>3</IntegerLiteralExpr>, </DictionaryElement><DictionaryElement><IntegerLiteralExpr>4</IntegerLiteralExpr>:<IntegerLiteralExpr>4</IntegerLiteralExpr></DictionaryElement>]</DictionaryExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><ArrayExpr>[<ArrayElement><IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a:<IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>), </ArrayElement><ArrayElement><IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a:<IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>), </ArrayElement><ArrayElement><IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a:<IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>), </ArrayElement><ArrayElement><IdentifierExpr>bar3</IdentifierExpr>(<FunctionCallArgument>a:<IntegerLiteralExpr>1</IntegerLiteralExpr></FunctionCallArgument>)</ArrayElement>]</ArrayExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
@@ -49,10 +50,10 @@
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><TupleExpr>(<TupleElement><IntegerLiteralExpr>1</IntegerLiteralExpr>, </TupleElement><TupleElement><IntegerLiteralExpr>2</IntegerLiteralExpr></TupleElement>)</TupleExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><TupleExpr>(<TupleElement>first: <IntegerLiteralExpr>1</IntegerLiteralExpr>, </TupleElement><TupleElement>second: <IntegerLiteralExpr>2</IntegerLiteralExpr></TupleElement>)</TupleExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
_ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><TupleExpr>(<TupleElement><IntegerLiteralExpr>1</IntegerLiteralExpr></TupleElement>)</TupleExpr></SequenceExpr><SequenceExpr><DiscardAssignmentExpr>
- _ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><TupleExpr>(<TupleElement>first: <IntegerLiteralExpr>1</IntegerLiteralExpr></TupleElement>)</TupleExpr></SequenceExpr>
- if <PrefixOperatorExpr>!<BooleanLiteralExpr>true </BooleanLiteralExpr></PrefixOperatorExpr><CodeBlock>{<ReturnStmt>
+ _ </DiscardAssignmentExpr><AssignmentExpr>= </AssignmentExpr><TupleExpr>(<TupleElement>first: <IntegerLiteralExpr>1</IntegerLiteralExpr></TupleElement>)</TupleExpr></SequenceExpr><IfStmt>
+ if <ConditionElement><PrefixOperatorExpr>!<BooleanLiteralExpr>true </BooleanLiteralExpr></PrefixOperatorExpr></ConditionElement><CodeBlock>{<ReturnStmt>
return</ReturnStmt>
- }</CodeBlock>
+ }</CodeBlock></IfStmt>
}</CodeBlock></FunctionDecl><FunctionDecl>
func foo3<FunctionSignature><ParameterClause>() </ParameterClause></FunctionSignature><CodeBlock>{<SequenceExpr><DiscardAssignmentExpr>
@@ -213,6 +214,71 @@
class C <MemberDeclBlock>{<VariableDecl><Attribute>
@objc</Attribute><DeclModifier>
- static </DeclModifier><DeclModifier>private </DeclModifier>var <PatternBinding><IdentifierPattern>a</IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></TypeAnnotation><InitializerClause>= <IntegerLiteralExpr>3 </IntegerLiteralExpr></InitializerClause><AccessorBlock>{ <ReturnStmt>return <IntegerLiteralExpr>3 </IntegerLiteralExpr></ReturnStmt>}</AccessorBlock>, </PatternBinding><PatternBinding><IdentifierPattern>b</IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int</SimpleTypeIdentifier></TypeAnnotation>, </PatternBinding><PatternBinding><IdentifierPattern>c </IdentifierPattern><InitializerClause>= <IntegerLiteralExpr>4</IntegerLiteralExpr></InitializerClause>, </PatternBinding><PatternBinding><IdentifierPattern>d </IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></TypeAnnotation><AccessorBlock>{ <AccessorDecl>get <CodeBlock>{} </CodeBlock></AccessorDecl><AccessorDecl>get <CodeBlock>{}</CodeBlock></AccessorDecl>}</AccessorBlock>, </PatternBinding><PatternBinding>(<IdentifierPattern>a</IdentifierPattern>, <IdentifierPattern>b</IdentifierPattern>)<TypeAnnotation>: <TupleType>(<TupleTypeElement><SimpleTypeIdentifier>Int</SimpleTypeIdentifier>, </TupleTypeElement><TupleTypeElement><SimpleTypeIdentifier>Int</SimpleTypeIdentifier></TupleTypeElement>)</TupleType></TypeAnnotation></PatternBinding></VariableDecl><VariableDecl>
- let <PatternBinding>(<IdentifierPattern>a</IdentifierPattern>, <IdentifierPattern>b</IdentifierPattern>) <InitializerClause>= <TupleExpr>(<TupleElement><IntegerLiteralExpr>1</IntegerLiteralExpr>,</TupleElement><TupleElement><IntegerLiteralExpr>2</IntegerLiteralExpr></TupleElement>)</TupleExpr></InitializerClause>, </PatternBinding><PatternBinding>_ <InitializerClause>= <IntegerLiteralExpr>4 </IntegerLiteralExpr></InitializerClause><AccessorBlock>{}</AccessorBlock></PatternBinding></VariableDecl>
-}</MemberDeclBlock></ClassDecl>
+ static </DeclModifier><DeclModifier>private </DeclModifier>var <PatternBinding><IdentifierPattern>a</IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></TypeAnnotation><InitializerClause>= <IntegerLiteralExpr>3 </IntegerLiteralExpr></InitializerClause><AccessorBlock>{ <ReturnStmt>return <IntegerLiteralExpr>3 </IntegerLiteralExpr></ReturnStmt>}</AccessorBlock>, </PatternBinding><PatternBinding><IdentifierPattern>b</IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int</SimpleTypeIdentifier></TypeAnnotation>, </PatternBinding><PatternBinding><IdentifierPattern>c </IdentifierPattern><InitializerClause>= <IntegerLiteralExpr>4</IntegerLiteralExpr></InitializerClause>, </PatternBinding><PatternBinding><IdentifierPattern>d </IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></TypeAnnotation><AccessorBlock>{ <AccessorDecl>get <CodeBlock>{} </CodeBlock></AccessorDecl><AccessorDecl>get <CodeBlock>{}</CodeBlock></AccessorDecl>}</AccessorBlock>, </PatternBinding><PatternBinding><TuplePattern>(<TuplePatternElement><IdentifierPattern>a</IdentifierPattern>, </TuplePatternElement><TuplePatternElement><IdentifierPattern>b</IdentifierPattern></TuplePatternElement>)</TuplePattern><TypeAnnotation>: <TupleType>(<TupleTypeElement><SimpleTypeIdentifier>Int</SimpleTypeIdentifier>, </TupleTypeElement><TupleTypeElement><SimpleTypeIdentifier>Int</SimpleTypeIdentifier></TupleTypeElement>)</TupleType></TypeAnnotation></PatternBinding></VariableDecl><VariableDecl>
+ let <PatternBinding><TuplePattern>(<TuplePatternElement><IdentifierPattern>a</IdentifierPattern>, </TuplePatternElement><TuplePatternElement><IdentifierPattern>b</IdentifierPattern></TuplePatternElement>) </TuplePattern><InitializerClause>= <TupleExpr>(<TupleElement><IntegerLiteralExpr>1</IntegerLiteralExpr>,</TupleElement><TupleElement><IntegerLiteralExpr>2</IntegerLiteralExpr></TupleElement>)</TupleExpr></InitializerClause>, </PatternBinding><PatternBinding><WildcardPattern>_ </WildcardPattern><InitializerClause>= <IntegerLiteralExpr>4 </IntegerLiteralExpr></InitializerClause><AccessorBlock>{}</AccessorBlock></PatternBinding></VariableDecl><FunctionDecl>
+
+ func patternTests<FunctionSignature><ParameterClause>() </ParameterClause></FunctionSignature><CodeBlock>{<ForInStmt>
+ for <ValueBindingPattern>let <TuplePattern>(<TuplePatternElement><IdentifierPattern>x</IdentifierPattern>, </TuplePatternElement><TuplePatternElement><WildcardPattern>_</WildcardPattern></TuplePatternElement>) </TuplePattern></ValueBindingPattern>in <IdentifierExpr>foo </IdentifierExpr><CodeBlock>{}</CodeBlock></ForInStmt><ForInStmt>
+ for <ValueBindingPattern>var <IdentifierPattern>x</IdentifierPattern></ValueBindingPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></TypeAnnotation>in <IdentifierExpr>foo </IdentifierExpr><CodeBlock>{}</CodeBlock></ForInStmt>
+ }</CodeBlock></FunctionDecl>
+}</MemberDeclBlock></ClassDecl><DoStmt>
+
+do <CodeBlock>{
+ switch <IdentifierExpr>foo </IdentifierExpr>{
+ case <ValueBindingPattern>let <IdentifierPattern>a</IdentifierPattern></ValueBindingPattern>: <BreakStmt>break</BreakStmt>
+ case <ValueBindingPattern>let <ExpressionPattern><SequenceExpr><UnresolvedPatternExpr><IdentifierPattern>a </IdentifierPattern></UnresolvedPatternExpr><AsExpr>as <SimpleTypeIdentifier>Int</SimpleTypeIdentifier></AsExpr></SequenceExpr></ExpressionPattern></ValueBindingPattern>: <BreakStmt>break</BreakStmt>
+ case <ValueBindingPattern>let <ExpressionPattern><TupleExpr>(<TupleElement><UnresolvedPatternExpr><IdentifierPattern>a</IdentifierPattern></UnresolvedPatternExpr>, </TupleElement><TupleElement><UnresolvedPatternExpr><IdentifierPattern>b</IdentifierPattern></UnresolvedPatternExpr></TupleElement>)</TupleExpr></ExpressionPattern></ValueBindingPattern>: <BreakStmt>break</BreakStmt>
+ case <ExpressionPattern><TupleExpr>(<TupleElement><UnresolvedPatternExpr><ValueBindingPattern>let <IdentifierPattern>a</IdentifierPattern></ValueBindingPattern></UnresolvedPatternExpr>, </TupleElement><TupleElement><UnresolvedPatternExpr><ValueBindingPattern>var <IdentifierPattern>b</IdentifierPattern></ValueBindingPattern></UnresolvedPatternExpr></TupleElement>)</TupleExpr></ExpressionPattern>: <BreakStmt>break</BreakStmt>
+ case <IsTypePattern>is <SimpleTypeIdentifier>Int</SimpleTypeIdentifier></IsTypePattern>: <BreakStmt>break</BreakStmt>
+ case <ValueBindingPattern>let <ExpressionPattern>.bar(<FunctionCallArgument><UnresolvedPatternExpr><IdentifierPattern>x</IdentifierPattern></UnresolvedPatternExpr></FunctionCallArgument>)</ExpressionPattern></ValueBindingPattern>: <BreakStmt>break</BreakStmt>
+ case <ExpressionPattern><MemberAccessExpr><IdentifierExpr>MyEnum</IdentifierExpr>.foo</MemberAccessExpr></ExpressionPattern>: <BreakStmt>break</BreakStmt>
+ case <ValueBindingPattern>let <ExpressionPattern><SequenceExpr><UnresolvedPatternExpr><IdentifierPattern>a </IdentifierPattern></UnresolvedPatternExpr><AsExpr>as <SimpleTypeIdentifier>Int</SimpleTypeIdentifier></AsExpr></SequenceExpr></ExpressionPattern></ValueBindingPattern>: <BreakStmt>break</BreakStmt>
+ case <ValueBindingPattern>let <ExpressionPattern><UnresolvedPatternExpr><IdentifierPattern>a</IdentifierPattern></UnresolvedPatternExpr>?</ExpressionPattern></ValueBindingPattern>: <BreakStmt>break</BreakStmt>
+ }
+}</CodeBlock></DoStmt><FunctionDecl>
+
+func statementTests<FunctionSignature><ParameterClause>() </ParameterClause></FunctionSignature><CodeBlock>{<DoStmt>
+ do <CodeBlock>{
+ } </CodeBlock><CatchClause>catch <ExpressionPattern><TupleExpr>(<TupleElement><UnresolvedPatternExpr><ValueBindingPattern>var <IdentifierPattern>x</IdentifierPattern></ValueBindingPattern></UnresolvedPatternExpr>, </TupleElement><TupleElement><UnresolvedPatternExpr><ValueBindingPattern>let <IdentifierPattern>y</IdentifierPattern></ValueBindingPattern></UnresolvedPatternExpr></TupleElement>) </TupleExpr></ExpressionPattern><CodeBlock>{
+ } </CodeBlock></CatchClause><CatchClause>catch <WhereClause>where <BooleanLiteralExpr>false </BooleanLiteralExpr></WhereClause><CodeBlock>{
+ } </CodeBlock></CatchClause><CatchClause>catch <ValueBindingPattern>let <IdentifierPattern>e </IdentifierPattern></ValueBindingPattern><WhereClause>where <SequenceExpr><MemberAccessExpr><IdentifierExpr>e</IdentifierExpr>.foo </MemberAccessExpr><BinaryOperatorExpr>== </BinaryOperatorExpr><IdentifierExpr>bar </IdentifierExpr></SequenceExpr></WhereClause><CodeBlock>{
+ } </CodeBlock></CatchClause><CatchClause>catch <CodeBlock>{
+ }</CodeBlock></CatchClause></DoStmt><RepeatWhileStmt>
+ repeat <CodeBlock>{ } </CodeBlock>while <BooleanLiteralExpr>true</BooleanLiteralExpr></RepeatWhileStmt><RepeatWhileStmt>
+ LABEL: repeat <CodeBlock>{ } </CodeBlock>while <BooleanLiteralExpr>false</BooleanLiteralExpr></RepeatWhileStmt><DoStmt>
+ LABEL: do <CodeBlock>{}</CodeBlock></DoStmt>
+ LABEL: switch <IdentifierExpr>foo </IdentifierExpr>{
+ case <ExpressionPattern><IntegerLiteralExpr>1</IntegerLiteralExpr></ExpressionPattern>:<FallthroughStmt>
+ fallthrough</FallthroughStmt>
+ case <ExpressionPattern><IntegerLiteralExpr>2</IntegerLiteralExpr></ExpressionPattern>:<BreakStmt>
+ break LABEL</BreakStmt>
+ case <ExpressionPattern><IntegerLiteralExpr>3</IntegerLiteralExpr></ExpressionPattern>:<BreakStmt>
+ break</BreakStmt>
+ }<ForInStmt>
+
+ for <IdentifierPattern>a </IdentifierPattern>in <IdentifierExpr>b </IdentifierExpr><CodeBlock>{<DeferStmt>
+ defer <CodeBlock>{ <TupleExpr>() </TupleExpr>}</CodeBlock></DeferStmt><IfStmt>
+ if <ConditionElement><IdentifierExpr>c </IdentifierExpr></ConditionElement><CodeBlock>{<ThrowStmt>
+ throw <IdentifierExpr>MyError</IdentifierExpr>()</ThrowStmt><ContinueStmt>
+ continue</ContinueStmt>
+ } </CodeBlock>else <CodeBlock>{<ContinueStmt>
+ continue LABEL</ContinueStmt>
+ }</CodeBlock></IfStmt>
+ }</CodeBlock></ForInStmt><IfStmt>
+
+ if<ConditionElement><IdentifierExpr>
+ foo</IdentifierExpr>,</ConditionElement><ConditionElement><OptionalBindingCondition>
+ let <IdentifierPattern>a </IdentifierPattern><InitializerClause>= <IdentifierExpr>foo</IdentifierExpr></InitializerClause></OptionalBindingCondition>,</ConditionElement><ConditionElement><OptionalBindingCondition>
+ let <IdentifierPattern>b</IdentifierPattern><TypeAnnotation>: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></TypeAnnotation><InitializerClause>= <IdentifierExpr>foo</IdentifierExpr></InitializerClause></OptionalBindingCondition>,</ConditionElement><ConditionElement><OptionalBindingCondition>
+ var <IdentifierPattern>c </IdentifierPattern><InitializerClause>= <IdentifierExpr>foo</IdentifierExpr></InitializerClause></OptionalBindingCondition>,</ConditionElement><ConditionElement><MatchingPatternCondition>
+ case <ExpressionPattern><TupleExpr>(<TupleElement><UnresolvedPatternExpr><ValueBindingPattern>let <IdentifierPattern>v</IdentifierPattern></ValueBindingPattern></UnresolvedPatternExpr>, </TupleElement><TupleElement><DiscardAssignmentExpr>_</DiscardAssignmentExpr></TupleElement>) </TupleExpr></ExpressionPattern><InitializerClause>= <IdentifierExpr>foo</IdentifierExpr></InitializerClause></MatchingPatternCondition>,</ConditionElement><ConditionElement><MatchingPatternCondition>
+ case <ExpressionPattern><TupleExpr>(<TupleElement><UnresolvedPatternExpr><ValueBindingPattern>let <IdentifierPattern>v</IdentifierPattern></ValueBindingPattern></UnresolvedPatternExpr>, </TupleElement><TupleElement><DiscardAssignmentExpr>_</DiscardAssignmentExpr></TupleElement>)</TupleExpr></ExpressionPattern><TypeAnnotation>: <TupleType>(<TupleTypeElement><SimpleTypeIdentifier>Int</SimpleTypeIdentifier>, </TupleTypeElement><TupleTypeElement><SimpleTypeIdentifier>Int</SimpleTypeIdentifier></TupleTypeElement>) </TupleType></TypeAnnotation><InitializerClause>= <IdentifierExpr>foo </IdentifierExpr></InitializerClause></MatchingPatternCondition></ConditionElement><CodeBlock>{
+ } </CodeBlock>else <IfStmt>if <ConditionElement><IdentifierExpr>foo </IdentifierExpr></ConditionElement><CodeBlock>{
+ } </CodeBlock>else <CodeBlock>{
+ }</CodeBlock></IfStmt></IfStmt><GuardStmt>
+
+ guard <ConditionElement><OptionalBindingCondition>let <IdentifierPattern>a </IdentifierPattern><InitializerClause>= <IdentifierExpr>b </IdentifierExpr></InitializerClause></OptionalBindingCondition></ConditionElement>else <CodeBlock>{}</CodeBlock></GuardStmt><ForInStmt>
+
+ for <ValueBindingPattern>var <IdentifierPattern>i </IdentifierPattern></ValueBindingPattern>in <IdentifierExpr>foo </IdentifierExpr><WhereClause>where <MemberAccessExpr><IdentifierExpr>i</IdentifierExpr>.foo </MemberAccessExpr></WhereClause><CodeBlock>{}</CodeBlock></ForInStmt><ForInStmt>
+ for case <IsTypePattern>is <SimpleTypeIdentifier>Int </SimpleTypeIdentifier></IsTypePattern>in <IdentifierExpr>foo </IdentifierExpr><CodeBlock>{}</CodeBlock></ForInStmt>
+}</CodeBlock></FunctionDecl>
diff --git a/test/Syntax/round_trip_parse_gen.swift b/test/Syntax/round_trip_parse_gen.swift
index 9f1329d..c8734c3 100644
--- a/test/Syntax/round_trip_parse_gen.swift
+++ b/test/Syntax/round_trip_parse_gen.swift
@@ -34,6 +34,7 @@
_ = bar2(a : bar2(a: 1, b: 2, c: 3), b: 2, c: 3)
_ = bar3(a : bar3(a: bar3(a: 1)))
_ = bar4(bar4(bar4(1)))
+ _ = [:]
_ = [1, 2, 3, 4]
_ = [1:1, 2:2, 3:3, 4:4]
_ = [bar3(a:1), bar3(a:1), bar3(a:1), bar3(a:1)]
@@ -215,4 +216,69 @@
@objc
static private var a: Int = 3 { return 3 }, b: Int, c = 4, d : Int { get {} get {}}, (a, b): (Int, Int)
let (a, b) = (1,2), _ = 4 {}
+
+ func patternTests() {
+ for let (x, _) in foo {}
+ for var x: Int in foo {}
+ }
+}
+
+do {
+ switch foo {
+ case let a: break
+ case let a as Int: break
+ case let (a, b): break
+ case (let a, var b): break
+ case is Int: break
+ case let .bar(x): break
+ case MyEnum.foo: break
+ case let a as Int: break
+ case let a?: break
+ }
+}
+
+func statementTests() {
+ do {
+ } catch (var x, let y) {
+ } catch where false {
+ } catch let e where e.foo == bar {
+ } catch {
+ }
+ repeat { } while true
+ LABEL: repeat { } while false
+ LABEL: do {}
+ LABEL: switch foo {
+ case 1:
+ fallthrough
+ case 2:
+ break LABEL
+ case 3:
+ break
+ }
+
+ for a in b {
+ defer { () }
+ if c {
+ throw MyError()
+ continue
+ } else {
+ continue LABEL
+ }
+ }
+
+ if
+ foo,
+ let a = foo,
+ let b: Int = foo,
+ var c = foo,
+ case (let v, _) = foo,
+ case (let v, _): (Int, Int) = foo {
+ } else if foo {
+ } else {
+ }
+
+ guard let a = b else {}
+
+ for var i in foo where i.foo {}
+ for case is Int in foo {}
}
diff --git a/test/decl/protocol/req/associated_type_typealias_implements.swift b/test/decl/protocol/req/associated_type_typealias_implements.swift
new file mode 100644
index 0000000..8c85bef
--- /dev/null
+++ b/test/decl/protocol/req/associated_type_typealias_implements.swift
@@ -0,0 +1,38 @@
+// RUN: %target-typecheck-verify-swift
+
+protocol P { }
+
+protocol Q {
+ associatedtype T
+ associatedtype U // expected-note 2{{protocol requires nested type 'U'; do you want to add it?}}
+}
+
+protocol R: Q {
+}
+
+struct XT: P { }
+struct XTWithoutP { }
+
+struct XU { }
+
+extension R where T: P {
+ @_implements(Q, U)
+ typealias _Default_U = XU
+}
+
+struct Y1: R {
+ typealias T = XT
+ // okay: infers U = XU
+}
+
+struct Y2: R { // expected-error{{type 'Y2' does not conform to protocol 'Q'}}
+ typealias T = XTWithoutP
+
+ // FIXME: More detail from diagnostic.
+ // error: T: P fails
+}
+
+struct Y3: Q { // expected-error{{type 'Y3' does not conform to protocol 'Q'}}
+ typealias T = XT
+ // FIXME: More detail from diagnostic.
+}
diff --git a/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L14-3.swift.expected b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L14-3.swift.expected
new file mode 100644
index 0000000..edaa618
--- /dev/null
+++ b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L14-3.swift.expected
@@ -0,0 +1,20 @@
+func testConvertToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ if a < 5 {
+ x = a
+ } else {
+ x = b
+ }
+}
+func testConvertTupleToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y): (Int, Int) = a < 5 ? (a, b) : (b, a)
+}
+
+
+
+
+
diff --git a/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L15-3.swift.expected b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L15-3.swift.expected
new file mode 100644
index 0000000..0b67708
--- /dev/null
+++ b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L15-3.swift.expected
@@ -0,0 +1,21 @@
+func testConvertToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ if a < 5 {
+ x = a
+ } else {
+ x = b
+ }
+}
+func testConvertTupleToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y): (Int, Int)
+ (x, y) = a < 5 ? (a, b) : (b, a)
+}
+
+
+
+
+
diff --git a/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L4-3.swift.expected b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L4-3.swift.expected
new file mode 100644
index 0000000..bef8f6a
--- /dev/null
+++ b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L4-3.swift.expected
@@ -0,0 +1,20 @@
+func testConvertToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int = a < 5 ? a : b
+}
+func testConvertTupleToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y): (Int, Int)
+ if a < 5 {
+ (x, y) = (a, b)
+ } else {
+ (x, y) = (b, a)
+ }
+}
+
+
+
+
+
diff --git a/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L5-3.swift.expected b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L5-3.swift.expected
new file mode 100644
index 0000000..e4bf3f6
--- /dev/null
+++ b/test/refactoring/ConvertToTernaryExpr/Outputs/basic/L5-3.swift.expected
@@ -0,0 +1,21 @@
+func testConvertToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ x = a < 5 ? a : b
+}
+func testConvertTupleToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y): (Int, Int)
+ if a < 5 {
+ (x, y) = (a, b)
+ } else {
+ (x, y) = (b, a)
+ }
+}
+
+
+
+
+
diff --git a/test/refactoring/ConvertToTernaryExpr/basic.swift b/test/refactoring/ConvertToTernaryExpr/basic.swift
new file mode 100644
index 0000000..e94cb0d
--- /dev/null
+++ b/test/refactoring/ConvertToTernaryExpr/basic.swift
@@ -0,0 +1,34 @@
+func testConvertToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ if a < 5 {
+ x = a
+ } else {
+ x = b
+ }
+}
+func testConvertTupleToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y): (Int, Int)
+ if a < 5 {
+ (x, y) = (a, b)
+ } else {
+ (x, y) = (b, a)
+ }
+}
+
+// RUN: rm -rf %t.result && mkdir -p %t.result
+
+// RUN: %refactor -convert-to-ternary-expr -source-filename %s -pos=4:3 -end-pos=9:4 > %t.result/L4-3.swift
+// RUN: diff -u %S/Outputs/basic/L4-3.swift.expected %t.result/L4-3.swift
+
+// RUN: %refactor -convert-to-ternary-expr -source-filename %s -pos=5:3 -end-pos=9:4 > %t.result/L5-3.swift
+// RUN: diff -u %S/Outputs/basic/L5-3.swift.expected %t.result/L5-3.swift
+
+// RUN: %refactor -convert-to-ternary-expr -source-filename %s -pos=14:3 -end-pos=19:4 > %t.result/L14-3.swift
+// RUN: diff -u %S/Outputs/basic/L14-3.swift.expected %t.result/L14-3.swift
+
+// RUN: %refactor -convert-to-ternary-expr -source-filename %s -pos=15:3 -end-pos=19:4 > %t.result/L15-3.swift
+// RUN: diff -u %S/Outputs/basic/L15-3.swift.expected %t.result/L15-3.swift
diff --git a/test/refactoring/ExpandTernaryExpr/Outputs/basic/L17-3.swift.expected b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L17-3.swift.expected
new file mode 100644
index 0000000..abdfda6
--- /dev/null
+++ b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L17-3.swift.expected
@@ -0,0 +1,34 @@
+func testExpandBasicTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x = a < 5 ? a : b
+}
+func testExpandMultilineTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y) = a < 5
+ ? (a, b)
+ : (b, a)
+}
+func testExpandAssignOnlyTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ if a < 5 {
+x = a
+} else {
+x = b
+}
+}
+func testExpandAssignOnlyTupleTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ let y: Int
+ (x, y) = a < 5 ? (a, b) : (b, a)
+}
+
+
+
+
+
diff --git a/test/refactoring/ExpandTernaryExpr/Outputs/basic/L24-3.swift.expected b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L24-3.swift.expected
new file mode 100644
index 0000000..449eaeb
--- /dev/null
+++ b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L24-3.swift.expected
@@ -0,0 +1,34 @@
+func testExpandBasicTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x = a < 5 ? a : b
+}
+func testExpandMultilineTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y) = a < 5
+ ? (a, b)
+ : (b, a)
+}
+func testExpandAssignOnlyTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ x = a < 5 ? a : b
+}
+func testExpandAssignOnlyTupleTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ let y: Int
+ if a < 5 {
+(x, y) = (a, b)
+} else {
+(x, y) = (b, a)
+}
+}
+
+
+
+
+
diff --git a/test/refactoring/ExpandTernaryExpr/Outputs/basic/L4-3.swift.expected b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L4-3.swift.expected
new file mode 100644
index 0000000..147e3be
--- /dev/null
+++ b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L4-3.swift.expected
@@ -0,0 +1,35 @@
+func testExpandBasicTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+if a < 5 {
+x = a
+} else {
+x = b
+}
+}
+func testExpandMultilineTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y) = a < 5
+ ? (a, b)
+ : (b, a)
+}
+func testExpandAssignOnlyTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ x = a < 5 ? a : b
+}
+func testExpandAssignOnlyTupleTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ let y: Int
+ (x, y) = a < 5 ? (a, b) : (b, a)
+}
+
+
+
+
+
diff --git a/test/refactoring/ExpandTernaryExpr/Outputs/basic/L9-3.swift.expected b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L9-3.swift.expected
new file mode 100644
index 0000000..fc308b7
--- /dev/null
+++ b/test/refactoring/ExpandTernaryExpr/Outputs/basic/L9-3.swift.expected
@@ -0,0 +1,33 @@
+func testExpandBasicTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x = a < 5 ? a : b
+}
+func testExpandMultilineTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y): (Int, Int)
+if a < 5 {
+(x, y) = (a, b)
+} else {
+(x, y) = (b, a)
+}
+}
+func testExpandAssignOnlyTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ x = a < 5 ? a : b
+}
+func testExpandAssignOnlyTupleTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ let y: Int
+ (x, y) = a < 5 ? (a, b) : (b, a)
+}
+
+
+
+
+
diff --git a/test/refactoring/ExpandTernaryExpr/basic.swift b/test/refactoring/ExpandTernaryExpr/basic.swift
new file mode 100644
index 0000000..3cc55f9
--- /dev/null
+++ b/test/refactoring/ExpandTernaryExpr/basic.swift
@@ -0,0 +1,39 @@
+func testExpandBasicTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x = a < 5 ? a : b
+}
+func testExpandMultilineTernaryExpr() {
+ let a = 3
+ let b = 5
+ let (x, y) = a < 5
+ ? (a, b)
+ : (b, a)
+}
+func testExpandAssignOnlyTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ x = a < 5 ? a : b
+}
+func testExpandAssignOnlyTupleTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ let y: Int
+ (x, y) = a < 5 ? (a, b) : (b, a)
+}
+
+// RUN: rm -rf %t.result && mkdir -p %t.result
+
+// RUN: %refactor -expand-ternary-expr -source-filename %s -pos=4:3 -end-pos=4:24 > %t.result/L4-3.swift
+// RUN: diff -u %S/Outputs/basic/L4-3.swift.expected %t.result/L4-3.swift
+
+// RUN: %refactor -expand-ternary-expr -source-filename %s -pos=9:3 -end-pos=11:13 > %t.result/L9-3.swift
+// RUN: diff -u %S/Outputs/basic/L9-3.swift.expected %t.result/L9-3.swift
+
+// RUN: %refactor -expand-ternary-expr -source-filename %s -pos=17:3 -end-pos=17:20 > %t.result/L17-3.swift
+// RUN: diff -u %S/Outputs/basic/L17-3.swift.expected %t.result/L17-3.swift
+
+// RUN: %refactor -expand-ternary-expr -source-filename %s -pos=24:3 -end-pos=24:35 > %t.result/L24-3.swift
+// RUN: diff -u %S/Outputs/basic/L24-3.swift.expected %t.result/L24-3.swift
diff --git a/test/refactoring/RefactoringKind/basic.swift b/test/refactoring/RefactoringKind/basic.swift
index 15912dc..436c4f9 100644
--- a/test/refactoring/RefactoringKind/basic.swift
+++ b/test/refactoring/RefactoringKind/basic.swift
@@ -224,6 +224,24 @@
let account: AccountType = .savings
switch account { }
}
+
+func testExpandTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x = a < 5 ? a : b
+}
+
+func testConvertToTernaryExpr() {
+ let a = 3
+ let b = 5
+ let x: Int
+ if a < 5 {
+ x = a
+ } else {
+ x = b
+ }
+}
+
// RUN: %refactor -source-filename %s -pos=2:1 -end-pos=5:13 | %FileCheck %s -check-prefix=CHECK1
// RUN: %refactor -source-filename %s -pos=3:1 -end-pos=5:13 | %FileCheck %s -check-prefix=CHECK1
// RUN: %refactor -source-filename %s -pos=4:1 -end-pos=5:13 | %FileCheck %s -check-prefix=CHECK1
@@ -311,6 +329,9 @@
// RUN: %refactor -source-filename %s -pos=225:3 | %FileCheck %s -check-prefix=CHECK-EXPAND-SWITCH
+// RUN: %refactor -source-filename %s -pos=231:3 -end-pos=231:24 | %FileCheck %s -check-prefix=CHECK-EXPAND-TERNARY-EXPRESSEXPRESSION
+
+// RUN: %refactor -source-filename %s -pos=237:3 -end-pos=242:4 | %FileCheck %s -check-prefix=CHECK-CONVERT-TO-TERNARY-EXPRESSEXPRESSION
// CHECK1: Action begins
// CHECK1-NEXT: Extract Method
@@ -354,3 +375,7 @@
// CHECK-TRY-CATCH: Convert To Do/Catch
// CHECK-EXPAND-SWITCH: Expand Switch Cases
+
+// CHECK-EXPAND-TERNARY-EXPRESSEXPRESSION: Expand Ternary Expression
+
+// CHECK-CONVERT-TO-TERNARY-EXPRESSEXPRESSION: Convert To Ternary Expression
diff --git a/test/stmt/if_while_var.swift b/test/stmt/if_while_var.swift
index c35399a..750c190 100644
--- a/test/stmt/if_while_var.swift
+++ b/test/stmt/if_while_var.swift
@@ -95,7 +95,7 @@
// Test that these don't cause the parser to crash.
if true { if a == 0; {} } // expected-error {{use of unresolved identifier 'a'}} expected-error {{expected '{' after 'if' condition}}
-if a == 0, where b == 0 {} // expected-error 3{{}} expected-note {{}} {{25-25=do }}
+if a == 0, where b == 0 {} // expected-error 4{{}} expected-note {{}} {{25-25=do }}
diff --git a/tools/SwiftSyntax/Trivia.swift b/tools/SwiftSyntax/Trivia.swift
index 6986b1f..1a78a40 100644
--- a/tools/SwiftSyntax/Trivia.swift
+++ b/tools/SwiftSyntax/Trivia.swift
@@ -46,6 +46,9 @@
case "CarriageReturn":
let value = try container.decode(Int.self, forKey: .value)
self = .carriageReturns(value)
+ case "CarriageReturnLineFeed":
+ let value = try container.decode(Int.self, forKey: .value)
+ self = .carriageReturnLineFeeds(value)
case "Backtick":
let value = try container.decode(Int.self, forKey: .value)
self = .backticks(value)
@@ -102,6 +105,9 @@
case .carriageReturns(let count):
try container.encode("CarriageReturn", forKey: .kind)
try container.encode(count, forKey: .value)
+ case .carriageReturnLineFeeds(let count):
+ try container.encode("CarriageReturnLineFeeds", forKey: .kind)
+ try container.encode(count, forKey: .value)
case .spaces(let count):
try container.encode("Space", forKey: .kind)
try container.encode(count, forKey: .value)
@@ -132,6 +138,9 @@
/// A carriage-return '\r' character.
case carriageReturns(Int)
+
+ /// A newline two bytes sequence consists of '\r' and '\n' characters.
+ case carriageReturnLineFeeds(Int)
/// A backtick '`' character, used to escape identifiers.
case backticks(Int)
@@ -168,6 +177,7 @@
case let .formfeeds(count): printRepeated("\u{240C}", count: count)
case let .newlines(count): printRepeated("\n", count: count)
case let .carriageReturns(count): printRepeated("\r", count: count)
+ case let .carriageReturnLineFeeds(count): printRepeated("\r\n", count: count)
case let .backticks(count): printRepeated("`", count: count)
case let .lineComment(text),
let .blockComment(text),
@@ -195,6 +205,8 @@
return (lines: n, lastColumn: 0, utf8Length: n)
case .carriageReturns(let n):
return (lines: n, lastColumn: 0, utf8Length: n)
+ case .carriageReturnLineFeeds(let n):
+ return (lines: n, lastColumn: 0, utf8Length: n * 2)
case .lineComment(let text),
.docLineComment(let text):
let length = text.utf8.count
@@ -205,15 +217,29 @@
var lines = 0
var col = 0
var total = 0
+ var prevChar: UInt8? = nil
+ // TODO: CR + LF should be regarded as one newline
for char in text.utf8 {
total += 1
- if char == 0x0a /* ASCII newline */
- || char == 0x0d /* ASCII carriage-return */{
+ switch char {
+ case 0x0a:
+ if prevChar == 0x0d {
+ /* ASCII CR LF */
+ assert(col == 0)
+ } else {
+ /* ASCII newline */
+ col = 0
+ lines += 1
+ }
+ /* ASCII carriage-return */
+ case 0x0d:
col = 0
lines += 1
- } else {
+
+ default:
col += 1
}
+ prevChar = char
}
return (lines: lines, lastColumn: col, utf8Length: total)
}
@@ -290,6 +316,12 @@
return [.carriageReturns(count)]
}
+ /// Return a piece of trivia for some number of two bytes sequence
+ /// consists of CR and LF in a row.
+ public static func carriageReturnLineFeeds(_ count: Int) -> Trivia {
+ return [.carriageReturnLineFeeds(count)]
+ }
+
/// Return a piece of trivia for some number of backtick '`' characters
/// in a row.
public static func backticks(_ count: Int) -> Trivia {
diff --git a/tools/swift-refactor/swift-refactor.cpp b/tools/swift-refactor/swift-refactor.cpp
index e40c7a1..ecf7f3b 100644
--- a/tools/swift-refactor/swift-refactor.cpp
+++ b/tools/swift-refactor/swift-refactor.cpp
@@ -48,6 +48,10 @@
"simplify-long-number", "Perform simplify long number literal refactoring"),
clEnumValN(RefactoringKind::ConvertStringsConcatenationToInterpolation,
"strings-concatenation-to-interpolation", "Perform strings concatenation to interpolation refactoring"),
+ clEnumValN(RefactoringKind::ExpandTernaryExpr,
+ "expand-ternary-expr", "Perform expand ternary expression"),
+ clEnumValN(RefactoringKind::ConvertToTernaryExpr,
+ "convert-to-ternary-expr", "Perform convert to ternary expression"),
clEnumValN(RefactoringKind::ExtractFunction,
"extract-function", "Perform extract function refactoring"),
clEnumValN(RefactoringKind::MoveMembersToExtension,
diff --git a/unittests/Parse/LexerTriviaTests.cpp b/unittests/Parse/LexerTriviaTests.cpp
index 23eaf31..e1c7d08 100644
--- a/unittests/Parse/LexerTriviaTests.cpp
+++ b/unittests/Parse/LexerTriviaTests.cpp
@@ -184,3 +184,64 @@
ASSERT_EQ(LeadingTrivia, (Trivia{{TriviaPiece::carriageReturns(1)}}));
ASSERT_EQ(TrailingTrivia, Trivia());
}
+
+TEST_F(LexerTriviaTest, TriviaNewLines) {
+ using namespace swift::syntax;
+ StringRef SourceStr = "\n\r\r\n\r\r\r\n\r\n\n\n"
+ "aaa"
+ "\n\r\r\n\r\r\r\n\r\n\n\n"
+ "bbb"
+ "\n\r\r\n\r\r\r\n\r\n\n\n";
+
+ LangOptions LangOpts;
+ SourceManager SourceMgr;
+ unsigned BufferID = SourceMgr.addMemBufferCopy(SourceStr);
+
+ Lexer L(LangOpts, SourceMgr, BufferID, /*Diags=*/nullptr, /*InSILMode=*/false,
+ CommentRetentionMode::AttachToNextToken,
+ TriviaRetentionMode::WithTrivia);
+
+ Token Tok;
+ Trivia LeadingTrivia, TrailingTrivia;
+
+ L.lex(Tok, LeadingTrivia, TrailingTrivia);
+ ASSERT_EQ(tok::identifier, Tok.getKind());
+ ASSERT_EQ("aaa", Tok.getText());
+ ASSERT_TRUE(Tok.isAtStartOfLine());
+ ASSERT_EQ((Trivia{{
+ TriviaPiece::newlines(1),
+ TriviaPiece::carriageReturns(1),
+ TriviaPiece::carriageReturnLineFeeds(1),
+ TriviaPiece::carriageReturns(2),
+ TriviaPiece::carriageReturnLineFeeds(2),
+ TriviaPiece::newlines(2)
+ }}), LeadingTrivia);
+ ASSERT_EQ(Trivia(), TrailingTrivia);
+
+ L.lex(Tok, LeadingTrivia, TrailingTrivia);
+ ASSERT_EQ(tok::identifier, Tok.getKind());
+ ASSERT_EQ("bbb", Tok.getText());
+ ASSERT_TRUE(Tok.isAtStartOfLine());
+ ASSERT_EQ((Trivia{{
+ TriviaPiece::newlines(1),
+ TriviaPiece::carriageReturns(1),
+ TriviaPiece::carriageReturnLineFeeds(1),
+ TriviaPiece::carriageReturns(2),
+ TriviaPiece::carriageReturnLineFeeds(2),
+ TriviaPiece::newlines(2)
+ }}), LeadingTrivia);
+ ASSERT_EQ(Trivia(), TrailingTrivia);
+
+ L.lex(Tok, LeadingTrivia, TrailingTrivia);
+ ASSERT_EQ(tok::eof, Tok.getKind());
+ ASSERT_TRUE(Tok.isAtStartOfLine());
+ ASSERT_EQ((Trivia{{
+ TriviaPiece::newlines(1),
+ TriviaPiece::carriageReturns(1),
+ TriviaPiece::carriageReturnLineFeeds(1),
+ TriviaPiece::carriageReturns(2),
+ TriviaPiece::carriageReturnLineFeeds(2),
+ TriviaPiece::newlines(2)
+ }}), LeadingTrivia);
+ ASSERT_EQ(Trivia(), TrailingTrivia);
+}
diff --git a/unittests/Syntax/RawSyntaxTests.cpp b/unittests/Syntax/RawSyntaxTests.cpp
index 71cdfc9..4fb98de 100644
--- a/unittests/Syntax/RawSyntaxTests.cpp
+++ b/unittests/Syntax/RawSyntaxTests.cpp
@@ -1,5 +1,6 @@
#include "swift/Parse/Token.h"
#include "swift/Syntax/RawSyntax.h"
+#include "swift/Syntax/RawTokenSyntax.h"
#include "swift/Syntax/SyntaxFactory.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
@@ -8,3 +9,33 @@
using namespace swift::syntax;
// TODO
+
+TEST(RawSyntaxTests, accumulateAbsolutePosition1) {
+ auto Token = RawTokenSyntax::make(tok::identifier,
+ OwnedString("aaa"),
+ SourcePresence::Present,
+ Trivia {{
+ TriviaPiece::newlines(2),
+ TriviaPiece::carriageReturns(2),
+ TriviaPiece::carriageReturnLineFeeds(2) }},
+ Trivia {{ }});
+ AbsolutePosition Pos;
+ Token->accumulateAbsolutePosition(Pos);
+ ASSERT_EQ(7u, Pos.getLine());
+ ASSERT_EQ(4u, Pos.getColumn());
+ ASSERT_EQ(11u, Pos.getOffset());
+}
+
+TEST(RawSyntaxTests, accumulateAbsolutePosition2) {
+ auto Token = RawTokenSyntax::make(tok::identifier,
+ OwnedString("aaa"),
+ SourcePresence::Present,
+ Trivia {{
+ TriviaPiece::blockComment("/* \n\r\r\n */") }},
+ Trivia {{ }});
+ AbsolutePosition Pos;
+ Token->accumulateAbsolutePosition(Pos);
+ ASSERT_EQ(4u, Pos.getLine());
+ ASSERT_EQ(7u, Pos.getColumn());
+ ASSERT_EQ(13u, Pos.getOffset());
+}
diff --git a/unittests/runtime/Array.cpp b/unittests/runtime/Array.cpp
index ce56bbc..40c8023 100644
--- a/unittests/runtime/Array.cpp
+++ b/unittests/runtime/Array.cpp
@@ -80,8 +80,8 @@
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
{ { &destroyTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
- { { { MetadataKind::Class } }, 0, /*rodata*/ 1,
- ClassFlags::UsesSwift1Refcounting, 0, 0, 0, 0, 0, 0 }
+ { { { MetadataKind::Class } }, 0, SWIFT_CLASS_IS_SWIFT_MASK,
+ ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};
/// Create an object that, when deallocated, stores the given value to
diff --git a/unittests/runtime/LongTests/LongRefcounting.cpp b/unittests/runtime/LongTests/LongRefcounting.cpp
index bd3d710..ba5da09 100644
--- a/unittests/runtime/LongTests/LongRefcounting.cpp
+++ b/unittests/runtime/LongTests/LongRefcounting.cpp
@@ -98,8 +98,8 @@
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
{ { &deinitTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
- { { { MetadataKind::Class } }, 0, /*rodata*/ 1,
- ClassFlags::UsesSwift1Refcounting, 0, 0, 0, 0, 0, 0 }
+ { { { MetadataKind::Class } }, 0, SWIFT_CLASS_IS_SWIFT_MASK,
+ ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};
/// Create an object that, when deinited, stores the given value to
diff --git a/unittests/runtime/Refcounting.cpp b/unittests/runtime/Refcounting.cpp
index e1b6bf9..e6f60a3 100644
--- a/unittests/runtime/Refcounting.cpp
+++ b/unittests/runtime/Refcounting.cpp
@@ -31,8 +31,8 @@
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
{ { &destroyTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
- { { { MetadataKind::Class } }, 0, /*rodata*/ 1,
- ClassFlags::UsesSwift1Refcounting, 0, 0, 0, 0, 0, 0 }
+ { { { MetadataKind::Class } }, 0, SWIFT_CLASS_IS_SWIFT_MASK,
+ ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};
/// Create an object that, when deallocated, stores the given value to
diff --git a/utils/gyb_syntax_support/Child.py b/utils/gyb_syntax_support/Child.py
index 9a0eb74..c28be20 100644
--- a/utils/gyb_syntax_support/Child.py
+++ b/utils/gyb_syntax_support/Child.py
@@ -9,7 +9,7 @@
restricted subset of acceptable kinds or texts.
"""
def __init__(self, name, kind, is_optional=False,
- token_choices=None, text_choices=None):
+ token_choices=None, text_choices=None, node_choices=None):
self.name = name
self.swift_name = lowercase_first_word(name)
self.syntax_kind = kind
@@ -39,6 +39,19 @@
# token against the choices.
self.text_choices = text_choices or []
+ # A list of valid choices for a child
+ self.node_choices = node_choices or []
+
+ # Check the choices are either empty or multiple
+ assert len(self.node_choices) != 1
+
+ # Check node choices are well-formed
+ for choice in self.node_choices:
+ assert not choice.is_optional, \
+ "node choice %s cannot be optional" % choice.name
+ assert not choice.node_choices, \
+ "node choice %s cannot have further choices" % choice.name
+
def is_token(self):
"""
Returns true if this child has a token kind.
diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py
index a7af33f..782f167 100644
--- a/utils/gyb_syntax_support/DeclNodes.py
+++ b/utils/gyb_syntax_support/DeclNodes.py
@@ -358,9 +358,10 @@
Node('AccessorBlock', kind="Syntax",
children=[
Child('LeftBrace', kind='LeftBraceToken'),
- # one of the following children should be required.
- Child('Accessors', kind='AccessorList', is_optional=True),
- Child('Statements', kind='StmtList', is_optional=True),
+ Child('AccessorListOrStmtList', kind='Syntax',
+ node_choices=[
+ Child('Accessors', kind='AccessorList'),
+ Child('Statements', kind='StmtList')]),
Child('RightBrace', kind='RightBraceToken'),
]),
diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py
index 1f47df3..e3ebe08 100644
--- a/utils/gyb_syntax_support/ExprNodes.py
+++ b/utils/gyb_syntax_support/ExprNodes.py
@@ -74,6 +74,10 @@
Child('Elements', kind='ExprList'),
]),
+ Node('ExprList', kind='SyntaxCollection',
+ element='Expr',
+ element_name='Expression'),
+
# A #line expression.
Node('PoundLineExpr', kind='Expr',
children=[
@@ -152,7 +156,11 @@
Node('DictionaryExpr', kind='Expr',
children=[
Child('LeftSquare', kind='LeftSquareToken'),
- Child('Elements', kind='DictionaryElementList'),
+ Child('Content', kind='Syntax',
+ node_choices=[
+ Child('Colon', kind='ColonToken'),
+ Child('Elements', kind='DictionaryElementList'),
+ ]),
Child('RightSquare', kind='RightSquareToken'),
]),
@@ -300,9 +308,11 @@
children=[
Child('Capture', kind='ClosureCaptureSignature',
is_optional=True),
- # FIXME: one and only one of these two children is required
- Child('SimpleInput', kind='ClosureParamList', is_optional=True),
- Child('Input', kind='ParameterClause', is_optional=True),
+ Child('Input', kind='Syntax', is_optional=True,
+ node_choices=[
+ Child('SimpleInput', kind='ClosureParamList'),
+ Child('Input', kind='ParameterClause'),
+ ]),
Child('ThrowsTok', kind='ThrowsToken', is_optional=True),
Child('Output', kind='ReturnClause', is_optional=True),
Child('InTok', kind='InToken'),
@@ -315,4 +325,10 @@
Child('Statements', kind='StmtList'),
Child('RightBrace', kind='RightBraceToken'),
]),
+
+ # unresolved-pattern-expr -> pattern
+ Node('UnresolvedPatternExpr', kind='Expr',
+ children=[
+ Child('Pattern', kind='Pattern'),
+ ]),
]
diff --git a/utils/gyb_syntax_support/PatternNodes.py b/utils/gyb_syntax_support/PatternNodes.py
index eb962ae..f8ebb5b 100644
--- a/utils/gyb_syntax_support/PatternNodes.py
+++ b/utils/gyb_syntax_support/PatternNodes.py
@@ -28,10 +28,10 @@
Child('Type', kind='Type'),
]),
- # optional-pattern -> identifier '?'
+ # optional-pattern -> pattern '?'
Node('OptionalPattern', kind='Pattern',
children=[
- Child('Identifier', kind='IdentifierToken'),
+ Child('SubPattern', kind='Pattern'),
Child('QuestionMark', kind='PostfixQuestionMarkToken'),
]),
@@ -49,14 +49,12 @@
Child('Type', kind='Type'),
]),
- # tuple-pattern -> '(' tuple-pattern-element-list ')' type-annotation?
+ # tuple-pattern -> '(' tuple-pattern-element-list ')'
Node('TuplePattern', kind='Pattern',
children=[
Child('OpenParen', kind='LeftParenToken'),
Child('Elements', kind='TuplePatternElementList'),
Child('CloseParen', kind='RightParenToken'),
- Child('TypeAnnotation', kind='TypeAnnotation',
- is_optional=True),
]),
# wildcard-pattern -> '_' type-annotation?
@@ -72,7 +70,7 @@
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
- Child('LabelColon', kind='ColonToken',
+ Child('Colon', kind='ColonToken',
is_optional=True),
Child('Pattern', kind='Pattern'),
Child('Comma', kind='CommaToken',
diff --git a/utils/gyb_syntax_support/StmtNodes.py b/utils/gyb_syntax_support/StmtNodes.py
index 34049bc..844e0e6 100644
--- a/utils/gyb_syntax_support/StmtNodes.py
+++ b/utils/gyb_syntax_support/StmtNodes.py
@@ -20,7 +20,7 @@
Child('LabelColon', kind='ColonToken',
is_optional=True),
Child('WhileKeyword', kind='WhileToken'),
- Child('Conditions', kind='ConditionList'),
+ Child('Conditions', kind='ConditionElementList'),
Child('Body', kind='CodeBlock'),
Child('Semicolon', kind='SemicolonToken',
is_optional=True),
@@ -66,21 +66,17 @@
Node('GuardStmt', kind='Stmt',
children=[
Child('GuardKeyword', kind='GuardToken'),
- Child('Conditions', kind='ConditionList'),
+ Child('Conditions', kind='ConditionElementList'),
Child('ElseKeyword', kind='ElseToken'),
Child('Body', kind='CodeBlock'),
Child('Semicolon', kind='SemicolonToken',
is_optional=True),
]),
- Node('ExprList', kind='SyntaxCollection',
- element='Expr',
- element_name='Expression'),
-
Node('WhereClause', kind='Syntax',
children=[
Child('WhereKeyword', kind='WhereToken'),
- Child('Expressions', kind='ExprList'),
+ Child('GuardResult', kind='Expr'),
]),
# for-in-stmt -> label? ':'? 'for' 'case'? pattern 'in' expr 'where'?
@@ -94,9 +90,11 @@
Child('ForKeyword', kind='ForToken'),
Child('CaseKeyword', kind='CaseToken',
is_optional=True),
- Child('ItemPattern', kind='Pattern'),
+ Child('Pattern', kind='Pattern'),
+ Child('TypeAnnotation', kind='TypeAnnotation',
+ is_optional=True),
Child('InKeyword', kind='InToken'),
- Child('CollectionExpr', kind='Expr'),
+ Child('SequenceExpr', kind='Expr'),
Child('WhereClause', kind='WhereClause',
is_optional=True),
Child('Body', kind='CodeBlock'),
@@ -134,7 +132,8 @@
is_optional=True),
Child('DoKeyword', kind='DoToken'),
Child('Body', kind='CodeBlock'),
- Child('CatchClauses', kind='CatchClauseList'),
+ Child('CatchClauses', kind='CatchClauseList',
+ is_optional=True),
Child('Semicolon', kind='SemicolonToken',
is_optional=True),
]),
@@ -179,21 +178,53 @@
Node('CaseItemList', kind='SyntaxCollection',
element='CaseItem'),
- Node('Condition', kind='Syntax',
- children=[
- Child('Condition', kind='Syntax'),
- Child('TrailingComma', kind='CommaToken',
- is_optional=True),
- ]),
-
- # condition-list -> condition
- # | condition ','? condition-list
# condition -> expression
# | availability-condition
# | case-condition
# | optional-binding-condition
- Node('ConditionList', kind='SyntaxCollection',
- element='Condition'),
+ Node('ConditionElement', kind='Syntax',
+ children=[
+ Child('Condition', kind='Syntax',
+ node_choices=[
+ Child('Expression', kind='Expr'),
+ Child('Availablity', kind='AvailabilityCondition'),
+ Child('MatchingPattern',
+ kind='MatchingPatternCondition'),
+ Child('OptionalBinding',
+ kind='OptionalBindingCondition'),
+ ]),
+ Child('TrailingComma', kind='CommaToken',
+ is_optional=True),
+ ]),
+ Node('AvailabilityCondition', kind='Syntax',
+ children=[
+ Child('PoundAvailableKeyword', kind='PoundAvailableToken'),
+ Child('Arguments', kind='TokenList'),
+ ]),
+ Node('MatchingPatternCondition', kind='Syntax',
+ children=[
+ Child('CaseKeyword', kind='CaseToken'),
+ Child('Pattern', kind='Pattern'),
+ Child('TypeAnnotation', kind='TypeAnnotation',
+ is_optional=True),
+ Child('Initializer', kind='InitializerClause'),
+ ]),
+ Node('OptionalBindingCondition', kind='Syntax',
+ children=[
+ Child('LetOrVarKeyword', kind='Token',
+ token_choices=[
+ 'LetToken', 'VarToken',
+ ]),
+ Child('Pattern', kind='Pattern'),
+ Child('TypeAnnotation', kind='TypeAnnotation',
+ is_optional=True),
+ Child('Initializer', kind='InitializerClause'),
+ ]),
+
+ # condition-list -> condition
+ # | condition ','? condition-list
+ Node('ConditionElementList', kind='SyntaxCollection',
+ element='ConditionElement'),
# A declaration in statement position.
# struct Foo {};
@@ -222,9 +253,15 @@
Child('LabelColon', kind='ColonToken',
is_optional=True),
Child('IfKeyword', kind='IfToken'),
- Child('Conditions', kind='ConditionList'),
+ Child('Conditions', kind='ConditionElementList'),
Child('Body', kind='CodeBlock'),
- Child('ElseClause', kind='Syntax',
+ Child('ElseKeyword', kind='ElseToken',
+ is_optional=True),
+ Child('ElseBody', kind='Syntax',
+ node_choices=[
+ Child('IfStmt', kind='IfStmt'),
+ Child('CodeBlock', kind='CodeBlock'),
+ ],
is_optional=True),
Child('Semicolon', kind='SemicolonToken',
is_optional=True),
diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py
index 36ded62..44d625c 100644
--- a/utils/gyb_syntax_support/__init__.py
+++ b/utils/gyb_syntax_support/__init__.py
@@ -28,9 +28,54 @@
else:
missing_kind = "Unknown" if child.syntax_kind == "Syntax" \
else child.syntax_kind
+ if child.node_choices:
+ return make_missing_child(child.node_choices[0])
return 'RawSyntax::missing(SyntaxKind::%s)' % missing_kind
+def check_child_condition(child):
+ """
+ Generates a C++ closure to check whether a given syntax node S can satisfy
+ the requirements of child.
+ """
+ result = '[](const Syntax &S) {\n'
+ result += ' // check %s\n' % child.name
+ if child.token_choices:
+ # Check token kind choices are met.
+ result += 'if (auto Tok = S.getAs<TokenSyntax>()) {\n'
+ result += ' auto Kind = Tok->getTokenKind();\n'
+ tok_checks = []
+ for choice in child.token_choices:
+ tok_checks.append("Kind == tok::%s" % choice.kind)
+ all_checks = ' || '.join(tok_checks)
+ result += ' return %s;\n' % all_checks
+ result += '}\n'
+ result += 'return false;\n'
+ elif child.text_choices:
+ # Check token text choices are met.
+ result += 'if (auto Tok = S.getAs<TokenSyntax>()) {\n'
+ result += ' auto Text = Tok->getText();\n'
+ tok_checks = []
+ for choice in child.text_choices:
+ tok_checks.append("Text == \"%s\"" % choice)
+ all_checks = ' || '.join(tok_checks)
+ result += ' return %s;\n' % all_checks
+ result += '}\n'
+ result += 'return false;\n'
+ elif child.node_choices:
+ # Recursively, check one of the node choices' conditions are met.
+ node_checks = []
+ for choice in child.node_choices:
+ node_checks.append(check_child_condition(choice) + '(S)')
+ all_checks = ' || '.join(node_checks)
+ result += 'return %s;\n' % all_checks
+ else:
+ # For remaining children, simply check the syntax kind.
+ result += 'return S.getAs<%s>().hasValue();\n' % child.type_name
+ result += '}'
+ return result
+
+
def make_missing_swift_child(child):
"""
Generates a Swift call to make the raw syntax for a given Child object.
diff --git a/validation-test/compiler_crashers/28865-void-lookupinmodule-llvm-smallset-swift-cantype-4u-anonymous-namespace-sortcanty.swift b/validation-test/compiler_crashers/28865-void-lookupinmodule-llvm-smallset-swift-cantype-4u-anonymous-namespace-sortcanty.swift
new file mode 100644
index 0000000..a0fdccf
--- /dev/null
+++ b/validation-test/compiler_crashers/28865-void-lookupinmodule-llvm-smallset-swift-cantype-4u-anonymous-namespace-sortcanty.swift
@@ -0,0 +1,9 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol A:a{}typealias a:A&
diff --git a/validation-test/compiler_crashers/28866-unreachable-executed-at-swift-include-swift-ast-cantypevisitor-h-41.swift b/validation-test/compiler_crashers/28866-unreachable-executed-at-swift-include-swift-ast-cantypevisitor-h-41.swift
new file mode 100644
index 0000000..5c7f26e
--- /dev/null
+++ b/validation-test/compiler_crashers/28866-unreachable-executed-at-swift-include-swift-ast-cantypevisitor-h-41.swift
@@ -0,0 +1,11 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+[.a
+[Int?as?Int
+nil?
diff --git a/validation-test/compiler_crashers/28867-swift-iterativetypechecker-issatisfied-swift-typecheckrequest.swift b/validation-test/compiler_crashers/28867-swift-iterativetypechecker-issatisfied-swift-typecheckrequest.swift
new file mode 100644
index 0000000..71b51ec
--- /dev/null
+++ b/validation-test/compiler_crashers/28867-swift-iterativetypechecker-issatisfied-swift-typecheckrequest.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol A:a
+& {}typealias a:A
diff --git a/validation-test/compiler_crashers/28868-known-typebindings-end.swift b/validation-test/compiler_crashers/28868-known-typebindings-end.swift
new file mode 100644
index 0000000..711219e
--- /dev/null
+++ b/validation-test/compiler_crashers/28868-known-typebindings-end.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+struct B{func a{a(Int?as?ManagedBuffer{
diff --git a/validation-test/compiler_crashers/28869-swift-diagnosticengine-formatdiagnostictext-llvm-raw-ostream-llvm-stringref-llvm.swift b/validation-test/compiler_crashers/28869-swift-diagnosticengine-formatdiagnostictext-llvm-raw-ostream-llvm-stringref-llvm.swift
new file mode 100644
index 0000000..641a444
--- /dev/null
+++ b/validation-test/compiler_crashers/28869-swift-diagnosticengine-formatdiagnostictext-llvm-raw-ostream-llvm-stringref-llvm.swift
@@ -0,0 +1,9 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol A:A&CLong
diff --git a/validation-test/compiler_crashers/28870-swift-associatedtypedecl-getoverriddendecls-const.swift b/validation-test/compiler_crashers/28870-swift-associatedtypedecl-getoverriddendecls-const.swift
new file mode 100644
index 0000000..61a157f
--- /dev/null
+++ b/validation-test/compiler_crashers/28870-swift-associatedtypedecl-getoverriddendecls-const.swift
@@ -0,0 +1,10 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+protocol A:a{typealias a}protocol a:A{typealias a
+class a
diff --git a/validation-test/compiler_crashers/28871-nested-second-nested-second-isequal-result-nested-second-haserror-result-haserro.swift b/validation-test/compiler_crashers/28871-nested-second-nested-second-isequal-result-nested-second-haserror-result-haserro.swift
new file mode 100644
index 0000000..c7d21fb
--- /dev/null
+++ b/validation-test/compiler_crashers/28871-nested-second-nested-second-isequal-result-nested-second-haserror-result-haserro.swift
@@ -0,0 +1,11 @@
+// This source file is part of the Swift.org open source project
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+
+// REQUIRES: asserts
+// RUN: not --crash %target-swift-frontend %s -emit-ir
+class a:A
+protocol A:a{typealias a:=a
diff --git a/validation-test/stdlib/CollectionType.swift.gyb b/validation-test/stdlib/CollectionType.swift.gyb
index f826161..0f287a3 100644
--- a/validation-test/stdlib/CollectionType.swift.gyb
+++ b/validation-test/stdlib/CollectionType.swift.gyb
@@ -853,4 +853,28 @@
% end
+struct RACollectionWithIntIndex<T> {
+ var contents: [T]
+}
+
+extension RACollectionWithIntIndex: RandomAccessCollection {
+ var startIndex: Int { return contents.startIndex }
+ var endIndex: Int { return contents.endIndex }
+ subscript(index: Int) -> T {
+ get { return contents[index] }
+ set { }
+ }
+}
+
+CollectionTypeTests.test("AssociatedTypes/RACollectionWithIntIndex") {
+ typealias C = RACollectionWithIntIndex<Void>
+ expectCollectionAssociatedTypes(
+ collectionType: C.self,
+ iteratorType: IndexingIterator<C>.self,
+ subSequenceType: Slice<C>.self,
+ indexType: Int.self,
+ indicesType: CountableRange<Int>.self)
+}
+
+
runAllTests()
diff --git a/validation-test/stdlib/Lazy.swift.gyb b/validation-test/stdlib/Lazy.swift.gyb
index 9518334..44b29ac 100644
--- a/validation-test/stdlib/Lazy.swift.gyb
+++ b/validation-test/stdlib/Lazy.swift.gyb
@@ -1291,6 +1291,11 @@
}
}
+struct TryFlattenIndex<C: Collection> where C.Element: Collection {
+ typealias FlattenedIndex = FlattenCollectionIndex<C>
+}
+
+
//===--- LazyPrefixWhile --------------------------------------------------===//
let prefixDropWhileTests: [(data: [Int], value: Int, pivot: Int)] = [
diff --git a/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c b/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c
index 74cc302..f4fe6cd 100644
--- a/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c
+++ b/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c
@@ -7,6 +7,6 @@
void _swift_slowDealloc(void) {}
void _swift_storeEnumTagSinglePayload(void) {}
void swift_allocateGenericValueMetadata(void) {}
-void swift_initEnumValueWitnessTableSinglePayload(void) {}
+void swift_initEnumMetadataSinglePayload(void) {}
void _swift_retain(){}
void swift_allocBox(){}