Merge pull request #14482 from xedin/rdar-37291371
[CSBindings] Look through optional types when trying to validate l-va…
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index 7882950..ec7a91b 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -59,6 +59,7 @@
single-source/DictTest
single-source/DictTest2
single-source/DictTest3
+ single-source/DictTest4
single-source/DictionaryBridge
single-source/DictionaryGroup
single-source/DictionaryLiteral
diff --git a/benchmark/single-source/DictTest4.swift b/benchmark/single-source/DictTest4.swift
new file mode 100644
index 0000000..d2849fa
--- /dev/null
+++ b/benchmark/single-source/DictTest4.swift
@@ -0,0 +1,129 @@
+//===--- DictTest4.swift --------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 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
+//
+//===----------------------------------------------------------------------===//
+
+import TestsUtils
+
+// This benchmark mostly measures lookups in dictionaries with complex keys,
+// exercising the default hash compression function.
+
+public let Dictionary4 = [
+ BenchmarkInfo(name: "Dictionary4", runFunction: run_Dictionary4, tags: [.validation, .api, .Dictionary]),
+ BenchmarkInfo(name: "Dictionary4OfObjects", runFunction: run_Dictionary4OfObjects, tags: [.validation, .api, .Dictionary]),
+]
+
+struct LargeKey: Hashable {
+ let i: Int
+ let j: Int
+ let k: Double
+ let l: UInt32
+ let m: Bool
+ let n: Bool
+ let o: Bool
+ let p: Bool
+ let q: Bool
+
+ init(_ value: Int) {
+ self.i = value
+ self.j = 2 * value
+ self.k = Double(value) / 7
+ self.l = UInt32(truncatingIfNeeded: value)
+ self.m = value & 1 == 0
+ self.n = value & 2 == 0
+ self.o = value & 4 == 0
+ self.p = value & 8 == 0
+ self.q = value & 16 == 0
+ }
+}
+
+@inline(never)
+public func run_Dictionary4(_ N: Int) {
+ let size1 = 100
+ let reps = 20
+ let ref_result = "1 99 \(reps) \(reps * 99)"
+ var hash1 = [LargeKey: Int]()
+ var hash2 = [LargeKey: Int]()
+ var res = ""
+
+ for _ in 1...N {
+ // Test insertions
+ hash1 = [:]
+ for i in 0..<size1 {
+ hash1[LargeKey(i)] = i
+ }
+
+ hash2 = hash1
+
+ // Test lookups & value replacement
+ for _ in 1..<reps {
+ for (k, v) in hash1 {
+ hash2[k] = hash2[k]! + v
+ }
+ }
+
+ res = "\(hash1[LargeKey(1)]!) \(hash1[LargeKey(99)]!)" +
+ " \(hash2[LargeKey(1)]!) \(hash2[LargeKey(99)]!)"
+ if res != ref_result {
+ break
+ }
+ }
+ CheckResults(res == ref_result)
+}
+
+class Box<T : Hashable> : Hashable {
+ var value: T
+
+ init(_ v: T) {
+ value = v
+ }
+
+ var hashValue: Int {
+ return value.hashValue
+ }
+
+ static func ==(lhs: Box, rhs: Box) -> Bool {
+ return lhs.value == rhs.value
+ }
+}
+
+@inline(never)
+public func run_Dictionary4OfObjects(_ N: Int) {
+ let size1 = 100
+ let reps = 20
+ let ref_result = "1 99 \(reps) \(reps * 99)"
+ var hash1 = [Box<LargeKey>: Int]()
+ var hash2 = [Box<LargeKey>: Int]()
+ var res = ""
+
+ for _ in 1...N {
+ // Test insertions
+ hash1 = [:]
+ for i in 0..<size1 {
+ hash1[Box(LargeKey(i))] = i
+ }
+
+ hash2 = hash1
+
+ // Test lookups & value replacement
+ for _ in 1..<reps {
+ for (k, v) in hash1 {
+ hash2[k] = hash2[k]! + v
+ }
+ }
+
+ res = "\(hash1[Box(LargeKey(1))]!) \(hash1[Box(LargeKey(99))]!)" +
+ " \(hash2[Box(LargeKey(1))]!) \(hash2[Box(LargeKey(99))]!)"
+ if res != ref_result {
+ break
+ }
+ }
+ CheckResults(res == ref_result)
+}
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index f723816..adb28b5 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -46,6 +46,7 @@
import DictTest
import DictTest2
import DictTest3
+import DictTest4
import DictionaryBridge
import DictionaryGroup
import DictionaryLiteral
@@ -189,6 +190,7 @@
registerBenchmark(Dictionary)
registerBenchmark(Dictionary2)
registerBenchmark(Dictionary3)
+registerBenchmark(Dictionary4)
registerBenchmark(DictionaryBridge)
registerBenchmark(DictionaryGroup)
registerBenchmark(DictionaryLiteral)
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index b9c0e8d..dff956a 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -258,11 +258,13 @@
Type getTypeInContext(GenericSignatureBuilder &builder,
GenericEnvironment *genericEnv);
- /// Dump a debugging representation of this equivalence class.
- void dump(llvm::raw_ostream &out) const;
+ /// Dump a debugging representation of this equivalence class,
+ void dump(llvm::raw_ostream &out,
+ GenericSignatureBuilder *builder = nullptr) const;
- LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
- "only for use in the debugger");
+ LLVM_ATTRIBUTE_DEPRECATED(
+ void dump(GenericSignatureBuilder *builder = nullptr) const,
+ "only for use in the debugger");
/// Caches.
@@ -271,9 +273,8 @@
/// The cached anchor itself.
Type anchor;
- /// The number of members of the equivalence class when the archetype
- /// anchor was cached.
- unsigned numMembers;
+ /// The generation at which the anchor was last computed.
+ unsigned lastGeneration;
} archetypeAnchorCache;
/// Describes a cached nested type.
@@ -444,6 +445,11 @@
/// Note that we have added the nested type nestedPA
void addedNestedType(PotentialArchetype *nestedPA);
+ /// Add a rewrite rule for a same-type constraint between the given
+ /// types.
+ void addSameTypeRewriteRule(PotentialArchetype *type1,
+ PotentialArchetype *type2);
+
/// \brief Add a new conformance requirement specifying that the given
/// potential archetypes are equivalent.
ConstraintResult addSameTypeRequirementBetweenArchetypes(
@@ -802,6 +808,12 @@
/// Determine whether the two given types are in the same equivalence class.
bool areInSameEquivalenceClass(Type type1, Type type2);
+ /// Simplify the given dependent type down to its canonical representation.
+ ///
+ /// \returns null if the type involved dependent member types that
+ /// don't have associated types.
+ Type getCanonicalTypeParameter(Type type);
+
/// Verify the correctness of the given generic signature.
///
/// This routine will test that the given generic signature is both minimal
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 6048734..350a246 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -573,6 +573,12 @@
/// whether a type parameter exists at any position.
bool isTypeParameter();
+ /// \brief Determine whether this type can dynamically be an optional type.
+ ///
+ /// \param includeExistential Whether an existential type should be considered
+ /// such a type.
+ bool canDynamicallyBeOptionalType(bool includeExistential);
+
/// Determine whether this type contains a type parameter somewhere in it.
bool hasTypeParameter() {
return getRecursiveProperties().hasTypeParameter();
@@ -4998,6 +5004,14 @@
return false;
}
+inline bool TypeBase::canDynamicallyBeOptionalType(bool includeExistential) {
+ CanType T = getCanonicalType();
+ auto isArchetypeOrExistential = isa<ArchetypeType>(T) ||
+ (includeExistential && T.isExistentialType());
+
+ return isArchetypeOrExistential && !T.isAnyClassReferenceType();
+}
+
inline ClassDecl *TypeBase::getClassOrBoundGenericClass() {
return getCanonicalType().getClassOrBoundGenericClass();
}
diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h
index 872f3c7..b5b4ae4 100644
--- a/include/swift/SIL/TypeSubstCloner.h
+++ b/include/swift/SIL/TypeSubstCloner.h
@@ -170,7 +170,11 @@
protected:
SILType remapType(SILType Ty) {
- return Ty.subst(Original.getModule(), SubsMap);
+ SILType &Sty = TypeCache[Ty];
+ if (!Sty) {
+ Sty = Ty.subst(Original.getModule(), SubsMap);
+ }
+ return Sty;
}
CanType remapASTType(CanType ty) {
@@ -286,6 +290,8 @@
ModuleDecl *SwiftMod;
/// The substitutions list for the specialization.
SubstitutionMap SubsMap;
+ /// Cache for substituted types.
+ llvm::DenseMap<SILType, SILType> TypeCache;
/// The original function to specialize.
SILFunction &Original;
/// The substitutions used at the call site.
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 2a28e95..492d385 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 397; // No resilience expansion in SILDeclRef
+const uint16_t VERSION_MINOR = 398; // Private discriminators for type xrefs
using DeclIDField = BCFixed<31>;
@@ -1288,6 +1288,7 @@
using XRefTypePathPieceLayout = BCRecordLayout<
XREF_TYPE_PATH_PIECE,
IdentifierIDField, // name
+ IdentifierIDField, // private discriminator
BCFixed<1> // restrict to protocol extension
>;
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index f473456..d657f7c 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -107,6 +107,190 @@
"Delayed requirements left unresolved");
STATISTIC(NumConditionalRequirementsAdded,
"# of conditional requirements added");
+STATISTIC(NumComponentsCollapsedViaRewriting,
+ "# of same-type components collapsed via term rewriting");
+
+namespace {
+
+/// A purely-relative rewrite path consisting of a (possibly empty)
+/// sequence of associated type references.
+using RelativeRewritePath = ArrayRef<AssociatedTypeDecl *>;
+
+/// Describes a rewrite path, which contains an optional base (generic
+/// parameter) followed by a sequence of associated type references.
+class RewritePath {
+ Optional<GenericParamKey> base;
+ TinyPtrVector<AssociatedTypeDecl *> path;
+
+public:
+ RewritePath() { }
+
+ enum PathOrder {
+ Forward,
+ Reverse,
+ };
+
+ /// Form a rewrite path given an optional base and a relative rewrite path.
+ RewritePath(Optional<GenericParamKey> base, RelativeRewritePath path,
+ PathOrder order);
+
+ /// Retrieve the base of the given rewrite path.
+ ///
+ /// When present, it indicates that the entire path will be rebased on
+ /// the given base generic parameter. This is required for describing
+ /// rewrites on type parameters themselves, e.g., T == U.
+ Optional<GenericParamKey> getBase() const { return base; }
+
+ /// Retrieve the sequence of associated type references that describes
+ /// the path.
+ ArrayRef<AssociatedTypeDecl *> getPath() const { return path; }
+
+ /// Decompose a type into a path.
+ ///
+ /// \returns the path, or None if it contained unresolved dependent member
+ /// types.
+ Optional<RewritePath> static createPath(Type type);
+
+ /// Decompose a potential archetype into a patch.
+ ///
+ /// \returns the path, or None if it contained potential archetypes
+ /// with concrete declarations.
+ Optional<RewritePath> static createPath(PotentialArchetype *pa);
+
+ /// Compute the common path between this path and \c other, if one exists.
+ Optional<RewritePath> commonPath(const RewritePath &other) const;
+
+ /// Form a canonical, dependent type.
+ ///
+ /// This requires that the rewrite path have a base.
+ CanType formDependentType(ASTContext &ctx) const;
+
+ /// Compare the given rewrite paths.
+ int compare(const RewritePath &other) const;
+
+ /// Print this path.
+ void print(llvm::raw_ostream &out) const;
+
+ LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
+ "only for use within the debugger") {
+ print(llvm::errs());
+ }
+
+ friend bool operator==(const RewritePath &lhs, const RewritePath &rhs) {
+ return lhs.getBase() == rhs.getBase() && lhs.getPath() == rhs.getPath();
+ }
+};
+
+/// A node within the prefix tree that is used to match associated type
+/// references.
+class RewriteTreeNode {
+ /// The associated type that leads to this node.
+ ///
+ /// The bit indicates whether there is a rewrite rule for this particular
+ /// node. If the bit is not set, \c rewrite is invalid.
+ llvm::PointerIntPair<AssociatedTypeDecl *, 1, bool> assocTypeAndHasRewrite;
+
+ /// The sequence of associated types to which a reference to this associated
+ /// type (from the equivalence class root) can be rewritten. This field is
+ /// only valid when the bit of \c assocTypeAndHasRewrite is set.
+ ///
+ /// Consider a requirement "Self.A.B.C == C". This will be encoded as
+ /// a prefix tree starting at the equivalence class for Self with
+ /// the following nodes:
+ ///
+ /// (assocType: A,
+ /// children: [
+ /// (assocType: B,
+ /// children: [
+ /// (assocType: C, rewrite: [C], children: [])
+ /// ])
+ /// ])
+ RewritePath rewrite;
+
+ /// The child nodes, which extend the sequence to be matched.
+ ///
+ /// The child nodes are sorted by the associated type declaration
+ /// pointers, so we can perform binary searches quickly.
+ llvm::TinyPtrVector<RewriteTreeNode *> children;
+
+public:
+ ~RewriteTreeNode();
+
+ RewriteTreeNode(AssociatedTypeDecl *assocType)
+ : assocTypeAndHasRewrite(assocType, false) { }
+
+ /// Retrieve the associated type declaration one must match to use this
+ /// node, which may the
+ AssociatedTypeDecl *getMatch() const {
+ return assocTypeAndHasRewrite.getPointer();
+ }
+
+ /// Determine whether this particular node has a rewrite rule.
+ bool hasRewriteRule() const {
+ return assocTypeAndHasRewrite.getInt();
+ }
+
+ /// Set a new rewrite rule for this particular node. This can only be
+ /// performed once.
+ void setRewriteRule(RewritePath replacementPath) {
+ assert(!hasRewriteRule());
+ assocTypeAndHasRewrite.setInt(true);
+ rewrite = replacementPath;
+ }
+
+ /// Retrieve the path to which this node will be rewritten.
+ const RewritePath &getRewriteRule() const {
+ assert(hasRewriteRule());
+ return rewrite;
+ }
+
+ /// Add a new rewrite rule to this tree node.
+ ///
+ /// \param matchPath The path of associated type declarations that must
+ /// be matched to produce a rewrite.
+ ///
+ /// \param replacementPath The sequence of associated type declarations
+ /// with which a match will be replaced.
+ void addRewriteRule(RelativeRewritePath matchPath,
+ RewritePath replacementPath);
+
+ /// Enumerate all of the paths to which the given matched path can be
+ /// rewritten.
+ ///
+ /// \param matchPath The path to match.
+ ///
+ /// \param callback A callback that will be invoked with (prefix, rewrite)
+ /// pairs, where \c prefix is the length of the matching prefix of
+ /// \c matchPath that matched and \c rewrite is the path to which it can
+ /// be rewritten.
+ void enumerateRewritePaths(
+ RelativeRewritePath matchPath,
+ llvm::function_ref<void(unsigned, RewritePath)> callback,
+ unsigned depth = 0) const;
+
+ /// Find the best rewrite rule to match the given path.
+ ///
+ /// \param path The path to match.
+ /// \param prefixLength The length of the prefix leading up to \c path.
+ Optional<std::pair<unsigned, RewritePath>>
+ bestMatch(GenericParamKey base, RelativeRewritePath path,
+ unsigned prefixLength);
+
+ /// Merge the given rewrite tree into \c other.
+ void mergeInto(RewriteTreeNode *other);
+
+ LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
+ "only for use within the debugger");
+
+ /// Dump the tree.
+ void dump(llvm::raw_ostream &out, bool lastChild = true) const;
+
+private:
+ /// Merge the given rewrite tree into \c other.
+ void mergeIntoRec(RewriteTreeNode *other,
+ llvm::SmallVectorImpl<AssociatedTypeDecl *> &matchPath);
+};
+}
struct GenericSignatureBuilder::Implementation {
/// Allocator.
@@ -131,6 +315,9 @@
/// Equivalence classes that are not currently being used.
std::vector<void *> FreeEquivalenceClasses;
+ /// The roots of the rewrite tree.
+ DenseMap<const EquivalenceClass *, RewriteTreeNode *> RewriteTreeRoots;
+
/// The generation number, which is incremented whenever we successfully
/// introduce a new constraint.
unsigned Generation = 0;
@@ -141,16 +328,6 @@
/// Whether we are currently processing delayed requirements.
bool ProcessingDelayedRequirements = false;
- /// Tear down an implementation.
- ~Implementation();
-
- /// Allocate a new equivalence class with the given representative.
- EquivalenceClass *allocateEquivalenceClass(
- PotentialArchetype *representative);
-
- /// Deallocate the given equivalence class, returning it to the free list.
- void deallocateEquivalenceClass(EquivalenceClass *equivClass);
-
/// Whether there were any errors.
bool HadAnyError = false;
@@ -161,12 +338,35 @@
/// Whether we've already finalized the builder.
bool finalized = false;
#endif
+
+ /// Tear down an implementation.
+ ~Implementation();
+
+ /// Allocate a new equivalence class with the given representative.
+ EquivalenceClass *allocateEquivalenceClass(
+ PotentialArchetype *representative);
+
+ /// Deallocate the given equivalence class, returning it to the free list.
+ void deallocateEquivalenceClass(EquivalenceClass *equivClass);
+
+ /// Retrieve the rewrite tree root for the given equivalence class,
+ /// if present.
+ RewriteTreeNode *getRewriteTreeRootIfPresent(
+ const EquivalenceClass *equivClass);
+
+ /// Retrieve the rewrite tree root for the given equivalence class,
+ /// creating it if needed.
+ RewriteTreeNode *getOrCreateRewriteTreeRoot(
+ const EquivalenceClass *equivClass);
};
#pragma mark Memory management
GenericSignatureBuilder::Implementation::~Implementation() {
for (auto pa : PotentialArchetypes)
pa->~PotentialArchetype();
+
+ for (const auto &root : RewriteTreeRoots)
+ delete root.second;
}
EquivalenceClass *
@@ -1915,31 +2115,13 @@
return populateResult((nestedTypeNameCache[name] = std::move(entry)));
}
-/// Determine whether any part of this potential archetype's path to the
-/// root contains the given equivalence class.
-static bool pathContainsEquivalenceClass(GenericSignatureBuilder &builder,
- PotentialArchetype *pa,
- EquivalenceClass *equivClass) {
- // Chase the potential archetype up to the root.
- for (; pa; pa = pa->getParent()) {
- // Check whether this potential archetype is in the given equivalence
- // class.
- if (pa->getOrCreateEquivalenceClass(builder) == equivClass)
- return true;
- }
-
- return false;
-}
-
Type EquivalenceClass::getAnchor(
GenericSignatureBuilder &builder,
TypeArrayView<GenericTypeParamType> genericParams) {
- // Check whether the cache is valid.
- if (archetypeAnchorCache.anchor &&
- archetypeAnchorCache.numMembers == members.size()) {
- ++NumArchetypeAnchorCacheHits;
+ // Substitute into the anchor with the given generic parameters.
+ auto substAnchor = [&] {
+ if (genericParams.empty()) return archetypeAnchorCache.anchor;
- // Reparent the anchor using genericParams.
return archetypeAnchorCache.anchor.subst(
[&](SubstitutableType *dependentType) {
if (auto gp = dyn_cast<GenericTypeParamType>(dependentType)) {
@@ -1951,73 +2133,43 @@
return Type(dependentType);
},
MakeAbstractConformanceForGenericType());
+
+ };
+
+ // Check whether the cache is valid.
+ if (archetypeAnchorCache.anchor &&
+ archetypeAnchorCache.lastGeneration == builder.Impl->Generation) {
+ ++NumArchetypeAnchorCacheHits;
+ return substAnchor();
}
- // Map the members of this equivalence class to the best associated type
- // within that equivalence class.
- llvm::SmallDenseMap<EquivalenceClass *, AssociatedTypeDecl *> nestedTypes;
+ // Check whether we already have an anchor, in which case we
+ // can simplify it further.
+ if (archetypeAnchorCache.anchor) {
+ // Record the cache miss.
+ ++NumArchetypeAnchorCacheMisses;
- Type bestGenericParam;
+ // Update the anchor by simplifying it further.
+ archetypeAnchorCache.anchor =
+ builder.getCanonicalTypeParameter(archetypeAnchorCache.anchor);
+ archetypeAnchorCache.lastGeneration = builder.Impl->Generation;
+ return substAnchor();
+ }
+
+ // Form the anchor.
for (auto member : members) {
- // If the member is a generic parameter, keep the best generic parameter.
- if (member->isGenericParam()) {
- Type genericParamType = member->getDependentType(genericParams);
- if (!bestGenericParam ||
- compareDependentTypes(genericParamType, bestGenericParam) < 0)
- bestGenericParam = genericParamType;
- continue;
- }
+ auto anchorType =
+ builder.getCanonicalTypeParameter(member->getDependentType(genericParams));
+ if (!anchorType) continue;
- // If we saw a generic parameter, ignore any nested types.
- if (bestGenericParam) continue;
-
- // If the nested type doesn't have an associated type, skip it.
- auto assocType = member->getResolvedAssociatedType();
- if (!assocType) continue;
-
- // Dig out the equivalence class of the parent.
- auto parentEquivClass =
- member->getParent()->getOrCreateEquivalenceClass(builder);
-
- // If the path from this member to the root contains this equivalence
- // class, it cannot be part of the anchor.
- if (pathContainsEquivalenceClass(builder, member->getParent(), this))
- continue;
-
- // Take the best associated type for this equivalence class.
- assocType = assocType->getAssociatedTypeAnchor();
- auto &bestAssocType = nestedTypes[parentEquivClass];
- if (!bestAssocType ||
- compareAssociatedTypes(assocType, bestAssocType) < 0)
- bestAssocType = assocType;
+ // Record the cache miss and update the cache.
+ ++NumArchetypeAnchorCacheMisses;
+ archetypeAnchorCache.anchor = anchorType;
+ archetypeAnchorCache.lastGeneration = builder.Impl->Generation;
+ return substAnchor();
}
- // If we found a generic parameter, return that.
- if (bestGenericParam)
- return bestGenericParam;
-
- // Determine the best anchor among the parent equivalence classes.
- Type bestParentAnchor;
- AssociatedTypeDecl *bestAssocType = nullptr;
- std::pair<EquivalenceClass *, Identifier> bestNestedType;
- for (const auto &nestedType : nestedTypes) {
- auto parentAnchor = nestedType.first->getAnchor(builder, genericParams);
- if (!bestParentAnchor ||
- compareDependentTypes(parentAnchor, bestParentAnchor) < 0) {
- bestParentAnchor = parentAnchor;
- bestAssocType = nestedType.second;
- }
- }
-
- // Form the anchor type.
- Type anchorType = DependentMemberType::get(bestParentAnchor, bestAssocType);
-
- // Record the cache miss and update the cache.
- ++NumArchetypeAnchorCacheMisses;
- archetypeAnchorCache.anchor = anchorType;
- archetypeAnchorCache.numMembers = members.size();
-
- return anchorType;
+ llvm_unreachable("Unable to compute anchor");
}
Type EquivalenceClass::getTypeInContext(GenericSignatureBuilder &builder,
@@ -2138,7 +2290,8 @@
return archetype;
}
-void EquivalenceClass::dump(llvm::raw_ostream &out) const {
+void EquivalenceClass::dump(llvm::raw_ostream &out,
+ GenericSignatureBuilder *builder) const {
out << "Equivalence class represented by "
<< members.front()->getRepresentative()->getDebugName() << ":\n";
out << "Members: ";
@@ -2183,6 +2336,13 @@
out << "\n";
+ if (builder) {
+ if (auto rewriteRoot = builder->Impl->getRewriteTreeRootIfPresent(this)) {
+ out << "---Rewrite tree---\n";
+ rewriteRoot->dump(out);
+ }
+ }
+
{
out << "---GraphViz output for same-type constraints---\n";
@@ -2215,8 +2375,8 @@
}
}
-void EquivalenceClass::dump() const {
- dump(llvm::errs());
+void EquivalenceClass::dump(GenericSignatureBuilder *builder) const {
+ dump(llvm::errs(), builder);
}
void DelayedRequirement::dump(llvm::raw_ostream &out) const {
@@ -2523,6 +2683,24 @@
return 0;
}
+/// Compare two dependent paths to determine which is better.
+static int compareDependentPaths(ArrayRef<AssociatedTypeDecl *> path1,
+ ArrayRef<AssociatedTypeDecl *> path2) {
+ // Shorter paths win.
+ if (path1.size() != path2.size())
+ return path1.size() < path2.size() ? -1 : 1;
+
+ // The paths are the same length, so order by comparing the associted
+ // types.
+ for (unsigned index : indices(path1)) {
+ if (int result = compareAssociatedTypes(path1[index], path2[index]))
+ return result;
+ }
+
+ // Identical paths.
+ return 0;
+}
+
namespace {
/// Function object used to suppress conflict diagnoses when we know we'll
/// see them again later.
@@ -2883,6 +3061,507 @@
}
}
+#pragma mark Rewrite tree
+RewritePath::RewritePath(Optional<GenericParamKey> base,
+ RelativeRewritePath path,
+ PathOrder order)
+ : base(base)
+{
+ switch (order) {
+ case Forward:
+ this->path.insert(this->path.begin(), path.begin(), path.end());
+ break;
+
+ case Reverse:
+ this->path.insert(this->path.begin(), path.rbegin(), path.rend());
+ break;
+ }
+}
+
+Optional<RewritePath> RewritePath::createPath(PotentialArchetype *pa) {
+ SmallVector<AssociatedTypeDecl *, 4> path;
+ while (auto parent = pa->getParent()) {
+ auto assocType = pa->getResolvedAssociatedType();
+ if (!assocType) return None;
+
+ path.push_back(assocType);
+ pa = parent;
+ }
+
+ return RewritePath(pa->getGenericParamKey(), path, Reverse);
+}
+
+Optional<RewritePath> RewritePath::createPath(Type type) {
+ SmallVector<AssociatedTypeDecl *, 4> path;
+ while (auto depMemTy = type->getAs<DependentMemberType>()) {
+ auto assocType = depMemTy->getAssocType();
+ if (!assocType) return None;
+
+ path.push_back(assocType);
+ type = depMemTy->getBase();
+ }
+
+ auto genericParam = type->getAs<GenericTypeParamType>();
+ if (!genericParam) return None;
+
+ return RewritePath(GenericParamKey(genericParam), path, Reverse);
+}
+
+Optional<RewritePath> RewritePath::commonPath(const RewritePath &other) const {
+ assert(getBase().hasValue() && other.getBase().hasValue());
+
+ if (*getBase() != *other.getBase()) return None;
+
+ // Find the longest common prefix.
+ RelativeRewritePath path1 = getPath();
+ RelativeRewritePath path2 = other.getPath();
+ if (path1.size() > path2.size())
+ std::swap(path1, path2);
+ unsigned prefixLength =
+ std::mismatch(path1.begin(), path1.end(), path2.begin()).first
+ - path1.begin();
+
+ // Form the common path.
+ return RewritePath(getBase(), path1.slice(0, prefixLength), Forward);
+}
+
+/// Form a dependent type with the given generic parameter, then following the
+/// path of associated types.
+static Type formDependentType(GenericTypeParamType *base,
+ RelativeRewritePath path) {
+ return std::accumulate(path.begin(), path.end(), Type(base),
+ [](Type type, AssociatedTypeDecl *assocType) -> Type {
+ return DependentMemberType::get(type, assocType);
+ });
+}
+
+/// Form a dependent type with the (canonical) generic parameter for the given
+/// parameter key, then following the path of associated types.
+static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam,
+ RelativeRewritePath path) {
+ return formDependentType(GenericTypeParamType::get(genericParam.Depth,
+ genericParam.Index,
+ ctx),
+ path);
+}
+
+CanType RewritePath::formDependentType(ASTContext &ctx) const {
+ assert(getBase());
+ return CanType(::formDependentType(ctx, *getBase(), getPath()));
+}
+
+int RewritePath::compare(const RewritePath &other) const {
+ // Prefer relative to absolute paths.
+ if (getBase().hasValue() != other.getBase().hasValue()) {
+ return other.getBase().hasValue() ? -1 : 1;
+ }
+
+ // Order based on the bases.
+ if (getBase() && *getBase() != *other.getBase())
+ return (*getBase() < *other.getBase()) ? -1 : 1;
+
+ // Order based on the path contents.
+ return compareDependentPaths(getPath(), other.getPath());
+}
+
+void RewritePath::print(llvm::raw_ostream &out) const {
+ out << "[";
+
+ if (getBase()) {
+ out << "(" << getBase()->Depth << ", " << getBase()->Index << ")";
+ if (!getPath().empty()) out << " -> ";
+ }
+
+ interleave(getPath().begin(), getPath().end(),
+ [&](AssociatedTypeDecl *assocType) {
+ out.changeColor(raw_ostream::BLUE);
+ out << assocType->getProtocol()->getName() << "."
+ << assocType->getName();
+ out.resetColor();
+ }, [&] {
+ out << " -> ";
+ });
+ out << "]";
+}
+
+RewriteTreeNode::~RewriteTreeNode() {
+ for (auto child : children)
+ delete child;
+}
+
+namespace {
+/// Function object used to order rewrite tree nodes based on the address
+/// of the associated type.
+class OrderTreeRewriteNode {
+ bool compare(AssociatedTypeDecl *lhs, AssociatedTypeDecl *rhs) const {
+ // Make sure null pointers precede everything else.
+ if (static_cast<bool>(lhs) != static_cast<bool>(rhs))
+ return static_cast<bool>(rhs);
+
+ // Use std::less to provide a defined ordering.
+ return std::less<AssociatedTypeDecl *>()(lhs, rhs);
+ }
+
+public:
+ bool operator()(RewriteTreeNode *lhs, AssociatedTypeDecl *rhs) const {
+ return compare(lhs->getMatch(), rhs);
+ }
+
+ bool operator()(AssociatedTypeDecl *lhs, RewriteTreeNode *rhs) const {
+ return compare(lhs, rhs->getMatch());
+ }
+
+ bool operator()(RewriteTreeNode *lhs, RewriteTreeNode *rhs) const {
+ return compare(lhs->getMatch(), rhs->getMatch());
+ }
+};
+}
+
+void RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
+ RewritePath replacementPath) {
+ // If the match path is empty, we're adding the rewrite rule to this node.
+ if (matchPath.empty()) {
+ // If we don't already have a rewrite rule, add it.
+ if (!hasRewriteRule()) {
+ setRewriteRule(replacementPath);
+ return;
+ }
+
+ // If we already have this rewrite rule, we're done.
+ if (getRewriteRule() == replacementPath) return;
+
+ // Check whether any of the continuation children matches.
+ auto insertPos = children.begin();
+ while (insertPos != children.end() && !(*insertPos)->getMatch()) {
+ if ((*insertPos)->hasRewriteRule() &&
+ (*insertPos)->getRewriteRule() == replacementPath)
+ return;
+
+ ++insertPos;
+ }
+
+ // We already have a rewrite rule, so add a new child with a
+ // null associated type match to hold the rewrite rule.
+ auto newChild = new RewriteTreeNode(nullptr);
+ newChild->setRewriteRule(replacementPath);
+ children.insert(insertPos, newChild);
+ return;
+ }
+
+ // Find (or create) a child node describing the next step in the match.
+ auto matchFront = matchPath.front();
+ auto childPos =
+ std::lower_bound(children.begin(), children.end(), matchFront,
+ OrderTreeRewriteNode());
+ if (childPos == children.end() || (*childPos)->getMatch() != matchFront) {
+ childPos = children.insert(childPos, new RewriteTreeNode(matchFront));
+ }
+
+ // Add the rewrite rule to the child.
+ (*childPos)->addRewriteRule(matchPath.slice(1), replacementPath);
+}
+
+void RewriteTreeNode::enumerateRewritePaths(
+ RelativeRewritePath matchPath,
+ llvm::function_ref<void(unsigned, RewritePath)> callback,
+ unsigned depth) const {
+ // Determine whether we know anything about the next step in the path.
+ auto childPos =
+ depth < matchPath.size()
+ ? std::lower_bound(children.begin(), children.end(),
+ matchPath[depth], OrderTreeRewriteNode())
+ : children.end();
+ if (childPos != children.end() &&
+ (*childPos)->getMatch() == matchPath[depth]) {
+ // Try to match the rest of the path.
+ (*childPos)->enumerateRewritePaths(matchPath, callback, depth + 1);
+ }
+
+ // If we have a rewrite rule at this position, invoke it.
+ if (hasRewriteRule()) {
+ // Invoke the callback with the first result.
+ callback(depth, rewrite);
+ }
+
+ // Walk any children with NULL associated types; they might have more matches.
+ for (auto otherRewrite : children) {
+ if (otherRewrite->getMatch()) break;
+ otherRewrite->enumerateRewritePaths(matchPath, callback, depth);
+ }
+}
+
+Optional<std::pair<unsigned, RewritePath>>
+RewriteTreeNode::bestMatch(GenericParamKey base, RelativeRewritePath path,
+ unsigned prefixLength) {
+ Optional<std::pair<unsigned, RewritePath>> best;
+ unsigned bestAdjustedLength = 0;
+ enumerateRewritePaths(path,
+ [&](unsigned length, RewritePath path) {
+ // Determine how much of the original path will be replaced by the rewrite.
+ unsigned adjustedLength = length;
+ if (auto newBase = path.getBase()) {
+ adjustedLength += prefixLength;
+
+ // If the base is unchanged, make sure we're reducing the length.
+ if (*newBase == base && adjustedLength <= path.getPath().size())
+ return;
+ }
+
+ if (adjustedLength == 0) return;
+
+ if (adjustedLength > bestAdjustedLength ||
+ (adjustedLength == bestAdjustedLength &&
+ path.compare(best->second) < 0)) {
+ best = { length, path };
+ bestAdjustedLength = adjustedLength;
+ }
+ });
+
+ return best;
+}
+
+void RewriteTreeNode::mergeInto(RewriteTreeNode *other) {
+ SmallVector<AssociatedTypeDecl *, 4> matchPath;
+ mergeIntoRec(other, matchPath);
+}
+
+void RewriteTreeNode::mergeIntoRec(
+ RewriteTreeNode *other,
+ llvm::SmallVectorImpl<AssociatedTypeDecl *> &matchPath) {
+ // FIXME: A destructive version of this operation would be more efficient,
+ // since we generally don't care about \c other after doing this.
+ if (auto assocType = getMatch())
+ matchPath.push_back(assocType);
+
+ // Add this rewrite rule, if there is one.
+ if (hasRewriteRule())
+ other->addRewriteRule(matchPath, rewrite);
+
+ // Recurse into the child nodes.
+ for (auto child : children)
+ child->mergeIntoRec(other, matchPath);
+
+ if (auto assocType = getMatch())
+ matchPath.pop_back();
+}
+
+void RewriteTreeNode::dump() const {
+ dump(llvm::errs());
+}
+
+void RewriteTreeNode::dump(llvm::raw_ostream &out, bool lastChild) const {
+ std::string prefixStr;
+
+ std::function<void(const RewriteTreeNode *, bool lastChild)> print;
+ print = [&](const RewriteTreeNode *node, bool lastChild) {
+ out << prefixStr << " `--";
+
+ // Print the node name.
+ out.changeColor(raw_ostream::GREEN);
+ if (auto assoc = node->getMatch())
+ out << assoc->getProtocol()->getName() << "." << assoc->getName();
+ else
+ out << "(cont'd)";
+ out.resetColor();
+
+ // Print the rewrite, if there is one.
+ if (node->hasRewriteRule()) {
+ out << " --> ";
+ node->rewrite.print(out);
+ }
+
+ out << "\n";
+
+ // Print children.
+ prefixStr += ' ';
+ prefixStr += (lastChild ? ' ' : '|');
+ prefixStr += " ";
+
+ for (auto child : node->children) {
+ print(child, child == node->children.back());
+ }
+
+ prefixStr.erase(prefixStr.end() - 4, prefixStr.end());
+ };
+
+ print(this, lastChild);
+}
+
+RewriteTreeNode *
+GenericSignatureBuilder::Implementation::getRewriteTreeRootIfPresent(
+ const EquivalenceClass *equivClass) {
+ auto known = RewriteTreeRoots.find(equivClass);
+ if (known != RewriteTreeRoots.end()) return known->second;
+
+ return nullptr;
+}
+
+RewriteTreeNode *
+GenericSignatureBuilder::Implementation::getOrCreateRewriteTreeRoot(
+ const EquivalenceClass *equivClass) {
+ auto known = RewriteTreeRoots.find(equivClass);
+ if (known != RewriteTreeRoots.end()) return known->second;
+
+ auto root = new RewriteTreeNode(nullptr);
+ RewriteTreeRoots[equivClass] = root;
+ return root;
+}
+
+void GenericSignatureBuilder::addSameTypeRewriteRule(PotentialArchetype *pa1,
+ PotentialArchetype *pa2){
+ auto pathOpt1 = RewritePath::createPath(pa1);
+ if (!pathOpt1) return;
+
+ auto pathOpt2 = RewritePath::createPath(pa2);
+ if (!pathOpt2) return;
+
+ auto path1 = std::move(pathOpt1).getValue();
+ auto path2 = std::move(pathOpt2).getValue();
+
+ // Look for a common path.
+ auto prefix = path1.commonPath(path2);
+
+ // If we didn't find a common path, try harder.
+ Type simplifiedType1;
+ Type simplifiedType2;
+ if (!prefix) {
+ // Simplify both sides in the hope of uncovering a common path.
+ simplifiedType1 = getCanonicalTypeParameter(pa1->getDependentType({ }));
+ simplifiedType2 = getCanonicalTypeParameter(pa2->getDependentType({ }));
+ if (simplifiedType1->isEqual(simplifiedType2)) return;
+
+ // Create new paths from the simplified types.
+ path1 = *RewritePath::createPath(simplifiedType1);
+ path2 = *RewritePath::createPath(simplifiedType2);
+
+ // Find a common path.
+ prefix = path1.commonPath(path2);
+ }
+
+ // When we have a common prefix, form a rewrite rule using relative paths.
+ if (prefix) {
+ // Find the better relative rewrite path.
+ RelativeRewritePath relPath1
+ = path1.getPath().slice(prefix->getPath().size());
+ RelativeRewritePath relPath2
+ = path2.getPath().slice(prefix->getPath().size());
+ // Order the paths so that we go to the more-canonical path.
+ if (compareDependentPaths(relPath1, relPath2) < 0)
+ std::swap(relPath1, relPath2);
+
+ // Find the equivalence class for the prefix.
+ CanType commonType = prefix->formDependentType(getASTContext());
+ auto equivClass =
+ resolveEquivalenceClass(commonType, ArchetypeResolutionKind::WellFormed);
+ assert(equivClass && "Prefix cannot be resolved?");
+
+ // Add the rewrite rule.
+ auto root = Impl->getOrCreateRewriteTreeRoot(equivClass);
+ root->addRewriteRule(relPath1,
+ RewritePath(None, relPath2, RewritePath::Forward));
+
+ return;
+ }
+
+ // Otherwise, form a rewrite rule with absolute paths.
+
+ // Find the better path and make sure it's in path2.
+ if (compareDependentTypes(simplifiedType1, simplifiedType2) < 0) {
+ std::swap(path1, path2);
+ std::swap(simplifiedType1, simplifiedType2);
+ }
+
+ // Add the rewrite rule.
+ Type firstBase =
+ GenericTypeParamType::get(path1.getBase()->Depth, path1.getBase()->Index,
+ getASTContext());
+ auto equivClass =
+ resolveEquivalenceClass(firstBase, ArchetypeResolutionKind::WellFormed);
+ assert(equivClass && "Base cannot be resolved?");
+
+ auto root = Impl->getOrCreateRewriteTreeRoot(equivClass);
+ root->addRewriteRule(path1.getPath(), path2);
+}
+
+Type GenericSignatureBuilder::getCanonicalTypeParameter(Type type) {
+ auto initialPath = RewritePath::createPath(type);
+ if (!initialPath) return nullptr;
+
+ auto genericParamType =
+ GenericTypeParamType::get(initialPath->getBase()->Depth,
+ initialPath->getBase()->Index,
+ getASTContext());
+ auto initialEquivClass =
+ resolveEquivalenceClass(genericParamType,
+ ArchetypeResolutionKind::WellFormed);
+ if (!initialEquivClass) return nullptr;
+
+ unsigned startIndex = 0;
+ auto equivClass = initialEquivClass;
+ Type currentType = genericParamType;
+ SmallVector<AssociatedTypeDecl *, 4> path(initialPath->getPath().begin(),
+ initialPath->getPath().end());
+ bool simplified = false;
+ do {
+ if (auto rootNode = Impl->getRewriteTreeRootIfPresent(equivClass)) {
+ // Find the best rewrite rule for the path starting at startIndex.
+ auto match =
+ rootNode->bestMatch(genericParamType,
+ llvm::makeArrayRef(path).slice(startIndex),
+ startIndex);
+
+ // If we have a match, replace the matched path with the replacement
+ // path.
+ if (match) {
+ // Determine the range in the path which we'll be replacing.
+ unsigned replaceStartIndex = match->second.getBase() ? 0 : startIndex;
+ unsigned replaceEndIndex = startIndex + match->first;
+
+ // Overwrite the beginning of the match.
+ auto replacementPath = match->second.getPath();
+ assert((replaceEndIndex - replaceStartIndex) >= replacementPath.size());
+ auto replacementStartPos = path.begin() + replaceStartIndex;
+ std::copy(replacementPath.begin(), replacementPath.end(),
+ replacementStartPos);
+
+ // Erase the rest.
+ path.erase(replacementStartPos + replacementPath.size(),
+ path.begin() + replaceEndIndex);
+
+ // If this is an absolute path, use the new base.
+ if (auto newBase = match->second.getBase()) {
+ genericParamType =
+ GenericTypeParamType::get(newBase->Depth, newBase->Index,
+ getASTContext());
+ initialEquivClass =
+ resolveEquivalenceClass(genericParamType,
+ ArchetypeResolutionKind::WellFormed);
+ assert(initialEquivClass && "Must have an equivalence class");
+ }
+
+ // Move back to the beginning; we may have opened up other rewrites.
+ simplified = true;
+ startIndex = 0;
+ currentType = genericParamType;
+ equivClass = initialEquivClass;
+ continue;
+ }
+ }
+
+ // If we've hit the end of the path, we're done.
+ if (startIndex >= path.size()) break;
+
+ // FIXME: It would be nice if there were a better way to get the equivalence
+ // class of a named nested type.
+ currentType = DependentMemberType::get(currentType, path[startIndex++]);
+ equivClass =
+ resolveEquivalenceClass(currentType, ArchetypeResolutionKind::WellFormed);
+ if (!equivClass) break;
+ } while (true);
+
+ return formDependentType(genericParamType, path);
+}
+
#pragma mark Equivalence classes
EquivalenceClass::EquivalenceClass(PotentialArchetype *representative)
: recursiveConcreteType(false), invalidConcreteType(false),
@@ -3865,6 +4544,9 @@
PotentialArchetype *OrigT2,
const RequirementSource *Source)
{
+ // Add a rewrite rule based on the given same-type constraint.
+ addSameTypeRewriteRule(OrigT1, OrigT2);
+
// Record the same-type constraint, and bail out if it was already known.
if (!OrigT1->getOrCreateEquivalenceClass(*this)
->recordSameTypeConstraint(OrigT1, OrigT2, Source))
@@ -3910,6 +4592,20 @@
equivClass->sameTypeConstraints.end(),
equivClass2->sameTypeConstraints.begin(),
equivClass2->sameTypeConstraints.end());
+
+ // Combine the rewrite rules.
+ if (auto rewriteRoot2 = Impl->getOrCreateRewriteTreeRoot(equivClass2)) {
+ if (auto rewriteRoot1 = Impl->getOrCreateRewriteTreeRoot(equivClass)) {
+ // Merge the second rewrite tree into the first.
+ rewriteRoot2->mergeInto(rewriteRoot1);
+ Impl->RewriteTreeRoots.erase(equivClass2);
+ delete rewriteRoot2;
+ } else {
+ // Take the second rewrite tree and make it the first.
+ Impl->RewriteTreeRoots.erase(equivClass2);
+ (void)Impl->RewriteTreeRoots.insert({equivClass, rewriteRoot2});
+ }
+ }
}
// Same-type-to-concrete requirements.
@@ -5446,7 +6142,7 @@
return lhs.constraint < rhs.constraint;
}
- LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
+ LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
"only for use in the debugger");
};
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 8fcfcce..e506ae4 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -212,23 +212,16 @@
case llvm::Triple::TvOS:
case llvm::Triple::WatchOS:
return llvm::make_unique<toolchains::Darwin>(*this, target);
- break;
case llvm::Triple::Linux:
- if (target.isAndroid()) {
+ if (target.isAndroid())
return llvm::make_unique<toolchains::Android>(*this, target);
- } else {
- return llvm::make_unique<toolchains::GenericUnix>(*this, target);
- }
- break;
+ return llvm::make_unique<toolchains::GenericUnix>(*this, target);
case llvm::Triple::FreeBSD:
return llvm::make_unique<toolchains::GenericUnix>(*this, target);
- break;
case llvm::Triple::Win32:
return llvm::make_unique<toolchains::Cygwin>(*this, target);
- break;
case llvm::Triple::Haiku:
return llvm::make_unique<toolchains::GenericUnix>(*this, target);
- break;
default:
Diags.diagnose(SourceLoc(), diag::error_unknown_target,
ArgList.getLastArg(options::OPT_target)->getValue());
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 222dbc7..382b4ee 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3905,7 +3905,8 @@
if (Flags.contains(PD_InProtocol) || isInSILMode()) {
if (Tok.is(tok::r_brace)) {
// Give syntax node an empty statement list.
- SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+ SyntaxParsingContext StmtListContext(SyntaxContext,
+ SyntaxKind::CodeBlockItemList);
}
while (Tok.isNot(tok::r_brace)) {
if (Tok.is(tok::eof))
@@ -3988,7 +3989,8 @@
// an implicit fallthrough off the end.
if (Tok.is(tok::r_brace)) {
// Give syntax node an empty statement list.
- SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+ SyntaxParsingContext StmtListContext(SyntaxContext,
+ SyntaxKind::CodeBlockItemList);
diagnose(Tok, diag::computed_property_no_accessors);
return true;
}
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 84d5bc9..5915b16 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -89,6 +89,7 @@
ParserStatus Parser::parseExprOrStmt(ASTNode &Result) {
if (Tok.is(tok::semi)) {
+ SyntaxParsingContext ErrorCtxt(SyntaxContext, SyntaxContextKind::Stmt);
diagnose(Tok, diag::illegal_semi_stmt)
.fixItRemove(SourceRange(Tok.getLoc()));
consumeToken();
@@ -112,6 +113,7 @@
if (Tok.is(tok::code_complete)) {
if (CodeCompletion)
CodeCompletion->completeStmtOrExpr();
+ SyntaxParsingContext ErrorCtxt(SyntaxContext, SyntaxContextKind::Stmt);
consumeToken(tok::code_complete);
return makeParserCodeCompletionStatus();
}
@@ -228,7 +230,8 @@
ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
BraceItemListKind Kind,
BraceItemListKind ConditionalBlockKind) {
- SyntaxParsingContext StmtListContext(SyntaxContext, SyntaxKind::StmtList);
+ SyntaxParsingContext ItemListContext(SyntaxContext,
+ SyntaxKind::CodeBlockItemList);
bool IsTopLevel = (Kind == BraceItemListKind::TopLevelCode) ||
(Kind == BraceItemListKind::TopLevelLibrary);
@@ -264,9 +267,10 @@
(isConditionalBlock ||
!isTerminatorForBraceItemListKind(Kind, Entries))) {
- SyntaxParsingContext StmtContext(SyntaxContext, SyntaxContextKind::Stmt);
+ SyntaxParsingContext NodeContext(SyntaxContext, SyntaxKind::CodeBlockItem);
if (Tok.is(tok::r_brace)) {
+ SyntaxParsingContext ErrContext(SyntaxContext, SyntaxContextKind::Stmt);
assert(IsTopLevel);
diagnose(Tok, diag::extra_rbrace)
.fixItRemove(Tok.getLoc());
@@ -275,8 +279,11 @@
}
// Eat invalid tokens instead of allowing them to produce downstream errors.
- if (consumeIf(tok::unknown))
+ if (Tok.is(tok::unknown)) {
+ SyntaxParsingContext ErrContext(SyntaxContext, SyntaxContextKind::Stmt);
+ consumeToken();
continue;
+ }
bool NeedParseErrorRecovery = false;
ASTNode Result;
@@ -411,6 +418,11 @@
}
if (NeedParseErrorRecovery) {
+ SyntaxContext->createNodeInPlace(SyntaxKind::CodeBlockItem);
+ SyntaxContext->setTransparent();
+
+ SyntaxParsingContext ItemCtxt(SyntaxContext, SyntaxKind::CodeBlockItem);
+ SyntaxParsingContext StmtCtxt(SyntaxContext, SyntaxContextKind::Stmt);
// If we had a parse error, skip to the start of the next stmt, decl or
// '{'.
//
diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp
index 825e607..c17400e 100644
--- a/lib/Parse/SyntaxParsingContext.cpp
+++ b/lib/Parse/SyntaxParsingContext.cpp
@@ -68,17 +68,10 @@
if (Parts.size() == 1) {
auto RawNode = Parts.front();
switch (Kind) {
- case SyntaxContextKind::Stmt: {
- if (RawNode->isStmt())
- return RawNode;
- else if (RawNode->isDecl())
- return createSyntaxAs(SyntaxKind::DeclarationStmt, Parts);
- else if (RawNode->isExpr())
- return createSyntaxAs(SyntaxKind::ExpressionStmt, Parts);
- else
+ case SyntaxContextKind::Stmt:
+ if (!RawNode->isStmt())
return makeUnknownSyntax(SyntaxKind::UnknownStmt, Parts);
break;
- }
case SyntaxContextKind::Decl:
if (!RawNode->isDecl())
return makeUnknownSyntax(SyntaxKind::UnknownDecl, Parts);
@@ -186,6 +179,7 @@
createNodeInPlace(Kind, Pair.first);
break;
}
+ case SyntaxKind::CodeBlockItem:
case SyntaxKind::IdentifierExpr:
case SyntaxKind::SpecializeExpr:
case SyntaxKind::MemberAccessExpr:
@@ -255,8 +249,8 @@
if (SF.hasSyntaxRoot()) {
auto SourceRaw = SF.getSyntaxRoot().getRaw();
- auto Decls = SourceRaw->getChild(SourceFileSyntax::Cursor::TopLevelDecls)
- ->getLayout();
+ auto Decls =
+ SourceRaw->getChild(SourceFileSyntax::Cursor::Items)->getLayout();
std::copy(Decls.begin(), Decls.end(), std::back_inserter(AllTopLevel));
EOFToken = SourceRaw->getChild(SourceFileSyntax::Cursor::EOFToken);
}
@@ -267,12 +261,13 @@
}
for (auto RawNode : Parts) {
- if (RawNode->getKind() != SyntaxKind::StmtList)
+ if (RawNode->getKind() != SyntaxKind::CodeBlockItemList)
// FIXME: Skip toplevel garbage nodes for now. we shouldn't emit them in
// the first place.
continue;
- AllTopLevel.push_back(
- SyntaxFactory::createRaw(SyntaxKind::TopLevelCodeDecl, {RawNode}));
+
+ auto Items = RawNode->getLayout();
+ std::copy(Items.begin(), Items.end(), std::back_inserter(AllTopLevel));
}
if (!EOFToken)
@@ -281,8 +276,10 @@
auto newRaw = SyntaxFactory::createRaw(
SyntaxKind::SourceFile,
{
- SyntaxFactory::createRaw(SyntaxKind::DeclList, AllTopLevel), EOFToken,
+ SyntaxFactory::createRaw(SyntaxKind::CodeBlockItemList, AllTopLevel),
+ EOFToken,
});
+ assert(newRaw);
SF.setSyntaxRoot(make<SourceFileSyntax>(newRaw));
if (SF.getASTContext().LangOpts.VerifySyntaxTree) {
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index 4f2c181..2df2022 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -239,14 +239,13 @@
return false;
}
-/// Given that a type is not statically known to be an optional type, check whether
-/// it might dynamically be an optional type.
-static bool canDynamicallyBeOptionalType(CanType type) {
+/// Given that a type is not statically known to be an optional type, check
+/// whether it might dynamically be able to store an optional.
+static bool canDynamicallyStoreOptional(CanType type) {
assert(!type.getOptionalObjectType());
- return (isa<ArchetypeType>(type) || type.isExistentialType())
- && !type.isAnyClassReferenceType();
+ return type->canDynamicallyBeOptionalType(/* includeExistential */ true);
}
-
+
/// Given two class types, check whether there's a hierarchy relationship
/// between them.
static DynamicCastFeasibility
@@ -326,7 +325,7 @@
auto result = classifyDynamicCast(M, source, targetObject,
/* isSourceTypeExact */ false,
isWholeModuleOpts);
- if (canDynamicallyBeOptionalType(source))
+ if (canDynamicallyStoreOptional(source))
result = atWorst(result, DynamicCastFeasibility::MaySucceed);
return result;
diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp
index 85188ca..fe0371b 100644
--- a/lib/SIL/Projection.cpp
+++ b/lib/SIL/Projection.cpp
@@ -73,8 +73,6 @@
Value = ValueTy(ProjectionKind::Struct, SEAI->getFieldNo());
assert(getKind() == ProjectionKind::Struct);
assert(getIndex() == SEAI->getFieldNo());
- assert(getType(SEAI->getOperand()->getType(), SEAI->getModule()) ==
- SEAI->getType());
break;
}
case SILInstructionKind::StructExtractInst: {
@@ -82,8 +80,6 @@
Value = ValueTy(ProjectionKind::Struct, SEI->getFieldNo());
assert(getKind() == ProjectionKind::Struct);
assert(getIndex() == SEI->getFieldNo());
- assert(getType(SEI->getOperand()->getType(), SEI->getModule()) ==
- SEI->getType());
break;
}
case SILInstructionKind::RefElementAddrInst: {
@@ -91,8 +87,6 @@
Value = ValueTy(ProjectionKind::Class, REAI->getFieldNo());
assert(getKind() == ProjectionKind::Class);
assert(getIndex() == REAI->getFieldNo());
- assert(getType(REAI->getOperand()->getType(), REAI->getModule()) ==
- REAI->getType());
break;
}
case SILInstructionKind::RefTailAddrInst: {
@@ -107,8 +101,6 @@
Value = ValueTy(ProjectionKind::Box, static_cast<uintptr_t>(0));
assert(getKind() == ProjectionKind::Box);
assert(getIndex() == 0);
- assert(getType(PBI->getOperand()->getType(), PBI->getModule()) ==
- PBI->getType());
(void) PBI;
break;
}
@@ -117,8 +109,6 @@
Value = ValueTy(ProjectionKind::Tuple, TEI->getFieldNo());
assert(getKind() == ProjectionKind::Tuple);
assert(getIndex() == TEI->getFieldNo());
- assert(getType(TEI->getOperand()->getType(), TEI->getModule()) ==
- TEI->getType());
break;
}
case SILInstructionKind::TupleElementAddrInst: {
@@ -126,8 +116,6 @@
Value = ValueTy(ProjectionKind::Tuple, TEAI->getFieldNo());
assert(getKind() == ProjectionKind::Tuple);
assert(getIndex() == TEAI->getFieldNo());
- assert(getType(TEAI->getOperand()->getType(), TEAI->getModule()) ==
- TEAI->getType());
break;
}
case SILInstructionKind::UncheckedEnumDataInst: {
@@ -135,8 +123,6 @@
Value = ValueTy(ProjectionKind::Enum, UEDI->getElementNo());
assert(getKind() == ProjectionKind::Enum);
assert(getIndex() == UEDI->getElementNo());
- assert(getType(UEDI->getOperand()->getType(), UEDI->getModule()) ==
- UEDI->getType());
break;
}
case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
@@ -144,8 +130,6 @@
Value = ValueTy(ProjectionKind::Enum, UTEDAI->getElementNo());
assert(getKind() == ProjectionKind::Enum);
assert(getIndex() == UTEDAI->getElementNo());
- assert(getType(UTEDAI->getOperand()->getType(), UTEDAI->getModule()) ==
- UTEDAI->getType());
break;
}
case SILInstructionKind::IndexAddrInst: {
@@ -168,8 +152,6 @@
assert(Ty->isCanonical());
Value = ValueTy(ProjectionKind::Upcast, Ty);
assert(getKind() == ProjectionKind::Upcast);
- assert(getType(I->getOperand(0)->getType(), I->getModule()) ==
- I->getType());
break;
}
case SILInstructionKind::UncheckedRefCastInst: {
@@ -177,8 +159,6 @@
assert(Ty->isCanonical());
Value = ValueTy(ProjectionKind::RefCast, Ty);
assert(getKind() == ProjectionKind::RefCast);
- assert(getType(I->getOperand(0)->getType(), I->getModule()) ==
- I->getType());
break;
}
case SILInstructionKind::UncheckedBitwiseCastInst:
@@ -187,8 +167,6 @@
assert(Ty->isCanonical());
Value = ValueTy(ProjectionKind::BitwiseCast, Ty);
assert(getKind() == ProjectionKind::BitwiseCast);
- assert(getType(I->getOperand(0)->getType(), I->getModule()) ==
- I->getType());
break;
}
}
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index bce425e..112a213 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -3299,14 +3299,21 @@
auto destValueType
= finalResultType->lookThroughAllOptionalTypes(destOptionals);
- // When performing a bridging operation, if the destination value type
- // is 'AnyObject', leave any extra optionals on the source in place.
- if (castKind == OptionalBindingsCastKind::Bridged &&
- srcOptionals.size() > destOptionals.size() &&
- destValueType->isAnyObject()) {
- srcType = srcOptionals[destOptionals.size()];
- srcOptionals.erase(srcOptionals.begin() + destOptionals.size(),
- srcOptionals.end());
+ auto isBridgeToAnyObject =
+ castKind == OptionalBindingsCastKind::Bridged &&
+ destValueType->isAnyObject();
+
+ // If the destination value type is 'AnyObject' when performing a
+ // bridging operation, or if the destination value type could dynamically
+ // be an optional type, leave any extra optionals on the source in place.
+ if (isBridgeToAnyObject || destValueType->canDynamicallyBeOptionalType(
+ /* includeExistential */ false)) {
+ auto destOptionalsCount = destOptionals.size() - destExtraOptionals;
+ if (srcOptionals.size() > destOptionalsCount) {
+ srcType = srcOptionals[destOptionalsCount];
+ srcOptionals.erase(srcOptionals.begin() + destOptionalsCount,
+ srcOptionals.end());
+ }
}
// When performing a bridging operation, if the destination type
@@ -4482,9 +4489,6 @@
/// Diagnose an optional injection that is probably not what the
/// user wanted, because it comes from a forced downcast.
void diagnoseOptionalInjection(InjectIntoOptionalExpr *injection) {
- // Don't diagnose when we're injecting into
- auto toOptionalType = cs.getType(injection);
-
// Check whether we have a forced downcast.
auto &tc = cs.getTypeChecker();
auto *cast = findForcedDowncast(tc.Context, injection->getSubExpr());
@@ -6152,7 +6156,10 @@
// func bar() -> ((()) -> Void)? { return nil }
// foo(bar) // This expression should compile in Swift 3 mode
// ```
- if (tc.getLangOpts().isSwiftVersion3()) {
+ //
+ // See also: https://bugs.swift.org/browse/SR-6796
+ if (cs.getASTContext().isSwiftVersionAtLeast(3) &&
+ !cs.getASTContext().isSwiftVersionAtLeast(5)) {
auto obj1 = fromType->getOptionalObjectType();
auto obj2 = toType->getOptionalObjectType();
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 802b9b5..7971360 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1168,6 +1168,35 @@
}
}
+ // https://bugs.swift.org/browse/SR-6796
+ // Add a super-narrow hack to allow:
+ // (()) -> T to be passed in place of () -> T
+ if (getASTContext().isSwiftVersionAtLeast(4) &&
+ !getASTContext().isSwiftVersionAtLeast(5)) {
+ SmallVector<LocatorPathElt, 4> path;
+ locator.getLocatorParts(path);
+
+ // Find the last path element, skipping GenericArgument elements
+ // so that we allow this exception in cases of optional types, and
+ // skipping OptionalPayload elements so that we allow this
+ // exception in cases of optional injection.
+ auto last = std::find_if(
+ path.rbegin(), path.rend(), [](LocatorPathElt &elt) -> bool {
+ return elt.getKind() != ConstraintLocator::GenericArgument &&
+ elt.getKind() != ConstraintLocator::OptionalPayload;
+ });
+
+ if (last != path.rend()) {
+ if (last->getKind() == ConstraintLocator::ApplyArgToParam) {
+ if (auto *paren1 = dyn_cast<ParenType>(func1Input.getPointer())) {
+ auto innerTy = paren1->getUnderlyingType();
+ if (func2Input->isVoid() && innerTy->isVoid())
+ func1Input = innerTy;
+ }
+ }
+ }
+ }
+
// Input types can be contravariant (or equal).
SmallVector<AnyFunctionType::Param, 4> func1Params;
SmallVector<AnyFunctionType::Param, 4> func2Params;
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 682b604..50a8c09 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1264,18 +1264,22 @@
case XREF_TYPE_PATH_PIECE:
case XREF_VALUE_PATH_PIECE: {
IdentifierID IID;
+ IdentifierID privateDiscriminator = 0;
TypeID TID = 0;
bool isType = (recordID == XREF_TYPE_PATH_PIECE);
bool inProtocolExt = false;
bool isStatic = false;
if (isType)
- XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
+ XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
+ inProtocolExt);
else
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
isStatic);
DeclBaseName name = getDeclBaseName(IID);
pathTrace.addValue(name);
+ if (privateDiscriminator)
+ pathTrace.addValue(getIdentifier(privateDiscriminator));
Type filterTy;
if (!isType) {
@@ -1290,9 +1294,14 @@
pathTrace.addType(filterTy);
}
- baseModule->lookupQualified(ModuleType::get(baseModule), name,
- NL_QualifiedDefault | NL_KnownNoDependency,
- /*typeResolver=*/nullptr, values);
+ if (privateDiscriminator) {
+ baseModule->lookupMember(values, baseModule, name,
+ getIdentifier(privateDiscriminator));
+ } else {
+ baseModule->lookupQualified(ModuleType::get(baseModule), name,
+ NL_QualifiedDefault | NL_KnownNoDependency,
+ /*typeResolver=*/nullptr, values);
+ }
filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt, isStatic,
None, values);
break;
@@ -1348,7 +1357,7 @@
switch (recordID) {
case XREF_TYPE_PATH_PIECE: {
IdentifierID IID;
- XRefTypePathPieceLayout::readRecord(scratch, IID, None);
+ XRefTypePathPieceLayout::readRecord(scratch, IID, None, None);
result = getIdentifier(IID);
break;
}
@@ -1405,8 +1414,13 @@
// Fast path for nested types that avoids deserializing all
// members of the parent type.
IdentifierID IID;
+ IdentifierID privateDiscriminator;
bool onlyInNominal = false;
- XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
+ XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
+ onlyInNominal);
+ if (privateDiscriminator)
+ goto giveUpFastPath;
+
Identifier memberName = getIdentifier(IID);
pathTrace.addValue(memberName);
@@ -1449,21 +1463,25 @@
pathTrace.removeLast();
}
+giveUpFastPath:
LLVM_FALLTHROUGH;
}
case XREF_VALUE_PATH_PIECE:
case XREF_INITIALIZER_PATH_PIECE: {
TypeID TID = 0;
DeclBaseName memberName;
+ Identifier privateDiscriminator;
Optional<swift::CtorInitializerKind> ctorInit;
bool isType = false;
bool inProtocolExt = false;
bool isStatic = false;
switch (recordID) {
case XREF_TYPE_PATH_PIECE: {
- IdentifierID IID;
- XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
+ IdentifierID IID, discriminatorID;
+ XRefTypePathPieceLayout::readRecord(scratch, IID, discriminatorID,
+ inProtocolExt);
memberName = getDeclBaseName(IID);
+ privateDiscriminator = getIdentifier(discriminatorID);
isType = true;
break;
}
@@ -1490,6 +1508,8 @@
}
pathTrace.addValue(memberName);
+ if (!privateDiscriminator.empty())
+ pathTrace.addPrivateDiscriminator(privateDiscriminator);
Type filterTy;
if (!isType) {
@@ -1519,8 +1539,17 @@
getXRefDeclNameForError());
}
- auto members = nominal->lookupDirect(memberName);
- values.append(members.begin(), members.end());
+ if (!privateDiscriminator.empty()) {
+ ModuleDecl *searchModule = M;
+ if (!searchModule)
+ searchModule = nominal->getModuleContext();
+ searchModule->lookupMember(values, nominal, memberName,
+ privateDiscriminator);
+
+ } else {
+ auto members = nominal->lookupDirect(memberName);
+ values.append(members.begin(), members.end());
+ }
filterValues(filterTy, M, genericSig, isType, inProtocolExt, isStatic,
ctorInit, values);
break;
diff --git a/lib/Serialization/DeserializationErrors.h b/lib/Serialization/DeserializationErrors.h
index b5424c3..0703ea4 100644
--- a/lib/Serialization/DeserializationErrors.h
+++ b/lib/Serialization/DeserializationErrors.h
@@ -37,6 +37,7 @@
Accessor,
Extension,
GenericParam,
+ PrivateDiscriminator,
Unknown
};
@@ -55,11 +56,12 @@
: kind(K),
data(llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(value)) {}
- Identifier getAsIdentifier() const {
+ DeclBaseName getAsBaseName() const {
switch (kind) {
case Kind::Value:
case Kind::Operator:
- return getDataAs<Identifier>();
+ case Kind::PrivateDiscriminator:
+ return getDataAs<DeclBaseName>();
case Kind::Type:
case Kind::OperatorFilter:
case Kind::Accessor:
@@ -73,7 +75,7 @@
void print(raw_ostream &os) const {
switch (kind) {
case Kind::Value:
- os << getDataAs<Identifier>();
+ os << getDataAs<DeclBaseName>();
break;
case Kind::Type:
os << "with type " << getDataAs<Type>();
@@ -137,6 +139,9 @@
case Kind::GenericParam:
os << "generic param #" << getDataAs<uintptr_t>();
break;
+ case Kind::PrivateDiscriminator:
+ os << "(in " << getDataAs<Identifier>() << ")";
+ break;
case Kind::Unknown:
os << "unknown xref kind " << getDataAs<uintptr_t>();
break;
@@ -180,17 +185,21 @@
path.push_back({ PathPiece::Kind::GenericParam, index });
}
+ void addPrivateDiscriminator(Identifier name) {
+ path.push_back({ PathPiece::Kind::PrivateDiscriminator, name });
+ }
+
void addUnknown(uintptr_t kind) {
path.push_back({ PathPiece::Kind::Unknown, kind });
}
- Identifier getLastName() const {
+ DeclBaseName getLastName() const {
for (auto &piece : reversed(path)) {
- Identifier result = piece.getAsIdentifier();
+ DeclBaseName result = piece.getAsBaseName();
if (!result.empty())
return result;
}
- return Identifier();
+ return DeclBaseName();
}
void removeLast() {
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 1eca569..a020f9d 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1868,8 +1868,16 @@
auto generic = cast<GenericTypeDecl>(DC);
abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
+
+ Identifier discriminator;
+ if (generic->isOutermostPrivateOrFilePrivateScope()) {
+ auto *containingFile = cast<FileUnit>(generic->getModuleScopeContext());
+ discriminator = containingFile->getDiscriminatorForPrivateValue(generic);
+ }
+
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
addDeclBaseNameRef(generic->getName()),
+ addDeclBaseNameRef(discriminator),
false);
break;
}
@@ -2019,8 +2027,17 @@
bool isProtocolExt = D->getDeclContext()->getAsProtocolExtensionContext();
if (auto type = dyn_cast<TypeDecl>(D)) {
abbrCode = DeclTypeAbbrCodes[XRefTypePathPieceLayout::Code];
+
+ Identifier discriminator;
+ if (type->isOutermostPrivateOrFilePrivateScope()) {
+ auto *containingFile =
+ cast<FileUnit>(type->getDeclContext()->getModuleScopeContext());
+ discriminator = containingFile->getDiscriminatorForPrivateValue(type);
+ }
+
XRefTypePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
addDeclBaseNameRef(type->getName()),
+ addDeclBaseNameRef(discriminator),
isProtocolExt);
return;
}
diff --git a/lib/Syntax/RawSyntax.cpp b/lib/Syntax/RawSyntax.cpp
index 14a22ec..0613fec 100644
--- a/lib/Syntax/RawSyntax.cpp
+++ b/lib/Syntax/RawSyntax.cpp
@@ -30,7 +30,7 @@
return true;
switch(Kind) {
case SyntaxKind::SourceFile:
- case SyntaxKind::TopLevelCodeDecl:
+ case SyntaxKind::CodeBlockItem:
case SyntaxKind::ExpressionStmt:
case SyntaxKind::DeclarationStmt:
return true;
@@ -179,6 +179,8 @@
Trailer.accumulateAbsolutePosition(Pos);
} else {
for (auto &Child : getLayout()) {
+ if (!Child)
+ continue;
auto Result = Child->accumulateAbsolutePosition(Pos);
if (!Ret && Result)
Ret = Result;
@@ -254,6 +256,8 @@
}
} else {
for (auto &Child : getLayout()) {
+ if (!Child)
+ continue;
OS << "\n";
Child->dump(OS, Indent + 1);
}
diff --git a/test/Compatibility/tuple_arguments.swift b/test/Compatibility/tuple_arguments_3.swift
similarity index 98%
rename from test/Compatibility/tuple_arguments.swift
rename to test/Compatibility/tuple_arguments_3.swift
index e5e87d0..ad90c25 100644
--- a/test/Compatibility/tuple_arguments.swift
+++ b/test/Compatibility/tuple_arguments_3.swift
@@ -1,7 +1,8 @@
// RUN: %target-typecheck-verify-swift -swift-version 3
// Tests for tuple argument behavior in Swift 3, which was broken.
-// The Swift 4 test is in test/Constraints/tuple_arguments.swift.
+// The Swift 4 test is in test/Compatibility/tuple_arguments_4.swift.
+// The test for the most recent version is in test/Constraints/tuple_arguments.swift.
// Key:
// - "Crashes in actual Swift 3" -- snippets which crashed in Swift 3.0.1.
@@ -1516,3 +1517,20 @@
takeFn(fn: { (pair: (Int, Int?)) in } )
takeFn { (pair: (Int, Int?)) in }
}
+
+// https://bugs.swift.org/browse/SR-6796
+do {
+ func f(a: (() -> Void)? = nil) {}
+ func log<T>() -> ((T) -> Void)? { return nil }
+
+ f(a: log() as ((()) -> Void)?) // Allow ((()) -> Void)? to be passed in place of (() -> Void)?
+
+ func logNoOptional<T>() -> (T) -> Void { }
+ f(a: logNoOptional() as ((()) -> Void)) // Also allow the optional-injected form.
+
+ func g() {}
+ g(())
+
+ func h(_: ()) {}
+ h()
+}
diff --git a/test/Compatibility/tuple_arguments.swift b/test/Compatibility/tuple_arguments_4.swift
similarity index 68%
copy from test/Compatibility/tuple_arguments.swift
copy to test/Compatibility/tuple_arguments_4.swift
index e5e87d0..1432f0c 100644
--- a/test/Compatibility/tuple_arguments.swift
+++ b/test/Compatibility/tuple_arguments_4.swift
@@ -1,26 +1,10 @@
-// RUN: %target-typecheck-verify-swift -swift-version 3
+// RUN: %target-typecheck-verify-swift -swift-version 4
-// Tests for tuple argument behavior in Swift 3, which was broken.
-// The Swift 4 test is in test/Constraints/tuple_arguments.swift.
-
-// Key:
-// - "Crashes in actual Swift 3" -- snippets which crashed in Swift 3.0.1.
-// These don't have well-defined semantics in Swift 3 mode and don't
-// matter for source compatibility purposes.
-//
-// - "Does not diagnose in Swift 3 mode" -- snippets which failed to typecheck
-// in Swift 3.0.1, but now typecheck. This is fine.
-//
-// - "Diagnoses in Swift 3 mode" -- snippets which typechecked in Swift 3.0.1,
-// but now fail to typecheck. These are bugs in Swift 3 mode that should be
-// fixed.
-//
-// - "Crashes in Swift 3 mode" -- snippets which did not crash Swift 3.0.1,
-// but now crash. These are bugs in Swift 3 mode that should be fixed.
+// See test/Compatibility/tuple_arguments_3.swift for the Swift 3 behavior.
func concrete(_ x: Int) {}
func concreteLabeled(x: Int) {}
-func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 3 {{'concreteTwo' declared here}}
+func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 5 {{'concreteTwo' declared here}}
func concreteTuple(_ x: (Int, Int)) {}
do {
@@ -49,10 +33,10 @@
concrete(c)
concreteTwo(a, b)
- concreteTwo((a, b))
- concreteTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ concreteTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ concreteTwo(d) // expected-error {{missing argument for parameter #2 in call}}
- concreteTuple(a, b)
+ concreteTuple(a, b) // expected-error {{global function 'concreteTuple' expects a single parameter of type '(Int, Int)'}} {{17-17=(}} {{21-21=)}}
concreteTuple((a, b))
concreteTuple(d)
}
@@ -83,7 +67,7 @@
do {
generic(3)
- generic(3, 4)
+ generic(3, 4) // expected-error {{extra argument in call}}
generic((3))
generic((3, 4))
@@ -106,7 +90,7 @@
let d = (a, b)
generic(a)
- generic(a, b)
+ generic(a, b) // expected-error {{extra argument in call}}
generic((a))
generic(c)
generic((a, b))
@@ -128,7 +112,7 @@
var d = (a, b)
generic(a)
- // generic(a, b) // Crashes in actual Swift 3
+ generic(a, b) // expected-error {{extra argument in call}}
generic((a))
generic(c)
generic((a, b))
@@ -144,7 +128,7 @@
}
var function: (Int) -> ()
-var functionTwo: (Int, Int) -> () // expected-note 3 {{'functionTwo' declared here}}
+var functionTwo: (Int, Int) -> () // expected-note 5 {{'functionTwo' declared here}}
var functionTuple: ((Int, Int)) -> ()
do {
@@ -169,10 +153,10 @@
function(c)
functionTwo(a, b)
- functionTwo((a, b))
- functionTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ functionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ functionTwo(d) // expected-error {{missing argument for parameter #2 in call}}
- functionTuple(a, b)
+ functionTuple(a, b) // expected-error {{var 'functionTuple' expects a single parameter of type '(Int, Int)'}} {{17-17=(}} {{21-21=)}}
functionTuple((a, b))
functionTuple(d)
}
@@ -200,7 +184,7 @@
extension Concrete {
func concrete(_ x: Int) {}
- func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 3 {{'concreteTwo' declared here}}
+ func concreteTwo(_ x: Int, _ y: Int) {} // expected-note 5 {{'concreteTwo' declared here}}
func concreteTuple(_ x: (Int, Int)) {}
}
@@ -230,10 +214,10 @@
s.concrete(c)
s.concreteTwo(a, b)
- s.concreteTwo((a, b))
- s.concreteTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ s.concreteTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ s.concreteTwo(d) // expected-error {{missing argument for parameter #2 in call}}
- s.concreteTuple(a, b)
+ s.concreteTuple(a, b) // expected-error {{instance method 'concreteTuple' expects a single parameter of type '(Int, Int)'}} {{19-19=(}} {{23-23=)}}
s.concreteTuple((a, b))
s.concreteTuple(d)
}
@@ -270,7 +254,7 @@
let s = Concrete()
s.generic(3)
- s.generic(3, 4)
+ s.generic(3, 4) // expected-error {{extra argument in call}}
s.generic((3))
s.generic((3, 4))
@@ -295,7 +279,7 @@
let d = (a, b)
s.generic(a)
- s.generic(a, b)
+ s.generic(a, b) // expected-error {{extra argument in call}}
s.generic((a))
s.generic((a, b))
s.generic(d)
@@ -318,7 +302,7 @@
var d = (a, b)
s.generic(a)
- // s.generic(a, b) // Crashes in actual Swift 3
+ s.generic(a, b) // expected-error {{extra argument in call}}
s.generic((a))
s.generic((a, b))
s.generic(d)
@@ -334,7 +318,7 @@
extension Concrete {
mutating func mutatingConcrete(_ x: Int) {}
- mutating func mutatingConcreteTwo(_ x: Int, _ y: Int) {} // expected-note 3 {{'mutatingConcreteTwo' declared here}}
+ mutating func mutatingConcreteTwo(_ x: Int, _ y: Int) {} // expected-note 5 {{'mutatingConcreteTwo' declared here}}
mutating func mutatingConcreteTuple(_ x: (Int, Int)) {}
}
@@ -364,10 +348,10 @@
s.mutatingConcrete(c)
s.mutatingConcreteTwo(a, b)
- s.mutatingConcreteTwo((a, b))
- s.mutatingConcreteTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ s.mutatingConcreteTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ s.mutatingConcreteTwo(d) // expected-error {{missing argument for parameter #2 in call}}
- s.mutatingConcreteTuple(a, b)
+ s.mutatingConcreteTuple(a, b) // expected-error {{instance method 'mutatingConcreteTuple' expects a single parameter of type '(Int, Int)'}} {{27-27=(}} {{31-31=)}}
s.mutatingConcreteTuple((a, b))
s.mutatingConcreteTuple(d)
}
@@ -404,7 +388,7 @@
var s = Concrete()
s.mutatingGeneric(3)
- s.mutatingGeneric(3, 4)
+ s.mutatingGeneric(3, 4) // expected-error {{extra argument in call}}
s.mutatingGeneric((3))
s.mutatingGeneric((3, 4))
@@ -429,7 +413,7 @@
let d = (a, b)
s.mutatingGeneric(a)
- s.mutatingGeneric(a, b)
+ s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
s.mutatingGeneric((a))
s.mutatingGeneric((a, b))
s.mutatingGeneric(d)
@@ -452,7 +436,7 @@
var d = (a, b)
s.mutatingGeneric(a)
- // s.mutatingGeneric(a, b) // Crashes in actual Swift 3
+ s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
s.mutatingGeneric((a))
s.mutatingGeneric((a, b))
s.mutatingGeneric(d)
@@ -498,10 +482,11 @@
s.function(c)
s.functionTwo(a, b)
- s.functionTwo((a, b))
- s.functionTwo(d) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ s.functionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ s.functionTwo(d) // expected-error {{missing argument for parameter #2 in call}}
- s.functionTuple(a, b)
+
+ s.functionTuple(a, b) // expected-error {{single parameter of type '(Int, Int)' is expected in call}} {{19-19=(}} {{23-23=)}}
s.functionTuple((a, b))
s.functionTuple(d)
}
@@ -528,7 +513,7 @@
}
struct InitTwo {
- init(_ x: Int, _ y: Int) {} // expected-note 3 {{'init' declared here}}
+ init(_ x: Int, _ y: Int) {} // expected-note 5 {{'init' declared here}}
}
struct InitTuple {
@@ -556,10 +541,10 @@
let c = (a, b)
_ = InitTwo(a, b)
- _ = InitTwo((a, b))
- _ = InitTwo(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ _ = InitTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ _ = InitTwo(c) // expected-error {{missing argument for parameter #2 in call}}
- _ = InitTuple(a, b)
+ _ = InitTuple(a, b) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}} {{17-17=(}} {{21-21=)}}
_ = InitTuple((a, b))
_ = InitTuple(c)
}
@@ -579,7 +564,7 @@
}
struct SubscriptTwo {
- subscript(_ x: Int, _ y: Int) -> Int { get { return 0 } set { } } // expected-note 3 {{'subscript' declared here}}
+ subscript(_ x: Int, _ y: Int) -> Int { get { return 0 } set { } } // expected-note 5 {{'subscript' declared here}}
}
struct SubscriptTuple {
@@ -598,10 +583,6 @@
let s2 = SubscriptTuple()
_ = s2[3, 4] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{10-10=(}} {{14-14=)}}
_ = s2[(3, 4)]
-
- let s3 = SubscriptLabeledTuple()
- _ = s3[x: 3, 4] // expected-error {{extra argument in call}}
- _ = s3[x: (3, 4)]
}
do {
@@ -611,13 +592,17 @@
let s1 = SubscriptTwo()
_ = s1[a, b]
- _ = s1[(a, b)]
- _ = s1[d]
+ _ = s1[(a, b)] // expected-error {{missing argument for parameter #2 in call}}
+ _ = s1[d] // expected-error {{missing argument for parameter #2 in call}}
let s2 = SubscriptTuple()
- _ = s2[a, b]
+ _ = s2[a, b] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{10-10=(}} {{14-14=)}}
_ = s2[(a, b)]
_ = s2[d]
+
+ let s3 = SubscriptLabeledTuple()
+ _ = s3[x: 3, 4] // expected-error {{extra argument in call}}
+ _ = s3[x: (3, 4)]
}
do {
@@ -638,7 +623,7 @@
}
enum Enum {
- case two(Int, Int) // expected-note 3 {{'two' declared here}}
+ case two(Int, Int) // expected-note 6 {{'two' declared here}}
case tuple((Int, Int))
case labeledTuple(x: (Int, Int))
}
@@ -646,6 +631,7 @@
do {
_ = Enum.two(3, 4)
_ = Enum.two((3, 4)) // expected-error {{missing argument for parameter #2 in call}}
+ _ = Enum.two(3 > 4 ? 3 : 4) // expected-error {{missing argument for parameter #2 in call}}
_ = Enum.tuple(3, 4) // expected-error {{enum element 'tuple' expects a single parameter of type '(Int, Int)'}} {{18-18=(}} {{22-22=)}}
_ = Enum.tuple((3, 4))
@@ -660,10 +646,10 @@
let c = (a, b)
_ = Enum.two(a, b)
- _ = Enum.two((a, b))
- _ = Enum.two(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ _ = Enum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ _ = Enum.two(c) // expected-error {{missing argument for parameter #2 in call}}
- _ = Enum.tuple(a, b)
+ _ = Enum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(Int, Int)'}} {{18-18=(}} {{22-22=)}}
_ = Enum.tuple((a, b))
_ = Enum.tuple(c)
}
@@ -687,7 +673,7 @@
extension Generic {
func generic(_ x: T) {}
func genericLabeled(x: T) {}
- func genericTwo(_ x: T, _ y: T) {} // expected-note 2 {{'genericTwo' declared here}}
+ func genericTwo(_ x: T, _ y: T) {} // expected-note 3 {{'genericTwo' declared here}}
func genericTuple(_ x: (T, T)) {}
}
@@ -728,14 +714,14 @@
s.generic(c)
s.genericTwo(a, b)
- s.genericTwo((a, b))
+ s.genericTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
- s.genericTuple(a, b)
+ s.genericTuple(a, b) // expected-error {{instance method 'genericTuple' expects a single parameter of type '(Double, Double)'}} {{18-18=(}} {{22-22=)}}
s.genericTuple((a, b))
let sTwo = Generic<(Double, Double)>()
- sTwo.generic(a, b)
+ sTwo.generic(a, b) // expected-error {{instance method 'generic' expects a single parameter of type '(Double, Double)'}} {{16-16=(}} {{20-20=)}}
sTwo.generic((a, b))
sTwo.generic(d)
}
@@ -768,7 +754,7 @@
extension Generic {
mutating func mutatingGeneric(_ x: T) {}
mutating func mutatingGenericLabeled(x: T) {}
- mutating func mutatingGenericTwo(_ x: T, _ y: T) {} // expected-note 2 {{'mutatingGenericTwo' declared here}}
+ mutating func mutatingGenericTwo(_ x: T, _ y: T) {} // expected-note 3 {{'mutatingGenericTwo' declared here}}
mutating func mutatingGenericTuple(_ x: (T, T)) {}
}
@@ -809,14 +795,14 @@
s.mutatingGeneric(c)
s.mutatingGenericTwo(a, b)
- s.mutatingGenericTwo((a, b))
+ s.mutatingGenericTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
- s.mutatingGenericTuple(a, b)
+ s.mutatingGenericTuple(a, b) // expected-error {{instance method 'mutatingGenericTuple' expects a single parameter of type '(Double, Double)'}} {{26-26=(}} {{30-30=)}}
s.mutatingGenericTuple((a, b))
var sTwo = Generic<(Double, Double)>()
- sTwo.mutatingGeneric(a, b)
+ sTwo.mutatingGeneric(a, b) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type '(Double, Double)'}} {{24-24=(}} {{28-28=)}}
sTwo.mutatingGeneric((a, b))
sTwo.mutatingGeneric(d)
}
@@ -866,8 +852,8 @@
let sTwo = Generic<(Double, Double)>()
- sTwo.genericFunction(3.0, 4.0)
- sTwo.genericFunction((3.0, 4.0)) // Does not diagnose in Swift 3 mode
+ sTwo.genericFunction(3.0, 4.0) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{32-32=)}}
+ sTwo.genericFunction((3.0, 4.0))
}
do {
@@ -883,16 +869,16 @@
s.genericFunction(c)
s.genericFunctionTwo(a, b)
- s.genericFunctionTwo((a, b))
+ s.genericFunctionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
- s.genericFunctionTuple(a, b)
+ s.genericFunctionTuple(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{26-26=(}} {{30-30=)}}
s.genericFunctionTuple((a, b))
let sTwo = Generic<(Double, Double)>()
- sTwo.genericFunction(a, b)
+ sTwo.genericFunction(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{28-28=)}}
sTwo.genericFunction((a, b))
- sTwo.genericFunction(d) // Does not diagnose in Swift 3 mode
+ sTwo.genericFunction(d)
}
do {
@@ -915,12 +901,12 @@
var sTwo = Generic<(Double, Double)>()
- sTwo.genericFunction(a, b)
- sTwo.genericFunction((a, b)) // Does not diagnose in Swift 3 mode
- sTwo.genericFunction(d) // Does not diagnose in Swift 3 mode
+ sTwo.genericFunction(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{28-28=)}}
+ sTwo.genericFunction((a, b))
+ sTwo.genericFunction(d)
}
-struct GenericInit<T> { // expected-note 2 {{'T' declared as parameter to type 'GenericInit'}}
+struct GenericInit<T> {
init(_ x: T) {}
}
@@ -929,7 +915,7 @@
}
struct GenericInitTwo<T> {
- init(_ x: T, _ y: T) {} // expected-note 8 {{'init' declared here}}
+ init(_ x: T, _ y: T) {} // expected-note 10 {{'init' declared here}}
}
struct GenericInitTuple<T> {
@@ -941,7 +927,7 @@
}
do {
- _ = GenericInit(3, 4)
+ _ = GenericInit(3, 4) // expected-error {{extra argument in call}}
_ = GenericInit((3, 4))
_ = GenericInitLabeled(x: 3, 4) // expected-error {{extra argument in call}}
@@ -958,8 +944,8 @@
}
do {
- _ = GenericInit<(Int, Int)>(3, 4)
- _ = GenericInit<(Int, Int)>((3, 4)) // expected-error {{expression type 'GenericInit<(Int, Int)>' is ambiguous without more context}}
+ _ = GenericInit<(Int, Int)>(3, 4) // expected-error {{extra argument in call}}
+ _ = GenericInit<(Int, Int)>((3, 4))
_ = GenericInitLabeled<(Int, Int)>(x: 3, 4) // expected-error {{extra argument in call}}
_ = GenericInitLabeled<(Int, Int)>(x: (3, 4))
@@ -979,7 +965,7 @@
let b = 4
let c = (a, b)
- _ = GenericInit(a, b)
+ _ = GenericInit(a, b) // expected-error {{extra argument in call}}
_ = GenericInit((a, b))
_ = GenericInit(c)
@@ -997,15 +983,15 @@
let b = 4
let c = (a, b)
- _ = GenericInit<(Int, Int)>(a, b)
+ _ = GenericInit<(Int, Int)>(a, b) // expected-error {{extra argument in call}}
_ = GenericInit<(Int, Int)>((a, b))
_ = GenericInit<(Int, Int)>(c)
_ = GenericInitTwo<Int>(a, b)
- _ = GenericInitTwo<Int>((a, b)) // Does not diagnose in Swift 3 mode
- _ = GenericInitTwo<Int>(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ _ = GenericInitTwo<Int>((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ _ = GenericInitTwo<Int>(c) // expected-error {{missing argument for parameter #2 in call}}
- _ = GenericInitTuple<Int>(a, b) // Does not diagnose in Swift 3 mode
+ _ = GenericInitTuple<Int>(a, b) // expected-error {{initializer expects a single parameter of type '(T, T)'}} {{29-29=(}} {{33-33=)}}
_ = GenericInitTuple<Int>((a, b))
_ = GenericInitTuple<Int>(c)
}
@@ -1016,8 +1002,8 @@
var c = (a, b)
_ = GenericInit(a, b) // expected-error {{extra argument in call}}
- _ = GenericInit((a, b)) // expected-error {{generic parameter 'T' could not be inferred}} // expected-note {{explicitly specify the generic arguments to fix this issue}}
- _ = GenericInit(c) // expected-error {{generic parameter 'T' could not be inferred}} // expected-note {{explicitly specify the generic arguments to fix this issue}}
+ _ = GenericInit((a, b))
+ _ = GenericInit(c)
_ = GenericInitTwo(a, b)
_ = GenericInitTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1033,9 +1019,9 @@
var b = 4 // expected-warning {{variable 'b' was never mutated; consider changing to 'let' constant}}
var c = (a, b) // expected-warning {{variable 'c' was never mutated; consider changing to 'let' constant}}
- // _ = GenericInit<(Int, Int)>(a, b) // Crashes in Swift 3
- _ = GenericInit<(Int, Int)>((a, b)) // expected-error {{expression type 'GenericInit<(Int, Int)>' is ambiguous without more context}}
- _ = GenericInit<(Int, Int)>(c) // expected-error {{expression type 'GenericInit<(Int, Int)>' is ambiguous without more context}}
+ _ = GenericInit<(Int, Int)>(a, b) // expected-error {{extra argument in call}}
+ _ = GenericInit<(Int, Int)>((a, b))
+ _ = GenericInit<(Int, Int)>(c)
_ = GenericInitTwo<Int>(a, b)
_ = GenericInitTwo<Int>((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1047,8 +1033,7 @@
}
struct GenericSubscript<T> {
- // TODO: Restore regressed diagnostics rdar://problem/31724211
- subscript(_ x: T) -> Int { get { return 0 } set { } } // expected-note* {{}}
+ subscript(_ x: T) -> Int { get { return 0 } set { } }
}
struct GenericSubscriptLabeled<T> {
@@ -1056,22 +1041,21 @@
}
struct GenericSubscriptTwo<T> {
- subscript(_ x: T, _ y: T) -> Int { get { return 0 } set { } } // expected-note 3 {{'subscript' declared here}}
-}
-
-struct GenericSubscriptTuple<T> {
- subscript(_ x: (T, T)) -> Int { get { return 0 } set { } }
+ subscript(_ x: T, _ y: T) -> Int { get { return 0 } set { } } // expected-note 5 {{'subscript' declared here}}
}
struct GenericSubscriptLabeledTuple<T> {
subscript(x x: (T, T)) -> Int { get { return 0 } set { } }
}
+struct GenericSubscriptTuple<T> {
+ subscript(_ x: (T, T)) -> Int { get { return 0 } set { } }
+}
+
do {
let s1 = GenericSubscript<(Double, Double)>()
- _ = s1[3.0, 4.0]
- // TODO: Restore regressed diagnostics rdar://problem/31724211
- _ = s1[(3.0, 4.0)] // expected-error {{}}
+ _ = s1[3.0, 4.0] // expected-error {{extra argument in call}}
+ _ = s1[(3.0, 4.0)]
let s1a = GenericSubscriptLabeled<(Double, Double)>()
_ = s1a [x: 3.0, 4.0] // expected-error {{extra argument in call}}
@@ -1096,17 +1080,17 @@
let d = (a, b)
let s1 = GenericSubscript<(Double, Double)>()
- _ = s1[a, b]
+ _ = s1[a, b] // expected-error {{extra argument in call}}
_ = s1[(a, b)]
_ = s1[d]
let s2 = GenericSubscriptTwo<Double>()
_ = s2[a, b]
- _ = s2[(a, b)] // Does not diagnose in Swift 3 mode
- _ = s2[d] // Does not diagnose in Swift 3 mode
+ _ = s2[(a, b)] // expected-error {{missing argument for parameter #2 in call}}
+ _ = s2[d] // expected-error {{missing argument for parameter #2 in call}}
let s3 = GenericSubscriptTuple<Double>()
- _ = s3[a, b] // Does not diagnose in Swift 3 mode
+ _ = s3[a, b] // expected-error {{subscript expects a single parameter of type '(T, T)'}} {{10-10=(}} {{14-14=)}}
_ = s3[(a, b)]
_ = s3[d]
}
@@ -1118,11 +1102,9 @@
var d = (a, b) // e/xpected-warning {{variable 'd' was never mutated; consider changing to 'let' constant}}
var s1 = GenericSubscript<(Double, Double)>()
- _ = s1[a, b]
- // TODO: Restore regressed diagnostics rdar://problem/31724211
- // These two lines give different regressed behavior in S3 and S4 mode
- // _ = s1[(a, b)] // e/xpected-error {{expression type '@lvalue Int' is ambiguous without more context}}
- // _ = s1[d] // e/xpected-error {{expression type '@lvalue Int' is ambiguous without more context}}
+ _ = s1[a, b] // expected-error {{extra argument in call}}
+ _ = s1[(a, b)]
+ _ = s1[d]
var s2 = GenericSubscriptTwo<Double>()
_ = s2[a, b]
@@ -1138,12 +1120,12 @@
enum GenericEnum<T> {
case one(T)
case labeled(x: T)
- case two(T, T) // expected-note 8 {{'two' declared here}}
+ case two(T, T) // expected-note 10 {{'two' declared here}}
case tuple((T, T))
}
do {
- _ = GenericEnum.one(3, 4)
+ _ = GenericEnum.one(3, 4) // expected-error {{extra argument in call}}
_ = GenericEnum.one((3, 4))
_ = GenericEnum.labeled(x: 3, 4) // expected-error {{extra argument in call}}
@@ -1159,8 +1141,8 @@
}
do {
- _ = GenericEnum<(Int, Int)>.one(3, 4)
- _ = GenericEnum<(Int, Int)>.one((3, 4)) // Does not diagnose in Swift 3 mode
+ _ = GenericEnum<(Int, Int)>.one(3, 4) // expected-error {{enum element 'one' expects a single parameter of type '(Int, Int)'}} {{35-35=(}} {{39-39=)}}
+ _ = GenericEnum<(Int, Int)>.one((3, 4))
_ = GenericEnum<(Int, Int)>.labeled(x: 3, 4) // expected-error {{extra argument in call}}
_ = GenericEnum<(Int, Int)>.labeled(x: (3, 4))
@@ -1179,7 +1161,7 @@
let b = 4
let c = (a, b)
- _ = GenericEnum.one(a, b)
+ _ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
_ = GenericEnum.one((a, b))
_ = GenericEnum.one(c)
@@ -1197,15 +1179,15 @@
let b = 4
let c = (a, b)
- _ = GenericEnum<(Int, Int)>.one(a, b)
+ _ = GenericEnum<(Int, Int)>.one(a, b) // expected-error {{enum element 'one' expects a single parameter of type '(Int, Int)'}} {{35-35=(}} {{39-39=)}}
_ = GenericEnum<(Int, Int)>.one((a, b))
_ = GenericEnum<(Int, Int)>.one(c)
_ = GenericEnum<Int>.two(a, b)
- _ = GenericEnum<Int>.two((a, b))
- _ = GenericEnum<Int>.two(c) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
+ _ = GenericEnum<Int>.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
+ _ = GenericEnum<Int>.two(c) // expected-error {{missing argument for parameter #2 in call}}
- _ = GenericEnum<Int>.tuple(a, b)
+ _ = GenericEnum<Int>.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(Int, Int)'}} {{30-30=(}} {{34-34=)}}
_ = GenericEnum<Int>.tuple((a, b))
_ = GenericEnum<Int>.tuple(c)
}
@@ -1215,9 +1197,9 @@
var b = 4
var c = (a, b)
- // _ = GenericEnum.one(a, b) // Crashes in actual Swift 3
- _ = GenericEnum.one((a, b)) // Does not diagnose in Swift 3 mode
- _ = GenericEnum.one(c) // Does not diagnose in Swift 3 mode
+ _ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
+ _ = GenericEnum.one((a, b))
+ _ = GenericEnum.one(c)
_ = GenericEnum.two(a, b)
_ = GenericEnum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1233,9 +1215,9 @@
var b = 4
var c = (a, b)
- // _ = GenericEnum<(Int, Int)>.one(a, b) // Crashes in actual Swift 3
- _ = GenericEnum<(Int, Int)>.one((a, b)) // Does not diagnose in Swift 3 mode
- _ = GenericEnum<(Int, Int)>.one(c) // Does not diagnose in Swift 3 mode
+ _ = GenericEnum<(Int, Int)>.one(a, b) // expected-error {{enum element 'one' expects a single parameter of type '(Int, Int)'}} {{35-35=(}} {{39-39=)}}
+ _ = GenericEnum<(Int, Int)>.one((a, b))
+ _ = GenericEnum<(Int, Int)>.one(c)
_ = GenericEnum<Int>.two(a, b)
_ = GenericEnum<Int>.two((a, b)) // expected-error {{missing argument for parameter #2 in call}}
@@ -1253,7 +1235,7 @@
extension Protocol {
func requirement(_ x: Element) {}
func requirementLabeled(x: Element) {}
- func requirementTwo(_ x: Element, _ y: Element) {} // expected-note 2 {{'requirementTwo' declared here}}
+ func requirementTwo(_ x: Element, _ y: Element) {} // expected-note 3 {{'requirementTwo' declared here}}
func requirementTuple(_ x: (Element, Element)) {}
}
@@ -1266,7 +1248,7 @@
s.requirement(3.0)
s.requirement((3.0))
-
+
s.requirementLabeled(x: 3.0)
s.requirementLabeled(x: (3.0))
@@ -1298,14 +1280,14 @@
s.requirement(c)
s.requirementTwo(a, b)
- s.requirementTwo((a, b)) // Does not diagnose in Swift 3 mode
+ s.requirementTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
- s.requirementTuple(a, b) // Does not diagnose in Swift 3 mode
+ s.requirementTuple(a, b) // expected-error {{instance method 'requirementTuple' expects a single parameter of type '(Double, Double)'}} {{22-22=(}} {{26-26=)}}
s.requirementTuple((a, b))
let sTwo = GenericConforms<(Double, Double)>()
- sTwo.requirement(a, b)
+ sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{24-24=)}}
sTwo.requirement((a, b))
sTwo.requirement(d)
}
@@ -1347,9 +1329,9 @@
s.takesClosure({ x in })
s.takesClosure({ (x: Double) in })
- s.takesClosureTwo({ _ = $0 })
- s.takesClosureTwo({ x in })
- s.takesClosureTwo({ (x: (Double, Double)) in })
+ s.takesClosureTwo({ _ = $0 }) // expected-error {{contextual closure type '(Double, Double) -> ()' expects 2 arguments, but 1 was used in closure body}}
+ s.takesClosureTwo({ x in }) // expected-error {{contextual closure type '(Double, Double) -> ()' expects 2 arguments, but 1 was used in closure body}}
+ s.takesClosureTwo({ (x: (Double, Double)) in }) // expected-error {{contextual closure type '(Double, Double) -> ()' expects 2 arguments, but 1 was used in closure body}}
s.takesClosureTwo({ _ = $0; _ = $1 })
s.takesClosureTwo({ (x, y) in })
s.takesClosureTwo({ (x: Double, y:Double) in })
@@ -1375,12 +1357,12 @@
let _: ((Int, Int)) -> () = { _ = ($0.0, $0.1) }
let _: ((Int, Int)) -> () = { t in _ = (t.0, t.1) }
- let _: ((Int, Int)) -> () = { _ = ($0, $1) }
- let _: ((Int, Int)) -> () = { t, u in _ = (t, u) }
+ let _: ((Int, Int)) -> () = { _ = ($0, $1) } // expected-error {{closure tuple parameter '(Int, Int)' does not support destructuring}}
+ let _: ((Int, Int)) -> () = { t, u in _ = (t, u) } // expected-error {{closure tuple parameter '(Int, Int)' does not support destructuring}} {{33-37=(arg)}} {{41-41=let (t, u) = arg; }}
- let _: (Int, Int) -> () = { _ = $0 }
- let _: (Int, Int) -> () = { _ = ($0.0, $0.1) }
- let _: (Int, Int) -> () = { t in _ = (t.0, t.1) }
+ let _: (Int, Int) -> () = { _ = $0 } // expected-error {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}}
+ let _: (Int, Int) -> () = { _ = ($0.0, $0.1) } // expected-error {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}}
+ let _: (Int, Int) -> () = { t in _ = (t.0, t.1) } // expected-error {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}}
let _: (Int, Int) -> () = { _ = ($0, $1) }
let _: (Int, Int) -> () = { t, u in _ = (t, u) }
@@ -1398,19 +1380,17 @@
let fn: (Any) -> () = { _ in }
fn(123)
- fn(data: 123)
+ fn(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
takesAny(123)
- takesAny(data: 123)
+ takesAny(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
_ = HasAnyCase.any(123)
- _ = HasAnyCase.any(data: 123)
+ _ = HasAnyCase.any(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
}
// rdar://problem/29739905 - protocol extension methods on Array had
// ParenType sugar stripped off the element type
-typealias BoolPair = (Bool, Bool)
-
func processArrayOfFunctions(f1: [((Bool, Bool)) -> ()],
f2: [(Bool, Bool) -> ()],
c: Bool) {
@@ -1419,24 +1399,27 @@
f1.forEach { block in
block(p)
block((c, c))
- block(c, c)
+ block(c, c) // expected-error {{parameter 'block' expects a single parameter of type '(Bool, Bool)'}} {{11-11=(}} {{15-15=)}}
}
f2.forEach { block in
- block(p) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
- block((c, c))
+ // expected-note@-1 2{{'block' declared here}}
+ block(p) // expected-error {{missing argument for parameter #2 in call}}
+ block((c, c)) // expected-error {{missing argument for parameter #2 in call}}
block(c, c)
}
f2.forEach { (block: ((Bool, Bool)) -> ()) in
+ // expected-error@-1 {{cannot convert value of type '(((Bool, Bool)) -> ()) -> ()' to expected argument type '((Bool, Bool) -> ()) -> Void}}
block(p)
block((c, c))
block(c, c)
}
f2.forEach { (block: (Bool, Bool) -> ()) in
- block(p) // expected-error {{passing 2 arguments to a callee as a single tuple value has been removed in Swift 3}}
- block((c, c))
+ // expected-note@-1 2{{'block' declared here}}
+ block(p) // expected-error {{missing argument for parameter #2 in call}}
+ block((c, c)) // expected-error {{missing argument for parameter #2 in call}}
block(c, c)
}
}
@@ -1449,7 +1432,7 @@
}
-// SR-4378 -- FIXME -- this should type check, it used to work in Swift 3.0
+// SR-4378
final public class MutableProperty<Value> {
public init(_ initialValue: Value) {}
@@ -1460,38 +1443,190 @@
}
let pages1: MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)> = MutableProperty((
- // expected-error@-1 {{expression type 'MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)>' is ambiguous without more context}}
data: .notLoaded,
totalCount: 0
))
let pages2: MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)> = MutableProperty((
- // expected-error@-1 {{cannot convert value of type 'MutableProperty<(data: DataSourcePage<_>, totalCount: Int)>' to specified type 'MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)>'}}
data: DataSourcePage.notLoaded,
totalCount: 0
))
let pages3: MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)> = MutableProperty((
- // expected-error@-1 {{expression type 'MutableProperty<(data: DataSourcePage<Int>, totalCount: Int)>' is ambiguous without more context}}
data: DataSourcePage<Int>.notLoaded,
totalCount: 0
))
-// rdar://problem/32301091 - Make sure that in Swift 3 mode following expressions still compile just fine
+// SR-4745
+let sr4745 = [1, 2]
+let _ = sr4745.enumerated().map { (count, element) in "\(count): \(element)" }
+
+// SR-4738
+
+let sr4738 = (1, (2, 3))
+[sr4738].map { (x, (y, z)) -> Int in x + y + z } // expected-error {{use of undeclared type 'y'}}
+// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{20-26=arg1}} {{38-38=let (y, z) = arg1; }}
+
+// rdar://problem/31892961
+let r31892961_1 = [1: 1, 2: 2]
+r31892961_1.forEach { (k, v) in print(k + v) }
+
+let r31892961_2 = [1, 2, 3]
+let _: [Int] = r31892961_2.enumerated().map { ((index, val)) in
+ // expected-error@-1 {{closure tuple parameter does not support destructuring}} {{48-60=arg0}} {{3-3=\n let (index, val) = arg0\n }}
+ // expected-error@-2 {{use of undeclared type 'index'}}
+ val + 1
+}
+
+let r31892961_3 = (x: 1, y: 42)
+_ = [r31892961_3].map { (x: Int, y: Int) in x + y }
+
+_ = [r31892961_3].map { (x, y: Int) in x + y }
+
+let r31892961_4 = (1, 2)
+_ = [r31892961_4].map { x, y in x + y }
+
+let r31892961_5 = (x: 1, (y: 2, (w: 3, z: 4)))
+[r31892961_5].map { (x: Int, (y: Int, (w: Int, z: Int))) in x + y }
+// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{30-56=arg1}} {{61-61=let (y, (w, z)) = arg1; }}
+
+let r31892961_6 = (x: 1, (y: 2, z: 4))
+[r31892961_6].map { (x: Int, (y: Int, z: Int)) in x + y }
+// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{30-46=arg1}} {{51-51=let (y, z) = arg1; }}
+
+// rdar://problem/32214649 -- these regressed in Swift 4 mode
+// with SE-0110 because of a problem in associated type inference
+
+func r32214649_1<X,Y>(_ a: [X], _ f: (X)->Y) -> [Y] {
+ return a.map(f)
+}
+
+func r32214649_2<X>(_ a: [X], _ f: (X) -> Bool) -> [X] {
+ return a.filter(f)
+}
+
+func r32214649_3<X>(_ a: [X]) -> [X] {
+ return a.filter { _ in return true }
+}
+
+// rdar://problem/32301091 - [SE-0110] causes errors when passing a closure with a single underscore to a block accepting multiple parameters
func rdar32301091_1(_ :((Int, Int) -> ())!) {}
-rdar32301091_1 { _ in } // Ok in Swift 3
+rdar32301091_1 { _ in }
+// expected-error@-1 {{cannot convert value of type '(_) -> ()' to expected argument type '((Int, Int) -> ())?'}}
func rdar32301091_2(_ :(Int, Int) -> ()) {}
-rdar32301091_2 { _ in } // Ok in Swift 3
+rdar32301091_2 { _ in }
+// expected-error@-1 {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}} {{19-19=,_ }}
+rdar32301091_2 { x in }
+// expected-error@-1 {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}} {{19-19=,<#arg#> }}
-// rdar://problem/35198459 - source-compat-suite failure: Moya (toType->hasUnresolvedType() && "Should have handled this above")
+func rdar32875953() {
+ let myDictionary = ["hi":1]
+
+ myDictionary.forEach {
+ print("\($0) -> \($1)")
+ }
+
+ myDictionary.forEach { key, value in
+ print("\(key) -> \(value)")
+ }
+
+ myDictionary.forEach { (key, value) in
+ print("\(key) -> \(value)")
+ }
+
+ let array1 = [1]
+ let array2 = [2]
+
+ _ = zip(array1, array2).map(+)
+}
+
+struct SR_5199 {}
+extension Sequence where Iterator.Element == (key: String, value: String?) {
+ func f() -> [SR_5199] {
+ return self.map { (key, value) in
+ SR_5199() // Ok
+ }
+ }
+}
+
+func rdar33043106(_ records: [(Int)], _ other: [((Int))]) -> [Int] {
+ let x: [Int] = records.map { _ in
+ let i = 1
+ return i
+ }
+ let y: [Int] = other.map { _ in
+ let i = 1
+ return i
+ }
+
+ return x + y
+}
+
+func itsFalse(_: Int) -> Bool? {
+ return false
+}
+
+func rdar33159366(s: AnySequence<Int>) {
+ _ = s.compactMap(itsFalse)
+ let a = Array(s)
+ _ = a.compactMap(itsFalse)
+}
+
+func sr5429<T>(t: T) {
+ _ = AnySequence([t]).first(where: { (t: T) in true })
+}
+
+extension Concrete {
+ typealias T = (Int, Int)
+ typealias F = (T) -> ()
+ func opt1(_ fn: (((Int, Int)) -> ())?) {}
+ func opt2(_ fn: (((Int, Int)) -> ())??) {}
+ func opt3(_ fn: (((Int, Int)) -> ())???) {}
+ func optAliasT(_ fn: ((T) -> ())?) {}
+ func optAliasF(_ fn: F?) {}
+}
+
+extension Generic {
+ typealias F = (T) -> ()
+ func opt1(_ fn: (((Int, Int)) -> ())?) {}
+ func opt2(_ fn: (((Int, Int)) -> ())??) {}
+ func opt3(_ fn: (((Int, Int)) -> ())???) {}
+ func optAliasT(_ fn: ((T) -> ())?) {}
+ func optAliasF(_ fn: F?) {}
+}
+
+func rdar33239714() {
+ Concrete().opt1 { x, y in }
+ Concrete().opt1 { (x, y) in }
+ Concrete().opt2 { x, y in }
+ Concrete().opt2 { (x, y) in }
+ Concrete().opt3 { x, y in }
+ Concrete().opt3 { (x, y) in }
+ Concrete().optAliasT { x, y in }
+ Concrete().optAliasT { (x, y) in }
+ Concrete().optAliasF { x, y in }
+ Concrete().optAliasF { (x, y) in }
+ Generic<(Int, Int)>().opt1 { x, y in }
+ Generic<(Int, Int)>().opt1 { (x, y) in }
+ Generic<(Int, Int)>().opt2 { x, y in }
+ Generic<(Int, Int)>().opt2 { (x, y) in }
+ Generic<(Int, Int)>().opt3 { x, y in }
+ Generic<(Int, Int)>().opt3 { (x, y) in }
+ Generic<(Int, Int)>().optAliasT { x, y in }
+ Generic<(Int, Int)>().optAliasT { (x, y) in }
+ Generic<(Int, Int)>().optAliasF { x, y in }
+ Generic<(Int, Int)>().optAliasF { (x, y) in }
+}
+
+// rdar://problem/35198459 - source-compat-suite failure: Moya (toType->hasUnresolvedType() && "Should have handled this above"
do {
func foo(_: (() -> Void)?) {}
func bar() -> ((()) -> Void)? { return nil }
- foo(bar()) // OK in Swift 3 mode
+ foo(bar()) // Allow ((()) -> Void)? to be passed in place of (() -> Void)? for -swift-version 4 but not later.
}
// https://bugs.swift.org/browse/SR-6509
@@ -1506,13 +1641,32 @@
where Wrapped == (Value) -> Result {
return value.apply(self)
}
-}
+}
// https://bugs.swift.org/browse/SR-6837
do {
func takeFn(fn: (_ i: Int, _ j: Int?) -> ()) {}
func takePair(_ pair: (Int, Int?)) {}
- takeFn(fn: takePair)
- takeFn(fn: { (pair: (Int, Int?)) in } )
- takeFn { (pair: (Int, Int?)) in }
+ takeFn(fn: takePair) // Allow for -swift-version 4, but not later
+ takeFn(fn: { (pair: (Int, Int?)) in } ) // Disallow for -swift-version 4 and later
+ // expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
+ takeFn { (pair: (Int, Int?)) in } // Disallow for -swift-version 4 and later
+ // expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
+}
+
+// https://bugs.swift.org/browse/SR-6796
+do {
+ func f(a: (() -> Void)? = nil) {}
+ func log<T>() -> ((T) -> Void)? { return nil }
+
+ f(a: log() as ((()) -> Void)?) // Allow ((()) -> Void)? to be passed in place of (() -> Void)? for -swift-version 4 but not later.
+
+ func logNoOptional<T>() -> (T) -> Void { }
+ f(a: logNoOptional() as ((()) -> Void)) // Also allow the optional-injected form.
+
+ func g() {}
+ g(()) // expected-error {{argument passed to call that takes no arguments}}
+
+ func h(_: ()) {} // expected-note {{'h' declared here}}
+ h() // expected-error {{missing argument for parameter #1 in call}}
}
diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift
index 61429a7..9db51b7 100644
--- a/test/Constraints/tuple_arguments.swift
+++ b/test/Constraints/tuple_arguments.swift
@@ -1,6 +1,7 @@
-// RUN: %target-typecheck-verify-swift -swift-version 4
+// RUN: %target-typecheck-verify-swift -swift-version 5
-// See test/Compatibility/tuple_arguments.swift for the Swift 3 behavior.
+// See test/Compatibility/tuple_arguments_3.swift for the Swift 3 behavior.
+// See test/Compatibility/tuple_arguments_4.swift for the Swift 4 behavior.
func concrete(_ x: Int) {}
func concreteLabeled(x: Int) {}
@@ -1643,14 +1644,30 @@
}
}
-
// https://bugs.swift.org/browse/SR-6837
do {
func takeFn(fn: (_ i: Int, _ j: Int?) -> ()) {}
func takePair(_ pair: (Int, Int?)) {}
- takeFn(fn: takePair) // Allow for -swift-version 4, but not later
+ takeFn(fn: takePair) // expected-error {{cannot convert value of type '((Int, Int?)) -> ()' to expected argument type '(Int, Int?) -> ()'}}
takeFn(fn: { (pair: (Int, Int?)) in } ) // Disallow for -swift-version 4 and later
// expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
takeFn { (pair: (Int, Int?)) in } // Disallow for -swift-version 4 and later
// expected-error@-1 {{contextual closure type '(Int, Int?) -> ()' expects 2 arguments, but 1 was used in closure body}}
}
+
+// https://bugs.swift.org/browse/SR-6796
+do {
+ func f(a: (() -> Void)? = nil) {}
+ func log<T>() -> ((T) -> Void)? { return nil }
+
+ f(a: log() as ((()) -> Void)?) // expected-error {{cannot convert value of type '((()) -> Void)?' to expected argument type '(() -> Void)?'}}
+
+ func logNoOptional<T>() -> (T) -> Void { }
+ f(a: logNoOptional() as ((()) -> Void)) // expected-error {{cannot convert value of type '(()) -> Void' to expected argument type '(() -> Void)?'}}
+
+ func g() {}
+ g(()) // expected-error {{argument passed to call that takes no arguments}}
+
+ func h(_: ()) {} // expected-note {{'h' declared here}}
+ h() // expected-error {{missing argument for parameter #1 in call}}
+}
diff --git a/test/SILGen/generic_casts.swift b/test/SILGen/generic_casts.swift
index a686c3a..6fe1f40 100644
--- a/test/SILGen/generic_casts.swift
+++ b/test/SILGen/generic_casts.swift
@@ -217,7 +217,74 @@
}
// CHECK-LABEL: sil hidden @$S13generic_casts27optional_anyobject_to_classyAA1CCSgyXlSgF
-// CHECK: checked_cast_br {{%.*}} : $AnyObject to $C
func optional_anyobject_to_class(_ p: AnyObject?) -> C? {
return p as? C
+ // CHECK: checked_cast_br {{%.*}} : $AnyObject to $C
}
+
+// The below tests are to ensure we don't dig into an optional operand when
+// casting to a non-class archetype, as it could dynamically be an optional type.
+
+// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_opaque_archetype<T>(_ x: Any?) -> T {
+ return x as! T
+ // CHECK: bb0([[RET:%.*]] : @trivial $*T, {{%.*}} : @trivial $*Optional<Any>):
+ // CHECK: unconditional_checked_cast_addr Optional<Any> in {{%.*}} : $*Optional<Any> to T in [[RET]] : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts46optional_any_conditionally_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_opaque_archetype<T>(_ x: Any?) -> T? {
+ return x as? T
+ // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_is_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
+ return x is T
+ // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to T in {{%.*}} : $*T
+}
+
+// But we can dig into at most one layer of the operand if it's
+// an optional archetype...
+
+// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_optional_opaque_archetype<T>(_ x: Any?) -> T? {
+ return x as! T?
+ // CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts030optional_any_conditionally_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_optional_opaque_archetype<T>(_ x: Any?) -> T?? {
+ return x as? T?
+ // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_is_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_optional_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
+ return x is T?
+ // Because the levels of optional are the same, 'is' doesn't transform into an 'as?',
+ // so we just cast directly without digging into the optional operand.
+ // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to Optional<T> in {{%.*}} : $*Optional<T>
+}
+
+// And we can dig into the operand when casting to a class archetype, as it
+// cannot dynamically be optional...
+
+// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_class_archetype<T : AnyObject>(_ x: Any?) -> T {
+ return x as! T
+ // CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts45optional_any_conditionally_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_class_archetype<T : AnyObject>(_ x: Any?) -> T? {
+ return x as? T
+ // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_is_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_class_archetype<T : AnyObject>(_ x: Any?, _: T) -> Bool {
+ return x is T
+ // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
diff --git a/test/Serialization/Inputs/xref-private-type/Lib.swift b/test/Serialization/Inputs/xref-private-type/Lib.swift
new file mode 100644
index 0000000..4292ce3
--- /dev/null
+++ b/test/Serialization/Inputs/xref-private-type/Lib.swift
@@ -0,0 +1,8 @@
+import LibCore
+
+public let lazyFoo = Foo()
+public func testFoo(_: Foo = lazyFoo) {}
+public let lazyBar = Bar()
+public func testBar(_: Bar = lazyBar) {}
+public let lazyBaz = Baz()
+public func testBaz(_: Baz = lazyBaz) {}
diff --git a/test/Serialization/Inputs/xref-private-type/LibCore.swift b/test/Serialization/Inputs/xref-private-type/LibCore.swift
new file mode 100644
index 0000000..032dbdf
--- /dev/null
+++ b/test/Serialization/Inputs/xref-private-type/LibCore.swift
@@ -0,0 +1,24 @@
+private class TopLevelInternalClass {}
+public struct Foo {
+ private var ref: TopLevelInternalClass
+
+ public init() { self.ref = .init() }
+}
+
+public struct Bar {
+ private class NestedInternalClass {}
+
+ private var ref: NestedInternalClass
+
+ public init() { self.ref = .init() }
+}
+
+public struct Baz {
+ fileprivate class NestedInternalClass {
+ fileprivate class DoublyNestedInternalClass {}
+ }
+
+ private var ref: NestedInternalClass.DoublyNestedInternalClass
+
+ public init() { self.ref = .init() }
+}
diff --git a/test/Serialization/xref-private-type.swift b/test/Serialization/xref-private-type.swift
new file mode 100755
index 0000000..2ad6c92
--- /dev/null
+++ b/test/Serialization/xref-private-type.swift
@@ -0,0 +1,51 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift -swift-version 4 -O -force-single-frontend-invocation -emit-module-path %t/LibCore.swiftmodule %S/Inputs/xref-private-type/LibCore.swift
+// RUN: %target-build-swift -swift-version 4 -O -I %t -force-single-frontend-invocation -emit-module-path %t/Lib.swiftmodule %S/Inputs/xref-private-type/Lib.swift
+// RUN: %target-build-swift -swift-version 4 -O -I %t -emit-sil %s | %FileCheck %s
+
+import Lib
+
+// CHECK: sil{{.*}} @[[TESTSR6874:[^ ]+10testSR6874[^ ]+]] :
+func testSR6874() {
+ // The important lines in this test are the strong_retains, which refer to
+ // private types defined in LibCore. Normally we shouldn't have references to
+ // non-public declarations in inlinable code, but because SIL passes can break
+ // apart non-resilient structs and enums we can end up in that situation.
+ // Worse, this can happen *across module boundaries.*
+ //
+ // In this test, the addressor for each global defined in Lib ends up
+ // referencing private types defined in LibCore. Using those globals in
+ // default argument position leads to the addressor getting inlined into
+ // calling code in Swift 4 and later. This results in an attempt to not just
+ // reference a private type, but to *resolve a cross-reference to a private
+ // type.*
+ //
+ // This is the situation in SR-6874 (simplified). I'm not sure of a simpler
+ // way to reliably trigger the issue. But if this test breaks, please try to
+ // find one.
+ //
+ // (We may want to revisit this whole thing later, as it violates the model.
+ // But it's also useful for performance in non-resilient code.)
+
+ // CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyFoo
+ // CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Foo
+ // CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Foo, #Foo.ref
+ // CHECK: strong_retain [[REF]] : $TopLevelInternalClass
+ // CHECK: apply {{%.+}}([[LOADED]])
+ testFoo()
+
+ // CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyBar
+ // CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Bar
+ // CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Bar, #Bar.ref
+ // CHECK: strong_retain [[REF]] : $Bar.NestedInternalClass
+ // CHECK: apply {{%.+}}([[LOADED]])
+ testBar()
+
+ // CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyBaz
+ // CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Baz
+ // CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Baz, #Baz.ref
+ // CHECK: strong_retain [[REF]] : $Baz.NestedInternalClass.DoublyNestedInternalClass
+ // CHECK: apply {{%.+}}([[LOADED]])
+ testBaz()
+} // CHECK: end sil function '[[TESTSR6874]]'
+
diff --git a/test/SwiftSyntax/SyntaxChildren.swift b/test/SwiftSyntax/SyntaxChildren.swift
index be5473a..8e4cee9 100644
--- a/test/SwiftSyntax/SyntaxChildren.swift
+++ b/test/SwiftSyntax/SyntaxChildren.swift
@@ -28,25 +28,21 @@
SyntaxChildrenAPI.test("IterateWithAllPresent") {
let returnStmt = SyntaxFactory.makeReturnStmt(
returnKeyword: SyntaxFactory.makeReturnKeyword(),
- expression: SyntaxFactory.makeBlankUnknownExpr(),
- semicolon: SyntaxFactory.makeSemicolonToken())
+ expression: SyntaxFactory.makeBlankUnknownExpr())
var iterator = returnStmt.children.makeIterator()
expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .returnKeyword }
expectNext(&iterator) { $0 is ExprSyntax }
- expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .semicolon }
expectNextIsNil(&iterator)
}
SyntaxChildrenAPI.test("IterateWithSomeMissing") {
let returnStmt = SyntaxFactory.makeReturnStmt(
returnKeyword: SyntaxFactory.makeReturnKeyword(),
- expression: nil,
- semicolon: SyntaxFactory.makeSemicolonToken())
+ expression: nil)
var iterator = returnStmt.children.makeIterator()
expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .returnKeyword }
- expectNext(&iterator) { ($0 as? TokenSyntax)?.tokenKind == .semicolon }
expectNextIsNil(&iterator)
}
diff --git a/test/Syntax/Inputs/serialize_multiple_decls.json b/test/Syntax/Inputs/serialize_multiple_decls.json
index 909065d..931ea25 100644
--- a/test/Syntax/Inputs/serialize_multiple_decls.json
+++ b/test/Syntax/Inputs/serialize_multiple_decls.json
@@ -2,193 +2,181 @@
"kind": "SourceFile",
"layout": [
{
- "kind": "DeclList",
+ "kind": "CodeBlockItemList",
"layout": [
{
- "kind": "TopLevelCodeDecl",
+ "kind": "CodeBlockItem",
"layout": [
{
- "kind": "StmtList",
+ "kind": "StructDecl",
"layout": [
+ null,
+ null,
{
- "kind": "DeclarationStmt",
- "layout": [
+ "tokenKind": {
+ "kind": "kw_struct"
+ },
+ "leadingTrivia": [
{
- "kind": "StructDecl",
- "layout": [
- null,
- null,
- {
- "tokenKind": {
- "kind": "kw_struct"
- },
- "leadingTrivia": [
- {
- "kind": "LineComment",
- "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
- },
- {
- "kind": "Newline",
- "value": 1
- },
- {
- "kind": "LineComment",
- "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_multiple_decls.json"
- },
- {
- "kind": "Newline",
- "value": 2
- }
- ],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "A"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- null,
- null,
- null,
- {
- "kind": "MemberDeclBlock",
- "layout": [
- {
- "tokenKind": {
- "kind": "l_brace"
- },
- "leadingTrivia": [],
- "trailingTrivia": [],
- "presence": "Present"
- },
- {
- "kind": "DeclList",
- "layout": [],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "r_brace"
- },
- "leadingTrivia": [
- {
- "kind": "Newline",
- "value": 1
- }
- ],
- "trailingTrivia": [],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
+ "kind": "LineComment",
+ "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
},
- null
+ {
+ "kind": "Newline",
+ "value": 1
+ },
+ {
+ "kind": "LineComment",
+ "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_multiple_decls.json"
+ },
+ {
+ "kind": "Newline",
+ "value": 2
+ }
+ ],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
],
"presence": "Present"
},
{
- "kind": "DeclarationStmt",
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "A"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ null,
+ null,
+ null,
+ {
+ "kind": "MemberDeclBlock",
"layout": [
{
- "kind": "StructDecl",
- "layout": [
- null,
- null,
- {
- "tokenKind": {
- "kind": "kw_struct"
- },
- "leadingTrivia": [
- {
- "kind": "Newline",
- "value": 2
- }
- ],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "B"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- null,
- null,
- null,
- {
- "kind": "MemberDeclBlock",
- "layout": [
- {
- "tokenKind": {
- "kind": "l_brace"
- },
- "leadingTrivia": [],
- "trailingTrivia": [],
- "presence": "Present"
- },
- {
- "kind": "DeclList",
- "layout": [],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "r_brace"
- },
- "leadingTrivia": [
- {
- "kind": "Newline",
- "value": 1
- }
- ],
- "trailingTrivia": [],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
+ "tokenKind": {
+ "kind": "l_brace"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [],
"presence": "Present"
},
- null
+ {
+ "kind": "DeclList",
+ "layout": [],
+ "presence": "Present"
+ },
+ {
+ "tokenKind": {
+ "kind": "r_brace"
+ },
+ "leadingTrivia": [
+ {
+ "kind": "Newline",
+ "value": 1
+ }
+ ],
+ "trailingTrivia": [],
+ "presence": "Present"
+ }
],
"presence": "Present"
}
],
"presence": "Present"
- }
+ },
+ null
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "CodeBlockItem",
+ "layout": [
+ {
+ "kind": "StructDecl",
+ "layout": [
+ null,
+ null,
+ {
+ "tokenKind": {
+ "kind": "kw_struct"
+ },
+ "leadingTrivia": [
+ {
+ "kind": "Newline",
+ "value": 2
+ }
+ ],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "B"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ null,
+ null,
+ null,
+ {
+ "kind": "MemberDeclBlock",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "l_brace"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [],
+ "presence": "Present"
+ },
+ {
+ "kind": "DeclList",
+ "layout": [],
+ "presence": "Present"
+ },
+ {
+ "tokenKind": {
+ "kind": "r_brace"
+ },
+ "leadingTrivia": [
+ {
+ "kind": "Newline",
+ "value": 1
+ }
+ ],
+ "trailingTrivia": [],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ null
],
"presence": "Present"
}
diff --git a/test/Syntax/Inputs/serialize_struct_decl.json b/test/Syntax/Inputs/serialize_struct_decl.json
index 033ffeb..14d1da1 100644
--- a/test/Syntax/Inputs/serialize_struct_decl.json
+++ b/test/Syntax/Inputs/serialize_struct_decl.json
@@ -2,354 +2,85 @@
"kind": "SourceFile",
"layout": [
{
- "kind": "DeclList",
+ "kind": "CodeBlockItemList",
"layout": [
{
- "kind": "TopLevelCodeDecl",
+ "kind": "CodeBlockItem",
"layout": [
{
- "kind": "StmtList",
+ "kind": "StructDecl",
"layout": [
+ null,
+ null,
{
- "kind": "DeclarationStmt",
+ "tokenKind": {
+ "kind": "kw_struct"
+ },
+ "leadingTrivia": [
+ {
+ "kind": "LineComment",
+ "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
+ },
+ {
+ "kind": "Newline",
+ "value": 1
+ },
+ {
+ "kind": "LineComment",
+ "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_struct_decl.json"
+ },
+ {
+ "kind": "Newline",
+ "value": 2
+ }
+ ],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "Foo"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ null,
+ null,
+ null,
+ {
+ "kind": "MemberDeclBlock",
"layout": [
{
- "kind": "StructDecl",
+ "tokenKind": {
+ "kind": "l_brace"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [],
+ "presence": "Present"
+ },
+ {
+ "kind": "DeclList",
"layout": [
- null,
- null,
{
- "tokenKind": {
- "kind": "kw_struct"
- },
- "leadingTrivia": [
- {
- "kind": "LineComment",
- "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t"
- },
- {
- "kind": "Newline",
- "value": 1
- },
- {
- "kind": "LineComment",
- "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_struct_decl.json"
- },
- {
- "kind": "Newline",
- "value": 2
- }
- ],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "Foo"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- null,
- null,
- null,
- {
- "kind": "MemberDeclBlock",
+ "kind": "VariableDecl",
"layout": [
+ null,
+ null,
{
"tokenKind": {
- "kind": "l_brace"
- },
- "leadingTrivia": [],
- "trailingTrivia": [],
- "presence": "Present"
- },
- {
- "kind": "DeclList",
- "layout": [
- {
- "kind": "VariableDecl",
- "layout": [
- null,
- null,
- {
- "tokenKind": {
- "kind": "kw_let"
- },
- "leadingTrivia": [
- {
- "kind": "Newline",
- "value": 1
- },
- {
- "kind": "Space",
- "value": 2
- }
- ],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 3
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "PatternBindingList",
- "layout": [
- {
- "kind": "PatternBinding",
- "layout": [
- {
- "kind": "IdentifierPattern",
- "layout": [
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "bar"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "TypeAnnotation",
- "layout": [
- {
- "tokenKind": {
- "kind": "colon"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "SimpleTypeIdentifier",
- "layout": [
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "Int"
- },
- "leadingTrivia": [],
- "trailingTrivia": [],
- "presence": "Present"
- },
- null
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- null,
- null,
- null
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "VariableDecl",
- "layout": [
- null,
- null,
- {
- "tokenKind": {
- "kind": "kw_let"
- },
- "leadingTrivia": [
- {
- "kind": "Newline",
- "value": 2
- },
- {
- "kind": "Space",
- "value": 2
- }
- ],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "PatternBindingList",
- "layout": [
- {
- "kind": "PatternBinding",
- "layout": [
- {
- "kind": "IdentifierPattern",
- "layout": [
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "baz"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "TypeAnnotation",
- "layout": [
- {
- "tokenKind": {
- "kind": "colon"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "SimpleTypeIdentifier",
- "layout": [
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "Array"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "GenericArgumentClause",
- "layout": [
- {
- "tokenKind": {
- "kind": "l_angle"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- {
- "kind": "GenericArgumentList",
- "layout": [
- {
- "kind": "GenericArgument",
- "layout": [
- {
- "kind": "SimpleTypeIdentifier",
- "layout": [
- {
- "tokenKind": {
- "kind": "identifier",
- "text": "Int"
- },
- "leadingTrivia": [],
- "trailingTrivia": [
- {
- "kind": "Space",
- "value": 1
- }
- ],
- "presence": "Present"
- },
- null
- ],
- "presence": "Present"
- },
- null
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "r_angle"
- },
- "leadingTrivia": [],
- "trailingTrivia": [],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- null,
- null,
- null
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- }
- ],
- "presence": "Present"
- },
- {
- "tokenKind": {
- "kind": "r_brace"
+ "kind": "kw_let"
},
"leadingTrivia": [
{
@@ -358,10 +89,250 @@
},
{
"kind": "Space",
- "value": 6
+ "value": 2
}
],
- "trailingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 3
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "PatternBindingList",
+ "layout": [
+ {
+ "kind": "PatternBinding",
+ "layout": [
+ {
+ "kind": "IdentifierPattern",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "bar"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "TypeAnnotation",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "colon"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "SimpleTypeIdentifier",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "Int"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [],
+ "presence": "Present"
+ },
+ null
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ null,
+ null,
+ null
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "VariableDecl",
+ "layout": [
+ null,
+ null,
+ {
+ "tokenKind": {
+ "kind": "kw_let"
+ },
+ "leadingTrivia": [
+ {
+ "kind": "Newline",
+ "value": 2
+ },
+ {
+ "kind": "Space",
+ "value": 2
+ }
+ ],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "PatternBindingList",
+ "layout": [
+ {
+ "kind": "PatternBinding",
+ "layout": [
+ {
+ "kind": "IdentifierPattern",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "baz"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "TypeAnnotation",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "colon"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "SimpleTypeIdentifier",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "Array"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "GenericArgumentClause",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "l_angle"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "kind": "GenericArgumentList",
+ "layout": [
+ {
+ "kind": "GenericArgument",
+ "layout": [
+ {
+ "kind": "SimpleTypeIdentifier",
+ "layout": [
+ {
+ "tokenKind": {
+ "kind": "identifier",
+ "text": "Int"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [
+ {
+ "kind": "Space",
+ "value": 1
+ }
+ ],
+ "presence": "Present"
+ },
+ null
+ ],
+ "presence": "Present"
+ },
+ null
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ {
+ "tokenKind": {
+ "kind": "r_angle"
+ },
+ "leadingTrivia": [],
+ "trailingTrivia": [],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ }
+ ],
+ "presence": "Present"
+ },
+ null,
+ null,
+ null
+ ],
+ "presence": "Present"
+ }
+ ],
"presence": "Present"
}
],
@@ -370,13 +341,30 @@
],
"presence": "Present"
},
- null
+ {
+ "tokenKind": {
+ "kind": "r_brace"
+ },
+ "leadingTrivia": [
+ {
+ "kind": "Newline",
+ "value": 1
+ },
+ {
+ "kind": "Space",
+ "value": 6
+ }
+ ],
+ "trailingTrivia": [],
+ "presence": "Present"
+ }
],
"presence": "Present"
}
],
"presence": "Present"
- }
+ },
+ null
],
"presence": "Present"
}
diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp
index 6eddc66..ea0fc79 100644
--- a/unittests/Syntax/DeclSyntaxTests.cpp
+++ b/unittests/Syntax/DeclSyntaxTests.cpp
@@ -506,10 +506,10 @@
auto ReturnKW =
SyntaxFactory::makeReturnKeyword(Trivia::newlines(1) + Trivia::spaces(2),
{});
- auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, One, None);
+ auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, One);
+ auto ReturnItem = SyntaxFactory::makeCodeBlockItem(Return, None);
- auto Stmts = SyntaxFactory::makeBlankStmtList()
- .appending(Return);
+ auto Stmts = SyntaxFactory::makeCodeBlockItemList({ReturnItem});
auto LBrace = SyntaxFactory::makeLeftBraceToken({}, {});
auto RBrace = SyntaxFactory::makeRightBraceToken(Trivia::newlines(1), {});
diff --git a/unittests/Syntax/StmtSyntaxTests.cpp b/unittests/Syntax/StmtSyntaxTests.cpp
index 0deb1e9..7141df5 100644
--- a/unittests/Syntax/StmtSyntaxTests.cpp
+++ b/unittests/Syntax/StmtSyntaxTests.cpp
@@ -41,7 +41,7 @@
llvm::SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
- SyntaxFactory::makeFallthroughStmt(FallthroughKW, llvm::None).print(OS);
+ SyntaxFactory::makeFallthroughStmt(FallthroughKW).print(OS);
ASSERT_EQ(OS.str().str(), "fallthrough");
}
@@ -51,7 +51,7 @@
auto NewFallthroughKW = FallthroughKW.withLeadingTrivia(Trivia::spaces(2));
- SyntaxFactory::makeFallthroughStmt(NewFallthroughKW, llvm::None).print(OS);
+ SyntaxFactory::makeFallthroughStmt(NewFallthroughKW).print(OS);
ASSERT_EQ(OS.str().str(), " fallthrough");
}
@@ -62,7 +62,7 @@
auto NewFallthroughKW = FallthroughKW.withLeadingTrivia(Trivia::spaces(2))
.withTrailingTrivia(Trivia::spaces(2));
- SyntaxFactory::makeFallthroughStmt(NewFallthroughKW, llvm::None).print(OS);
+ SyntaxFactory::makeFallthroughStmt(NewFallthroughKW).print(OS);
ASSERT_EQ(OS.str().str(), " fallthrough ");
}
@@ -80,7 +80,7 @@
TEST(StmtSyntaxTests, BreakStmtGetAPIs) {
auto BreakKW = SyntaxFactory::makeBreakKeyword({}, Trivia::spaces(1));
auto Label = SyntaxFactory::makeIdentifier("sometimesYouNeedTo", {}, {});
- auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label, llvm::None);
+ auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label);
/// These should be directly shared through reference-counting.
ASSERT_EQ(BreakKW.getRaw(), Break.getBreakKeyword().getRaw());
@@ -128,7 +128,7 @@
llvm::raw_svector_ostream OS(Scratch);
auto BreakKW = SyntaxFactory::makeBreakKeyword({}, Trivia::spaces(1));
auto Label = SyntaxFactory::makeIdentifier("theBuild", {}, {});
- auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label, llvm::None);
+ auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label);
Break.print(OS);
ASSERT_EQ(OS.str().str(), "break theBuild"); // don't you dare
}
@@ -145,8 +145,7 @@
TEST(StmtSyntaxTests, ContinueStmtGetAPIs) {
auto ContinueKW = SyntaxFactory::makeContinueKeyword({}, Trivia::spaces(1));
auto Label = SyntaxFactory::makeIdentifier("always", {}, {});
- auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label,
- llvm::None);
+ auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label);
/// These should be directly shared through reference-counting.
ASSERT_EQ(ContinueKW.getRaw(), Continue.getContinueKeyword().getRaw());
@@ -194,8 +193,7 @@
llvm::raw_svector_ostream OS(Scratch);
auto ContinueKW = SyntaxFactory::makeContinueKeyword({}, Trivia::spaces(1));
auto Label = SyntaxFactory::makeIdentifier("toLead", {}, {});
- auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label,
- llvm::None);
+ auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label);
Continue.print(OS);
ASSERT_EQ(OS.str().str(), "continue toLead"); // by example
}
@@ -226,7 +224,7 @@
{
llvm::SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
- SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None).print(OS);
+ SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne).print(OS);
ASSERT_EQ(OS.str().str(), "return -1");
}
}
@@ -237,7 +235,7 @@
auto OneDigits = SyntaxFactory::makeIntegerLiteral("1", {}, {});
auto MinusOne = SyntaxFactory::makePrefixOperatorExpr(Minus,
SyntaxFactory::makeIntegerLiteralExpr(OneDigits));
- auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None);
+ auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
ASSERT_EQ(ReturnKW.getRaw(), Return.getReturnKeyword().getRaw());
auto GottenExpression = Return.getExpression().getValue();
diff --git a/unittests/Syntax/ThreadSafeCachingTests.cpp b/unittests/Syntax/ThreadSafeCachingTests.cpp
index 4d7fad6..184ab09 100644
--- a/unittests/Syntax/ThreadSafeCachingTests.cpp
+++ b/unittests/Syntax/ThreadSafeCachingTests.cpp
@@ -88,7 +88,7 @@
Pool P;
for (unsigned i = 0; i < 10000; ++i) {
- auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None);
+ auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
auto Future1 = P.run(getExpressionFrom, Return);
auto Future2 = P.run(getExpressionFrom, Return);
diff --git a/utils/gyb_syntax_support/CommonNodes.py b/utils/gyb_syntax_support/CommonNodes.py
index 429ecbf..744db91 100644
--- a/utils/gyb_syntax_support/CommonNodes.py
+++ b/utils/gyb_syntax_support/CommonNodes.py
@@ -1,4 +1,5 @@
-from Node import Node
+from Child import Child
+from Node import Node # noqa: I201
COMMON_NODES = [
Node('Decl', kind='Syntax'),
@@ -11,4 +12,29 @@
Node('UnknownStmt', kind='Stmt'),
Node('UnknownType', kind='Type'),
Node('UnknownPattern', kind='Pattern'),
+
+ # code-block-item = (decl | stmt | expr) ';'?
+ Node('CodeBlockItem', kind='Syntax',
+ children=[
+ Child('Item', kind='Syntax',
+ node_choices=[
+ Child('Decl', kind='Decl'),
+ Child('Stmt', kind='Stmt'),
+ Child('Expr', kind='Expr'),
+ ]),
+ Child('Semicolon', kind='SemicolonToken',
+ is_optional=True),
+ ]),
+
+ # code-block-item-list -> code-block-item code-block-item-list?
+ Node('CodeBlockItemList', kind='SyntaxCollection',
+ element='CodeBlockItem'),
+
+ # code-block -> '{' stmt-list '}'
+ Node('CodeBlock', kind='Syntax',
+ children=[
+ Child('OpenBrace', kind='LeftBraceToken'),
+ Child('Statements', kind='CodeBlockItemList'),
+ Child('CloseBrace', kind='RightBraceToken'),
+ ]),
]
diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py
index 5878ec2..84710fc 100644
--- a/utils/gyb_syntax_support/DeclNodes.py
+++ b/utils/gyb_syntax_support/DeclNodes.py
@@ -88,7 +88,7 @@
children=[
Child('PoundElseif', kind='PoundElseifToken'),
Child('Condition', kind='Expr'),
- Child('Body', kind='StmtList'),
+ Child('Body', kind='CodeBlockItemList'),
]),
# if-config-decl -> '#if' expr stmt-list else-if-directive-clause-list
@@ -97,7 +97,7 @@
children=[
Child('PoundIf', kind='PoundIfToken'),
Child('Condition', kind='Expr'),
- Child('Body', kind='StmtList'),
+ Child('Body', kind='CodeBlockItemList'),
Child('ElseifDirectiveClauses', kind='ElseifDirectiveClauseList',
is_optional=True),
Child('ElseClause', kind='ElseDirectiveClause',
@@ -245,19 +245,13 @@
Node('DeclList', kind='SyntaxCollection',
element='Decl'),
- # source-file = decl-list eof
+ # source-file = code-block-item-list eof
Node('SourceFile', kind='Syntax',
children=[
- Child('TopLevelDecls', kind='DeclList'),
+ Child('Items', kind='CodeBlockItemList'),
Child('EOFToken', kind='EOFToken')
]),
- # top-level-code-decl = stmt-list
- Node('TopLevelCodeDecl', kind='Decl',
- children=[
- Child('Body', kind='StmtList')
- ]),
-
# initializer -> '=' expr
Node('InitializerClause', kind='Syntax',
children=[
@@ -408,7 +402,7 @@
Node('ElseDirectiveClause', kind='Syntax',
children=[
Child('PoundElse', kind='PoundElseToken'),
- Child('Body', kind='StmtList'),
+ Child('Body', kind='CodeBlockItemList'),
]),
# access-level-modifier -> 'private' | 'private' '(' 'set' ')'
@@ -476,7 +470,7 @@
Child('AccessorListOrStmtList', kind='Syntax',
node_choices=[
Child('Accessors', kind='AccessorList'),
- Child('Statements', kind='StmtList')]),
+ Child('Statements', kind='CodeBlockItemList')]),
Child('RightBrace', kind='RightBraceToken'),
]),
diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py
index b950756..9e4ee1b 100644
--- a/utils/gyb_syntax_support/ExprNodes.py
+++ b/utils/gyb_syntax_support/ExprNodes.py
@@ -387,7 +387,7 @@
children=[
Child('LeftBrace', kind='LeftBraceToken'),
Child('Signature', kind='ClosureSignature', is_optional=True),
- Child('Statements', kind='StmtList'),
+ Child('Statements', kind='CodeBlockItemList'),
Child('RightBrace', kind='RightBraceToken'),
]),
diff --git a/utils/gyb_syntax_support/StmtNodes.py b/utils/gyb_syntax_support/StmtNodes.py
index 3cfc50e..50c7bfb 100644
--- a/utils/gyb_syntax_support/StmtNodes.py
+++ b/utils/gyb_syntax_support/StmtNodes.py
@@ -8,8 +8,6 @@
Child('ContinueKeyword', kind='ContinueToken'),
Child('Label', kind='IdentifierToken',
is_optional=True),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# while-stmt -> label? ':'? 'while' condition-list code-block ';'?
@@ -22,8 +20,6 @@
Child('WhileKeyword', kind='WhileToken'),
Child('Conditions', kind='ConditionElementList'),
Child('Body', kind='CodeBlock'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# defer-stmt -> 'defer' code-block ';'?
@@ -31,16 +27,12 @@
children=[
Child('DeferKeyword', kind='DeferToken'),
Child('Body', kind='CodeBlock'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# expr-stmt -> expression ';'?
Node('ExpressionStmt', kind='Stmt',
children=[
Child('Expression', kind='Expr'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# switch-case-list -> switch-case switch-case-list?
@@ -58,8 +50,6 @@
Child('Body', kind='CodeBlock'),
Child('WhileKeyword', kind='WhileToken'),
Child('Condition', kind='Expr'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# guard-stmt -> 'guard' condition-list 'else' code-block ';'?
@@ -69,8 +59,6 @@
Child('Conditions', kind='ConditionElementList'),
Child('ElseKeyword', kind='ElseToken'),
Child('Body', kind='CodeBlock'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
Node('WhereClause', kind='Syntax',
@@ -98,8 +86,6 @@
Child('WhereClause', kind='WhereClause',
is_optional=True),
Child('Body', kind='CodeBlock'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# switch-stmt -> identifier? ':'? 'switch' expr '{'
@@ -115,8 +101,6 @@
Child('OpenBrace', kind='LeftBraceToken'),
Child('Cases', kind='SwitchCaseList'),
Child('CloseBrace', kind='RightBraceToken'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# catch-clause-list -> catch-clause catch-clause-list?
@@ -134,8 +118,6 @@
Child('Body', kind='CodeBlock'),
Child('CatchClauses', kind='CatchClauseList',
is_optional=True),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# return-stmt -> 'return' expr? ';'?
@@ -144,16 +126,12 @@
Child('ReturnKeyword', kind='ReturnToken'),
Child('Expression', kind='Expr',
is_optional=True),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# fallthrough-stmt -> 'fallthrough' ';'?
Node('FallthroughStmt', kind='Stmt',
children=[
Child('FallthroughKeyword', kind='FallthroughToken'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# break-stmt -> 'break' identifier? ';'?
@@ -162,16 +140,6 @@
Child('BreakKeyword', kind='BreakToken'),
Child('Label', kind='IdentifierToken',
is_optional=True),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
- ]),
-
- # code-block -> '{' stmt-list '}'
- Node('CodeBlock', kind='Syntax',
- children=[
- Child('OpenBrace', kind='LeftBraceToken'),
- Child('Statements', kind='StmtList'),
- Child('CloseBrace', kind='RightBraceToken'),
]),
# case-item-list -> case-item case-item-list?
@@ -231,8 +199,6 @@
Node('DeclarationStmt', kind='Stmt',
children=[
Child('Declaration', kind='Decl'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# throw-stmt -> 'throw' expr ';'?
@@ -240,8 +206,6 @@
children=[
Child('ThrowKeyword', kind='ThrowToken'),
Child('Expression', kind='Expr'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# if-stmt -> identifier? ':'? 'if' condition-list code-block
@@ -263,8 +227,6 @@
Child('CodeBlock', kind='CodeBlock'),
],
is_optional=True),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
# else-if-continuation -> label? ':'? 'while' condition-list code-block ';'
@@ -278,20 +240,14 @@
children=[
Child('ElseKeyword', kind='ElseToken'),
Child('Body', kind='CodeBlock'),
- Child('Semicolon', kind='SemicolonToken',
- is_optional=True),
]),
- # stmt-list -> stmt stmt-list?
- Node('StmtList', kind='SyntaxCollection',
- element='Stmt'),
-
# switch-case -> switch-case-label stmt-list
# | default-label stmt-list
Node('SwitchCase', kind='Syntax',
children=[
Child('Label', kind='Syntax'),
- Child('Body', kind='StmtList'),
+ Child('Body', kind='CodeBlockItemList'),
]),
# switch-default-label -> 'default' ':'