Merge pull request #10731 from gottesmm/ignore_unreachable_nonowning_uses
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index d9971cd..ee5c0c5 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -48,6 +48,7 @@
single-source/DropLast
single-source/DropWhile
single-source/ErrorHandling
+ single-source/Exclusivity
single-source/ExistentialPerformance
single-source/Fibonacci
single-source/Hanoi
diff --git a/benchmark/single-source/Exclusivity.swift b/benchmark/single-source/Exclusivity.swift
new file mode 100644
index 0000000..368953a
--- /dev/null
+++ b/benchmark/single-source/Exclusivity.swift
@@ -0,0 +1,106 @@
+//===--- Exclusivity.swift -------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// A set of tests for measuring the enforcement overhead of memory access
+// exclusivity rules.
+//
+//===----------------------------------------------------------------------===//
+
+import TestsUtils
+
+// Initially these benchmarks only measure access checks at -Onone. In
+// the future, access checks will also be emitted at -O.
+
+// Measure memory access checks on a trivial global.
+// ---
+
+public var globalCounter: Int = 0
+
+// TODO:
+// - Merge begin/endAccess when no calls intervene (~2x speedup).
+// - Move Swift runtime into the OS (~2x speedup).
+// - Whole module analysis can remove exclusivity checks (> 10x speedup now, 4x speedup with runtime in OS).
+// (The global's "public" qualifier should make the benchmark immune to this optimization.)
+@inline(never)
+public func run_accessGlobal(_ N: Int) {
+ globalCounter = 0
+ for _ in 1...10000*N {
+ globalCounter += 1
+ }
+ CheckResults(globalCounter == 10000*N)
+}
+
+// Measure memory access checks on a class property.
+//
+// Note: The end_unpaired_access forces a callback on the property's
+// materializeForSet!
+// ---
+
+// Hopefully the optimizer will not see this as "final" and optimize away the
+// materializeForSet.
+public class C {
+ var counter = 0
+
+ func inc() {
+ counter += 1
+ }
+}
+
+// Thunk
+@inline(never)
+func updateClass(_ c: C) {
+ c.inc()
+}
+
+// TODO: Replacing materializeForSet accessors with yield-once
+// accessors should make the callback overhead go away.
+@inline(never)
+public func run_accessInMatSet(_ N: Int) {
+ let c = C()
+ for _ in 1...10000*N {
+ updateClass(c)
+ }
+ CheckResults(c.counter == 10000*N)
+}
+
+// Measure nested access to independent objects.
+//
+// A single access set is still faster than hashing for up to four accesses.
+// ---
+
+struct Var {
+ var val = 0
+}
+
+@inline(never)
+func update(a: inout Var, b: inout Var, c: inout Var, d: inout Var) {
+ a.val += 1
+ b.val += 1
+ c.val += 1
+ d.val += 1
+}
+
+@inline(never)
+public func run_accessIndependent(_ N: Int) {
+ var a = Var()
+ var b = Var()
+ var c = Var()
+ var d = Var()
+ let updateVars = {
+ update(a: &a, b: &b, c: &c, d: &d)
+ }
+ for _ in 1...1000*N {
+ updateVars()
+ }
+ CheckResults(a.val == 1000*N && b.val == 1000*N && c.val == 1000*N
+ && d.val == 1000*N)
+}
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index 6a4b6fe..6eda05c 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -53,6 +53,7 @@
import DropLast
import DropWhile
import ErrorHandling
+import Exclusivity
import ExistentialPerformance
import Fibonacci
import Hanoi
@@ -448,6 +449,9 @@
addTo(&precommitTests, "UTF8Decode", run_UTF8Decode)
addTo(&precommitTests, "Walsh", run_Walsh)
addTo(&precommitTests, "XorLoop", run_XorLoop)
+addTo(&precommitTests, "accessGlobal", run_accessGlobal)
+addTo(&precommitTests, "accessInMatSet", run_accessInMatSet)
+addTo(&precommitTests, "accessIndependent", run_accessIndependent)
// Other tests
addTo(&otherTests, "Ackermann", run_Ackermann)
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 8609243..7fc2f52 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -318,9 +318,9 @@
/// called 'static').
unsigned IsStatic : 1;
- /// \brief Whether this is a 'let' property, which can only be initialized
- /// once (either in its declaration, or once later), making it immutable.
- unsigned IsLet : 1;
+ /// \brief The specifier associated with this variable or parameter. This
+ /// determines the storage semantics of the value e.g. mutability.
+ unsigned Specifier : 2;
/// \brief Whether this declaration was an element of a capture list.
unsigned IsCaptureList : 1;
@@ -335,7 +335,7 @@
unsigned IsDebuggerVar : 1;
};
- enum { NumVarDeclBits = NumAbstractStorageDeclBits + 5 };
+ enum { NumVarDeclBits = NumAbstractStorageDeclBits + 6 };
static_assert(NumVarDeclBits <= 32, "fits in an unsigned");
class EnumElementDeclBitfields {
@@ -3501,7 +3501,7 @@
/// The generic signature representing exactly the new requirements introduced
/// by this protocol.
- GenericSignature *RequirementSignature = nullptr;
+ const Requirement *RequirementSignature = nullptr;
/// True if the protocol has requirements that cannot be satisfied (e.g.
/// because they could not be imported from Objective-C).
@@ -3511,6 +3511,9 @@
/// value, plus one. Otherwise, it will be 0.
unsigned KnownProtocol : 6;
+ /// The number of requirements in the requirement signature.
+ unsigned NumRequirementsInSignature : 16;
+
bool requiresClassSlow();
bool existentialConformsToSelfSlow();
@@ -3687,8 +3690,6 @@
/// Create the implicit generic parameter list for a protocol or
/// extension thereof.
- ///
- /// FIXME: protocol extensions will introduce a where clause here as well.
GenericParamList *createGenericParams(DeclContext *dc);
/// Create the generic parameters of this protocol if the haven't been
@@ -3700,17 +3701,17 @@
return TrailingWhere;
}
- /// Retrieve the generic signature representing the requirements introduced by
- /// this protocol.
+ /// Retrieve the requirements that describe this protocol.
///
- /// These are the requirements like any inherited protocols and conformances
- /// for associated types that are mentioned literally in this
- /// decl. Requirements implied via inheritance are not mentioned, nor is the
- /// conformance of Self to this protocol.
- GenericSignature *getRequirementSignature() const {
- assert(RequirementSignature &&
+ /// These are the requirements including any inherited protocols
+ /// and conformances for associated types that are introduced in this
+ /// protocol. Requirements implied via any other protocol (e.g., inherited
+ /// protocols of the inherited protocols) are not mentioned. The conformance
+ /// requirements listed here become entries in the witness table.
+ ArrayRef<Requirement> getRequirementSignature() const {
+ assert(isRequirementSignatureComputed() &&
"getting requirement signature before computing it");
- return RequirementSignature;
+ return llvm::makeArrayRef(RequirementSignature, NumRequirementsInSignature);
}
/// Has the requirement signature been computed yet?
@@ -3720,9 +3721,7 @@
void computeRequirementSignature();
- void setRequirementSignature(GenericSignature *sig) {
- RequirementSignature = sig;
- }
+ void setRequirementSignature(ArrayRef<Requirement> requirements);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
@@ -4325,15 +4324,28 @@
/// VarDecl - 'var' and 'let' declarations.
class VarDecl : public AbstractStorageDecl {
+public:
+ enum class Specifier : uint8_t {
+ // For Var Decls
+
+ Let = 0,
+ Var = 1,
+
+ // For Param Decls
+
+ None = Let,
+ InOut = 2,
+ };
+
protected:
llvm::PointerUnion<PatternBindingDecl*, Stmt*> ParentPattern;
- VarDecl(DeclKind Kind, bool IsStatic, bool IsLet, bool IsCaptureList,
+ VarDecl(DeclKind Kind, bool IsStatic, Specifier Sp, bool IsCaptureList,
SourceLoc NameLoc, Identifier Name, Type Ty, DeclContext *DC)
: AbstractStorageDecl(Kind, DC, Name, NameLoc)
{
VarDeclBits.IsStatic = IsStatic;
- VarDeclBits.IsLet = IsLet;
+ VarDeclBits.Specifier = static_cast<unsigned>(Sp);
VarDeclBits.IsCaptureList = IsCaptureList;
VarDeclBits.IsDebuggerVar = false;
VarDeclBits.HasNonPatternBindingInit = false;
@@ -4346,9 +4358,9 @@
Type typeInContext;
public:
- VarDecl(bool IsStatic, bool IsLet, bool IsCaptureList, SourceLoc NameLoc,
+ VarDecl(bool IsStatic, Specifier Sp, bool IsCaptureList, SourceLoc NameLoc,
Identifier Name, Type Ty, DeclContext *DC)
- : VarDecl(DeclKind::Var, IsStatic, IsLet, IsCaptureList, NameLoc, Name, Ty,
+ : VarDecl(DeclKind::Var, IsStatic, Sp, IsCaptureList, NameLoc, Name, Ty,
DC) {}
SourceRange getSourceRange() const;
@@ -4448,6 +4460,11 @@
/// Determine whether this declaration is an anonymous closure parameter.
bool isAnonClosureParam() const;
+ /// Return the raw specifier value for this property or parameter.
+ Specifier getSpecifier() const {
+ return static_cast<Specifier>(VarDeclBits.Specifier);
+ }
+
/// Is this a type ('static') variable?
bool isStatic() const { return VarDeclBits.IsStatic; }
void setStatic(bool IsStatic) { VarDeclBits.IsStatic = IsStatic; }
@@ -4456,9 +4473,20 @@
StaticSpellingKind getCorrectStaticSpelling() const;
/// Is this an immutable 'let' property?
- bool isLet() const { return VarDeclBits.IsLet; }
- void setLet(bool IsLet) { VarDeclBits.IsLet = IsLet; }
-
+ bool isLet() const { return getSpecifier() == Specifier::Let; }
+ // FIXME: Remove this setter.
+ void setLet(bool immutable) {
+ auto specifier = VarDecl::Specifier::Let;
+ if (!immutable) {
+ if (getKind() == DeclKind::Param) {
+ specifier = VarDecl::Specifier::InOut;
+ } else {
+ specifier = VarDecl::Specifier::Var;
+ }
+ }
+ VarDeclBits.Specifier = static_cast<unsigned>(specifier);
+ }
+
/// Is this an element in a capture list?
bool isCaptureList() const { return VarDeclBits.IsCaptureList; }
@@ -4509,7 +4537,7 @@
class ParamDecl : public VarDecl {
Identifier ArgumentName;
SourceLoc ArgumentNameLoc;
- SourceLoc LetVarInOutLoc;
+ SourceLoc SpecifierLoc;
struct StoredDefaultArgument {
Expr *DefaultArg = nullptr;
@@ -4530,7 +4558,8 @@
DefaultArgumentKind defaultArgumentKind = DefaultArgumentKind::None;
public:
- ParamDecl(bool isLet, SourceLoc letVarInOutLoc, SourceLoc argumentNameLoc,
+ ParamDecl(VarDecl::Specifier specifier,
+ SourceLoc specifierLoc, SourceLoc argumentNameLoc,
Identifier argumentName, SourceLoc parameterNameLoc,
Identifier parameterName, Type ty, DeclContext *dc);
@@ -4548,7 +4577,7 @@
/// was specified separately from the parameter name.
SourceLoc getArgumentNameLoc() const { return ArgumentNameLoc; }
- SourceLoc getLetVarInOutLoc() const { return LetVarInOutLoc; }
+ SourceLoc getSpecifierLoc() const { return SpecifierLoc; }
bool isTypeLocImplicit() const { return IsTypeLocImplicit; }
void setIsTypeLocImplicit(bool val) { IsTypeLocImplicit = val; }
diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def
index b3d227b..e098c22 100644
--- a/include/swift/AST/DiagnosticsFrontend.def
+++ b/include/swift/AST/DiagnosticsFrontend.def
@@ -167,6 +167,17 @@
ERROR(error_parse_input_file,none,
"error parsing input file '%0' (%1)", (StringRef, StringRef))
+ERROR(error_write_index_unit,none,
+ "writing index unit file: %0", (StringRef))
+ERROR(error_create_index_dir,none,
+ "creating index directory: %0", (StringRef))
+ERROR(error_write_index_record,none,
+ "writing index record file: %0", (StringRef))
+ERROR(error_index_failed_status_check,none,
+ "failed file status check: %0", (StringRef))
+ERROR(error_index_inputs_more_than_outputs,none,
+ "index output filenames do not match input source files", ())
+
ERROR(error_formatting_multiple_file_ranges,none,
"file ranges don't support multiple input files", ())
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index 350beb4..e20625b 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -814,8 +814,8 @@
ERROR(parameter_inout_var_let_repeated,none,
"parameter may not have multiple 'inout', 'var', or 'let' specifiers",
())
-ERROR(parameter_let_as_attr,none,
- "'let' as a parameter attribute is not allowed", ())
+ERROR(parameter_let_var_as_attr,none,
+ "'%select{var|let}0' as a parameter attribute is not allowed", (unsigned))
ERROR(expected_behavior_name,none,
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 649cf2a..7b4d9eb 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -1006,10 +1006,6 @@
ERROR(attribute_requires_single_argument,none,
"'%0' requires a function with one argument", (StringRef))
-ERROR(var_parameter_not_allowed,none,
- "parameters may not have the 'var' specifier", ())
-
-
ERROR(mutating_invalid_global_scope,none,
"'mutating' is only valid on methods", ())
ERROR(mutating_invalid_classes,none,
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index 0f81c85..583aff7 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -63,10 +63,6 @@
/// Determines how to resolve a dependent type to a potential archetype.
enum class ArchetypeResolutionKind {
- /// Always create a new potential archetype to describe this dependent type,
- /// which might be invalid and may not provide complete information.
- AlwaysPartial,
-
/// Only create a potential archetype when it is well-formed (e.g., a nested
/// type should exist) and make sure we have complete information about
/// that potential archetype.
@@ -274,10 +270,6 @@
GenericSignatureBuilder(const GenericSignatureBuilder &) = delete;
GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete;
- /// Record that the given potential archetype is unresolved, so we know to
- /// resolve it later.
- void recordUnresolvedType(PotentialArchetype *unresolvedPA);
-
/// When a particular requirement cannot be resolved due to, e.g., a
/// currently-unresolvable or nested type, this routine should be
/// called to cope with the unresolved requirement.
@@ -315,10 +307,6 @@
ProtocolDecl *Proto,
const RequirementSource *Source);
- /// Try to resolve the given unresolved potential archetype.
- ConstraintResult resolveUnresolvedType(PotentialArchetype *pa,
- bool allowTypoCorrection);
-
public:
/// \brief Add a new same-type requirement between two fully resolved types
/// (output of \c GenericSignatureBuilder::resolve).
@@ -567,12 +555,6 @@
ArrayRef<GenericTypeParamType *> genericParams,
bool allowConcreteGenericParams=false);
- /// Diagnose any remaining renames.
- ///
- /// \returns \c true if there were any remaining renames to diagnose.
- bool diagnoseRemainingRenames(SourceLoc loc,
- ArrayRef<GenericTypeParamType *> genericParams);
-
/// Process any delayed requirements that can be handled now.
void processDelayedRequirements();
@@ -1294,21 +1276,14 @@
/// The identifier describing this particular archetype.
///
- /// \c parentOrBuilder determines whether we have a nested type vs. a root,
- /// while `isUnresolvedNestedType` determines whether we have an unresolved
- /// nested type (vs. a resolved one);
+ /// \c parentOrBuilder determines whether we have a nested type vs. a root.
union PAIdentifier {
- /// The name of an unresolved, nested type.
- Identifier name;
-
/// The associated type or typealias for a resolved nested type.
TypeDecl *assocTypeOrConcrete;
/// The generic parameter key for a root.
GenericParamKey genericParam;
- PAIdentifier(Identifier name) : name(name) { }
-
PAIdentifier(AssociatedTypeDecl *assocType)
: assocTypeOrConcrete(assocType) { }
@@ -1357,55 +1332,32 @@
/// that share a name.
llvm::MapVector<Identifier, StoredNestedType> NestedTypes;
- /// Tracks the number of conformances that
- unsigned numConformancesInNestedType = 0;
-
- /// Whether this is an unresolved nested type.
- unsigned isUnresolvedNestedType : 1;
-
/// \brief Recursively conforms to itself.
unsigned IsRecursive : 1;
- /// Whether this potential archetype is invalid, e.g., because it could not
- /// be resolved.
- unsigned Invalid : 1;
-
- /// Whether we have diagnosed a rename.
- unsigned DiagnosedRename : 1;
-
- /// If we have renamed this (nested) type due to typo correction,
- /// the old name.
- Identifier OrigName;
-
/// \brief Construct a new potential archetype for an unresolved
/// associated type.
PotentialArchetype(PotentialArchetype *parent, Identifier name);
/// \brief Construct a new potential archetype for an associated type.
PotentialArchetype(PotentialArchetype *parent, AssociatedTypeDecl *assocType)
- : parentOrBuilder(parent), identifier(assocType),
- isUnresolvedNestedType(false), IsRecursive(false), Invalid(false),
- DiagnosedRename(false)
+ : parentOrBuilder(parent), identifier(assocType), IsRecursive(false)
{
assert(parent != nullptr && "Not an associated type?");
}
/// \brief Construct a new potential archetype for a concrete declaration.
PotentialArchetype(PotentialArchetype *parent, TypeDecl *concreteDecl)
- : parentOrBuilder(parent), identifier(concreteDecl),
- isUnresolvedNestedType(false),
- IsRecursive(false), Invalid(false),
- DiagnosedRename(false)
+ : parentOrBuilder(parent), identifier(concreteDecl), IsRecursive(false)
{
assert(parent != nullptr && "Not an associated type?");
}
/// \brief Construct a new potential archetype for a generic parameter.
- PotentialArchetype(GenericSignatureBuilder *builder, GenericParamKey genericParam)
+ PotentialArchetype(GenericSignatureBuilder *builder,
+ GenericParamKey genericParam)
: parentOrBuilder(builder), identifier(genericParam),
- isUnresolvedNestedType(false),
- IsRecursive(false), Invalid(false),
- DiagnosedRename(false)
+ IsRecursive(false)
{
}
@@ -1441,23 +1393,9 @@
/// has been resolved.
AssociatedTypeDecl *getResolvedAssociatedType() const {
assert(getParent() && "Not an associated type");
- if (isUnresolvedNestedType)
- return nullptr;
-
return dyn_cast<AssociatedTypeDecl>(identifier.assocTypeOrConcrete);
}
- /// Determine whether this PA is still unresolved.
- bool isUnresolved() const { return isUnresolvedNestedType; }
-
- /// Resolve the potential archetype to the given associated type.
- void resolveAssociatedType(AssociatedTypeDecl *assocType,
- GenericSignatureBuilder &builder);
-
- /// Resolve the potential archetype to the given typealias.
- void resolveConcreteType(TypeDecl *concreteDecl,
- GenericSignatureBuilder &builder);
-
/// Determine whether this is a generic parameter.
bool isGenericParam() const {
return parentOrBuilder.is<GenericSignatureBuilder *>();
@@ -1484,18 +1422,12 @@
/// Retrieve the name of a nested potential archetype.
Identifier getNestedName() const {
assert(getParent() && "Not a nested type");
- if (isUnresolvedNestedType)
- return identifier.name;
-
return identifier.assocTypeOrConcrete->getName();
}
/// Retrieve the concrete type declaration.
TypeDecl *getConcreteTypeDecl() const {
assert(getParent() && "not a nested type");
- if (isUnresolvedNestedType)
- return nullptr;
-
if (isa<AssociatedTypeDecl>(identifier.assocTypeOrConcrete))
return nullptr;
@@ -1649,12 +1581,7 @@
///
/// \param genericParams The set of generic parameters to use in the resulting
/// dependent type.
- ///
- /// \param allowUnresolved If true, allow the result to contain
- /// \c DependentMemberType types with a name but no specific associated
- /// type.
- Type getDependentType(ArrayRef<GenericTypeParamType *> genericParams,
- bool allowUnresolved);
+ Type getDependentType(ArrayRef<GenericTypeParamType *> genericParams);
/// True if the potential archetype has been bound by a concrete type
/// constraint.
@@ -1676,32 +1603,6 @@
void setIsRecursive() { IsRecursive = true; }
bool isRecursive() const { return IsRecursive; }
- bool isInvalid() const { return Invalid; }
-
- void setInvalid() { Invalid = true; }
-
- /// Determine whether this archetype was renamed due to typo
- /// correction. If so, \c getName() retrieves the new name.
- bool wasRenamed() const { return !OrigName.empty(); }
-
- /// Note that this potential archetype was is going to be renamed (due to typo
- /// correction), saving the old name.
- void saveNameForRenaming() {
- OrigName = getNestedName();
- }
-
- /// For a renamed potential archetype, retrieve the original name.
- Identifier getOriginalName() const {
- assert(wasRenamed());
- return OrigName;
- }
-
- /// Whether we already diagnosed this rename.
- bool alreadyDiagnosedRename() const { return DiagnosedRename; }
-
- /// Note that we already diagnosed this rename.
- void setAlreadyDiagnosedRename() { DiagnosedRename = true; }
-
LLVM_ATTRIBUTE_DEPRECATED(
void dump() const,
"only for use within the debugger");
@@ -1725,9 +1626,6 @@
/// A same-type requirement.
SameType,
-
- /// An unresolved potential archetype.
- Unresolved,
};
Kind kind;
diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h
index 8486681..0f31173 100644
--- a/include/swift/AST/NameLookup.h
+++ b/include/swift/AST/NameLookup.h
@@ -288,7 +288,8 @@
Type BaseTy,
const DeclContext *CurrDC,
LazyResolver *typeResolver,
- bool includeInstanceMembers);
+ bool includeInstanceMembers,
+ GenericSignatureBuilder *GSB = nullptr);
namespace namelookup {
enum class ResolutionKind {
diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h
index 37d81e5..cbe1b71 100644
--- a/include/swift/AST/ProtocolConformance.h
+++ b/include/swift/AST/ProtocolConformance.h
@@ -469,6 +469,8 @@
/// protocol, which line up with the conformance constraints in the
/// protocol's requirement signature.
ArrayRef<ProtocolConformanceRef> getSignatureConformances() const {
+ if (Resolver)
+ resolveLazyInfo();
return SignatureConformances;
}
diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h
index 9704256..b3da68c 100644
--- a/include/swift/ClangImporter/ClangImporterOptions.h
+++ b/include/swift/ClangImporter/ClangImporterOptions.h
@@ -37,6 +37,9 @@
/// Equivalent to Clang's -mcpu=.
std::string TargetCPU;
+ /// The path to which we should store indexing data, if any.
+ std::string IndexStorePath;
+
/// The bridging header or PCH that will be imported.
std::string BridgingHeader;
diff --git a/include/swift/Driver/Types.def b/include/swift/Driver/Types.def
index 0306909..98cb9b3 100644
--- a/include/swift/Driver/Types.def
+++ b/include/swift/Driver/Types.def
@@ -61,6 +61,10 @@
TYPE("tbd", TBD, "tbd", "")
TYPE("module-trace", ModuleTrace, "trace.json", "")
+// BEGIN APPLE-ONLY OUTPUT TYPES
+TYPE("index-data", IndexData, "", "")
+// END APPLE-ONLY OUTPUT TYPES
+
// Misc types
TYPE("pcm", ClangModuleFile, "pcm", "")
TYPE("pch", PCH, "pch", "")
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 021e27b..92ce827 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -132,6 +132,12 @@
/// The path to collect the group information for the compiled source files.
std::string GroupInfoPath;
+ /// The path to which we should store indexing data, if any.
+ std::string IndexStorePath;
+
+ /// Emit index data for imported serialized swift system modules.
+ bool IndexSystemModules = false;
+
/// If non-zero, warn when a function body takes longer than this many
/// milliseconds to type-check.
///
diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h
index 356eb47..1a2c376 100644
--- a/include/swift/IRGen/Linking.h
+++ b/include/swift/IRGen/Linking.h
@@ -312,8 +312,8 @@
CanType associatedType,
ProtocolDecl *requirement) {
unsigned index = 0;
- for (auto &reqt : conformance->getProtocol()->getRequirementSignature()
- ->getRequirements()) {
+ for (const auto &reqt :
+ conformance->getProtocol()->getRequirementSignature()) {
if (reqt.getKind() == RequirementKind::Conformance &&
reqt.getFirstType()->getCanonicalType() == associatedType &&
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() ==
@@ -328,9 +328,7 @@
static std::pair<CanType, ProtocolDecl*>
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
unsigned index) {
- auto &reqt =
- conformance->getProtocol()->getRequirementSignature()
- ->getRequirements()[index];
+ auto &reqt = conformance->getProtocol()->getRequirementSignature()[index];
assert(reqt.getKind() == RequirementKind::Conformance);
return { reqt.getFirstType()->getCanonicalType(),
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() };
diff --git a/include/swift/Index/IndexRecord.h b/include/swift/Index/IndexRecord.h
new file mode 100644
index 0000000..8ddcb44
--- /dev/null
+++ b/include/swift/Index/IndexRecord.h
@@ -0,0 +1,83 @@
+//===--- IndexRecord.h - Entry point for recording index data ---*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_INDEX_INDEXRECORD_H
+#define SWIFT_INDEX_INDEXRECORD_H
+
+#include "swift/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace swift {
+class DependencyTracker;
+class ModuleDecl;
+class SourceFile;
+
+namespace index {
+
+/// Index the given source file and store the results to \p indexStorePath.
+///
+/// \param primarySourceFile The source file to index.
+///
+/// \param indexUnitToken A unique identifier for this translation unit in the
+/// form of a file path.
+///
+/// \param indexStorePath The location to write the indexing data to.
+///
+/// \param indexSystemModules If true, emit index data for imported serialized
+/// swift system modules.
+///
+/// \param isDebugCompilation true for non-optimized compiler invocation.
+///
+/// \param targetTriple The target for this compilation.
+///
+/// \param dependencyTracker The set of dependencies seen while building.
+bool indexAndRecord(SourceFile *primarySourceFile, StringRef indexUnitToken,
+ StringRef indexStorePath, bool indexSystemModules,
+ bool isDebugCompilation, StringRef targetTriple,
+ const DependencyTracker &dependencyTracker);
+
+/// Index the given module and store the results to \p indexStorePath.
+///
+/// \param module The module to index.
+///
+/// \param indexUnitTokens A list of unique identifiers for the index units to
+/// be written. This may either be one unit per source file of \p module, or it
+/// may be a single unit, in which case all the index information will be
+/// combined into a single unit.
+///
+/// \param moduleUnitToken A unique identifier for this module unit in the form
+/// of a file path. Only used if \p indexUnitTokens are specified for each
+/// source file, otherwise the single \p indexUnitTokens value is used instead.
+///
+/// \param indexStorePath The location to write the indexing data to.
+///
+/// \param indexSystemModules If true, emit index data for imported serialized
+/// swift system modules.
+///
+/// \param isDebugCompilation true for non-optimized compiler invocation.
+///
+/// \param targetTriple The target for this compilation.
+///
+/// \param dependencyTracker The set of dependencies seen while building.
+bool indexAndRecord(ModuleDecl *module, ArrayRef<std::string> indexUnitTokens,
+ StringRef moduleUnitToken, StringRef indexStorePath,
+ bool indexSystemModules, bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker);
+// FIXME: indexUnitTokens could be StringRef, but that creates an impedance
+// mismatch in the caller.
+
+} // end namespace index
+} // end namespace swift
+
+#endif // SWIFT_INDEX_INDEXRECORD_H
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 4bc4968..d814367 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -414,6 +414,9 @@
HelpText<"Use the pass pipeline defined by <pass_pipeline_file>">,
MetaVarName<"<pass_pipeline_file>">;
+def index_system_modules : Flag<["-"], "index-system-modules">,
+ HelpText<"Emit index data for imported serialized swift system modules">;
+
def dump_interface_hash : Flag<["-"], "dump-interface-hash">,
HelpText<"Parse input file(s) and dump interface token hash(es)">,
ModeOpt;
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 73b9261..2bdbe29 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -646,6 +646,18 @@
HelpText<"Specify the type of coverage instrumentation for Sanitizers and"
" additional options separated by commas">;
+def index_file : Flag<["-"], "index-file">,
+ HelpText<"Produce index data for a source file">, ModeOpt,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
+def index_file_path : Separate<["-"], "index-file-path">,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ HelpText<"Produce index data for file <path>">,
+ MetaVarName<"<path>">;
+
+def index_store_path : Separate<["-"], "index-store-path">,
+ Flags<[FrontendOption]>, MetaVarName<"<path>">,
+ HelpText<"Store indexing data to <path>">;
+
def enforce_exclusivity_EQ : Joined<["-"], "enforce-exclusivity=">,
Flags<[FrontendOption]>, MetaVarName<"<enforcement>">,
HelpText<"Enforce law of exclusivity">;
diff --git a/include/swift/Option/SanitizerOptions.h b/include/swift/Option/SanitizerOptions.h
index f6d2360..2498b0e 100644
--- a/include/swift/Option/SanitizerOptions.h
+++ b/include/swift/Option/SanitizerOptions.h
@@ -28,7 +28,7 @@
/// \brief Parses a -sanitize= argument's values.
///
/// \param Diag If non null, the argument is used to diagnose invalid values.
-/// \param sanitizerRuntimeLibExists Function which checks for existance of a
+/// \param sanitizerRuntimeLibExists Function which checks for existence of a
// sanitizer dylib with a given name.
/// \return Returns a SanitizerKind.
SanitizerKind parseSanitizerArgValues(
diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h
index 2d7a40c..5cf71dc 100644
--- a/include/swift/Parse/Parser.h
+++ b/include/swift/Parse/Parser.h
@@ -977,15 +977,11 @@
/// Any declaration attributes attached to the parameter.
DeclAttributes Attrs;
- /// The location of the 'let', 'var', or 'inout' keyword, if present.
- SourceLoc LetVarInOutLoc;
-
- enum SpecifierKindTy {
- Let,
- Var,
- InOut
- };
- SpecifierKindTy SpecifierKind = Let; // Defaults to let.
+ /// The location of the 'inout' keyword, if present.
+ SourceLoc SpecifierLoc;
+
+ /// The parsed specifier kind, if present.
+ VarDecl::Specifier SpecifierKind = VarDecl::Specifier::None;
/// The location of the first name.
///
@@ -1097,7 +1093,8 @@
bool isExprBasic);
- Pattern *createBindingFromPattern(SourceLoc loc, Identifier name, bool isLet);
+ Pattern *createBindingFromPattern(SourceLoc loc, Identifier name,
+ VarDecl::Specifier specifier);
/// \brief Determine whether this token can only start a matching pattern
diff --git a/include/swift/SIL/SILWitnessVisitor.h b/include/swift/SIL/SILWitnessVisitor.h
index 0c86079..bffa77a 100644
--- a/include/swift/SIL/SILWitnessVisitor.h
+++ b/include/swift/SIL/SILWitnessVisitor.h
@@ -64,8 +64,7 @@
}
};
- for (auto &reqt : protocol->getRequirementSignature()
- ->getCanonicalSignature()->getRequirements()) {
+ for (const auto &reqt : protocol->getRequirementSignature()) {
switch (reqt.getKind()) {
// These requirements don't show up in the witness table.
case RequirementKind::Superclass:
@@ -74,10 +73,11 @@
continue;
case RequirementKind::Conformance: {
- auto type = CanType(reqt.getFirstType());
+ auto type = reqt.getFirstType()->getCanonicalType();
assert(type->isTypeParameter());
auto requirement =
- cast<ProtocolType>(CanType(reqt.getSecondType()))->getDecl();
+ cast<ProtocolType>(reqt.getSecondType()->getCanonicalType())
+ ->getDecl();
// ObjC protocols do not have witnesses.
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(requirement))
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index a90a8d2..9910471 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 = 347; // Last change: 'inout' on parameter types
+const uint16_t VERSION_MINOR = 348; // Last change: 'inout' in parameter decls.
using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
@@ -191,6 +191,15 @@
// These IDs must \em not be renumbered or reordered without incrementing
// VERSION_MAJOR.
+enum class VarDeclSpecifier : uint8_t {
+ Let = 0,
+ Var,
+ InOut,
+};
+using VarDeclSpecifierField = BCFixed<2>;
+
+// These IDs must \em not be renumbered or reordered without incrementing
+// VERSION_MAJOR.
enum class ParameterConvention : uint8_t {
Indirect_In,
Indirect_Inout,
@@ -227,7 +236,7 @@
NotAddressor, Unsafe, Owning, NativeOwning, NativePinning
};
using AddressorKindField = BCFixed<3>;
-
+
/// Translates an operator DeclKind to a Serialization fixity, whose values are
/// guaranteed to be stable.
static inline OperatorKind getStableFixity(DeclKind kind) {
@@ -876,7 +885,7 @@
BCFixed<1>, // implicit?
BCFixed<1>, // explicitly objc?
BCFixed<1>, // static?
- BCFixed<1>, // isLet?
+ VarDeclSpecifierField, // specifier
BCFixed<1>, // HasNonPatternBindingInit?
StorageKindField, // StorageKind
TypeIDField, // interface type
@@ -898,7 +907,7 @@
IdentifierIDField, // argument name
IdentifierIDField, // parameter name
DeclContextIDField, // context decl
- BCFixed<1>, // isLet?
+ VarDeclSpecifierField, // specifier
TypeIDField // interface type
>;
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index af4e858..75cc493 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -676,7 +676,9 @@
OS << " requirement signature=";
if (PD->isRequirementSignatureComputed()) {
- OS << PD->getRequirementSignature()->getAsString();
+ OS << GenericSignature::get({PD->getProtocolSelfType()} ,
+ PD->getRequirementSignature())
+ ->getAsString();
} else {
OS << "<null>";
}
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index b845ca2..c614e7f 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -1367,7 +1367,9 @@
if (isa<AssociatedTypeDecl>(attachingTo))
flags |= SwapSelfAndDependentMemberType;
printGenericSignature(
- proto->getRequirementSignature(), flags,
+ GenericSignature::get({proto->getProtocolSelfType()} ,
+ proto->getRequirementSignature()),
+ flags,
[&](const Requirement &req) {
auto location = bestRequirementPrintLocation(proto, req);
return location.AttachedTo == attachingTo && location.InWhereClause;
diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
index 8bd66bc..72b71c7 100644
--- a/lib/AST/ASTVerifier.cpp
+++ b/lib/AST/ASTVerifier.cpp
@@ -2348,7 +2348,7 @@
if (!normal->isInvalid()){
auto conformances = normal->getSignatureConformances();
unsigned idx = 0;
- for (auto req : proto->getRequirementSignature()->getRequirements()) {
+ for (const auto &req : proto->getRequirementSignature()) {
if (req.getKind() != RequirementKind::Conformance)
continue;
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index c2f28ec..755517c 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -158,7 +158,7 @@
SmallVector<ParamDecl*, 4> params;
for (Type argType : argTypes) {
- auto PD = new (Context) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(),
+ auto PD = new (Context) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
Identifier(), SourceLoc(),
Identifier(), argType,
DC);
@@ -217,7 +217,7 @@
for (unsigned i = 0, e = ArgParamTypes.size(); i < e; i++) {
auto paramType = ArgBodyTypes[i];
auto paramIfaceType = ArgParamTypes[i].getType();
- auto PD = new (Context) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(),
+ auto PD = new (Context) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
Identifier(), SourceLoc(),
Identifier(), paramType, DC);
PD->setInterfaceType(paramIfaceType);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 9857e63..cd3c392 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1681,7 +1681,7 @@
if (auto funcTy = signature.InterfaceType->getAs<AnyFunctionType>()) {
signature.InterfaceType
= GenericFunctionType::get(genericSig,
- funcTy->getInput(),
+ funcTy->getParams(),
funcTy->getResult(),
funcTy->getExtInfo())
->getCanonicalType();
@@ -2861,10 +2861,11 @@
ProtocolDeclBits.RequiresClass = false;
ProtocolDeclBits.ExistentialConformsToSelfValid = false;
ProtocolDeclBits.ExistentialConformsToSelf = false;
- KnownProtocol = 0;
ProtocolDeclBits.Circularity
= static_cast<unsigned>(CircularityCheck::Unchecked);
HasMissingRequirements = false;
+ KnownProtocol = 0;
+ NumRequirementsInSignature = 0;
}
llvm::TinyPtrVector<ProtocolDecl *>
@@ -2895,7 +2896,7 @@
// Gather inherited protocols from the requirement signature.
auto selfType = getProtocolSelfType();
- for (auto req : getRequirementSignature()->getRequirements()) {
+ for (const auto &req : getRequirementSignature()) {
if (req.getKind() == RequirementKind::Conformance &&
req.getFirstType()->isEqual(selfType))
result.push_back(req.getSecondType()->castTo<ProtocolType>()->getDecl());
@@ -3020,9 +3021,8 @@
// Tuples preserve variance.
if (auto tuple = type->getAs<TupleType>()) {
auto kind = SelfReferenceKind::None();
- for (auto &elt: tuple->getElements()) {
- kind |= findProtocolSelfReferences(proto, elt.getType(),
- skipAssocTypes);
+ for (auto &elt : tuple->getElements()) {
+ kind |= findProtocolSelfReferences(proto, elt.getType(), skipAssocTypes);
}
return kind;
}
@@ -3030,8 +3030,11 @@
// Function preserve variance in the result type, and flip variance in
// the parameter type.
if (auto funcTy = type->getAs<AnyFunctionType>()) {
- auto inputKind = findProtocolSelfReferences(proto, funcTy->getInput(),
- skipAssocTypes);
+ auto inputKind = SelfReferenceKind::None();
+ for (auto &elt : funcTy->getParams()) {
+ inputKind |= findProtocolSelfReferences(proto, elt.getType(),
+ skipAssocTypes);
+ }
auto resultKind = findProtocolSelfReferences(proto, funcTy->getResult(),
skipAssocTypes);
@@ -3299,8 +3302,23 @@
GenericSignatureBuilder::RequirementSource
::forRequirementSignature(selfPA, this),
nullptr);
-
- RequirementSignature = builder.computeGenericSignature(SourceLoc());
+
+ // Compute and record the signature.
+ auto requirementSig = builder.computeGenericSignature(SourceLoc());
+ RequirementSignature = requirementSig->getRequirements().data();
+ assert(RequirementSignature != nullptr);
+ NumRequirementsInSignature = requirementSig->getRequirements().size();
+}
+
+void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
+ assert(!RequirementSignature && "already computed requirement signature");
+ if (requirements.empty()) {
+ RequirementSignature = reinterpret_cast<Requirement *>(this + 1);
+ NumRequirementsInSignature = 0;
+ } else {
+ RequirementSignature = getASTContext().AllocateCopy(requirements).data();
+ NumRequirementsInSignature = requirements.size();
+ }
}
/// Returns the default witness for a requirement, or nullptr if there is
@@ -4113,25 +4131,27 @@
}
}
-ParamDecl::ParamDecl(bool isLet,
- SourceLoc letVarInOutLoc, SourceLoc argumentNameLoc,
+ParamDecl::ParamDecl(Specifier specifier,
+ SourceLoc specifierLoc, SourceLoc argumentNameLoc,
Identifier argumentName, SourceLoc parameterNameLoc,
Identifier parameterName, Type ty, DeclContext *dc)
- : VarDecl(DeclKind::Param, /*IsStatic*/false, /*IsLet*/isLet,
+ : VarDecl(DeclKind::Param, /*IsStatic*/false, specifier,
/*IsCaptureList*/false, parameterNameLoc, parameterName, ty, dc),
ArgumentName(argumentName), ArgumentNameLoc(argumentNameLoc),
- LetVarInOutLoc(letVarInOutLoc) {
+ SpecifierLoc(specifierLoc) {
+ assert(specifier != Specifier::Var &&
+ "'var' cannot appear on parameters; you meant 'inout'");
}
/// Clone constructor, allocates a new ParamDecl identical to the first.
/// Intentionally not defined as a copy constructor to avoid accidental copies.
ParamDecl::ParamDecl(ParamDecl *PD)
- : VarDecl(DeclKind::Param, /*IsStatic*/false, /*IsLet*/PD->isLet(),
+ : VarDecl(DeclKind::Param, /*IsStatic*/false, PD->getSpecifier(),
/*IsCaptureList*/false, PD->getNameLoc(), PD->getName(),
PD->hasType() ? PD->getType() : Type(), PD->getDeclContext()),
ArgumentName(PD->getArgumentName()),
ArgumentNameLoc(PD->getArgumentNameLoc()),
- LetVarInOutLoc(PD->getLetVarInOutLoc()),
+ SpecifierLoc(PD->getSpecifierLoc()),
DefaultValueAndIsVariadic(nullptr, PD->DefaultValueAndIsVariadic.getInt()),
IsTypeLocImplicit(PD->IsTypeLocImplicit),
defaultArgumentKind(PD->defaultArgumentKind) {
@@ -4172,7 +4192,7 @@
/// generic parameters.
ParamDecl *ParamDecl::createUnboundSelf(SourceLoc loc, DeclContext *DC) {
ASTContext &C = DC->getASTContext();
- auto *selfDecl = new (C) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(),
+ auto *selfDecl = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
Identifier(), loc, C.Id_self, Type(), DC);
selfDecl->setImplicit();
return selfDecl;
@@ -4192,6 +4212,7 @@
ASTContext &C = DC->getASTContext();
auto selfType = DC->getSelfTypeInContext();
auto selfInterfaceType = DC->getSelfInterfaceType();
+ auto specifier = VarDecl::Specifier::None;
assert(selfType && selfInterfaceType);
if (isStaticMethod) {
@@ -4202,9 +4223,10 @@
if (isInOut) {
selfType = InOutType::get(selfType);
selfInterfaceType = InOutType::get(selfInterfaceType);
+ specifier = VarDecl::Specifier::InOut;
}
- auto *selfDecl = new (C) ParamDecl(/*IsLet*/!isInOut, SourceLoc(),SourceLoc(),
+ auto *selfDecl = new (C) ParamDecl(specifier, SourceLoc(),SourceLoc(),
Identifier(), loc, C.Id_self, selfType,DC);
selfDecl->setImplicit();
selfDecl->setInterfaceType(selfInterfaceType);
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index 95bd2af..0ab5f82 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -105,14 +105,6 @@
GenericTypeParamType *DeclContext::getProtocolSelfType() const {
assert(getAsProtocolOrProtocolExtensionContext() && "not a protocol");
- // FIXME: This comes up when the extension didn't resolve,
- // and we have a protocol nested inside that extension
- // (which is not allowed in the first place).
- //
- // Handle this more systematically elsewhere.
- if (!isInnermostContextGeneric())
- return nullptr;
-
return getGenericParamsOfContext()->getParams().front()
->getDeclaredInterfaceType()
->castTo<GenericTypeParamType>();
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 5c5a50f..9870f8f 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -709,7 +709,7 @@
return getCanonicalTypeInContext(rep->getConcreteType(), builder);
}
- return rep->getDependentType(getGenericParams(), /*allowUnresolved*/ false);
+ return rep->getDependentType(getGenericParams());
});
auto result = type->getCanonicalType();
@@ -793,13 +793,13 @@
#ifndef NDEBUG
// Local function to determine whether there is a conformance of the given
- // subject type to the given protocol within the given generic signature's
- // explicit requirements.
- auto hasConformanceInSignature = [&](const GenericSignature *genericSig,
+ // subject type to the given protocol within the given set of explicit
+ // requirements.
+ auto hasConformanceInSignature = [&](ArrayRef<Requirement> requirements,
Type subjectType,
ProtocolDecl *proto) -> bool {
// Make sure this requirement exists in the requirement signature.
- for (const auto& req: genericSig->getRequirements()) {
+ for (const auto& req: requirements) {
if (req.getKind() == RequirementKind::Conformance &&
req.getFirstType()->isEqual(subjectType) &&
req.getSecondType()->castTo<ProtocolType>()->getDecl()
@@ -814,16 +814,27 @@
// Local function to construct the conformance access path from the
// requirement.
- std::function<void(GenericSignature *, const RequirementSource *,
- ProtocolDecl *, Type)> buildPath;
- buildPath = [&](GenericSignature *sig, const RequirementSource *source,
- ProtocolDecl *conformingProto, Type rootType) {
+ std::function<void(ArrayRef<Requirement>, const RequirementSource *,
+ ProtocolDecl *, Type, ProtocolDecl *)> buildPath;
+ buildPath = [&](ArrayRef<Requirement> reqs, const RequirementSource *source,
+ ProtocolDecl *conformingProto, Type rootType,
+ ProtocolDecl *requirementSignatureProto) {
// Each protocol requirement is a step along the path.
if (source->isProtocolRequirement()) {
+ // If we're expanding for a protocol that has no requirement signature
+ // (yet) and have hit the penultimate step, this is the last step
+ // that would occur in the requirement signature.
+ if (!source->parent->parent && requirementSignatureProto) {
+ Type subjectType = source->getStoredType()->getCanonicalType();
+ path.path.push_back({subjectType, conformingProto});
+ return;
+ }
+
// Follow the rest of the path to derive the conformance into which
// this particular protocol requirement step would look.
auto inProtocol = source->getProtocolDecl();
- buildPath(sig, source->parent, inProtocol, rootType);
+ buildPath(reqs, source->parent, inProtocol, rootType,
+ requirementSignatureProto);
assert(path.path.back().second == inProtocol &&
"path produces incorrect conformance");
@@ -857,11 +868,10 @@
"missing signature");
}
- // Get a generic signature builder for the requirement signature. This has
- // the requirement we need.
- auto reqSig = inProtocol->getRequirementSignature();
- auto &reqSigBuilder = *reqSig->getGenericSignatureBuilder(
- *inProtocol->getModuleContext());
+ // Get a generic signature for the protocol's signature.
+ auto inProtoSig = inProtocol->getGenericSignature();
+ auto &inProtoSigBuilder = *inProtoSig->getGenericSignatureBuilder(
+ *inProtocol->getModuleContext());
// Retrieve the stored type, but erase all of the specific associated
// type declarations; we don't want any details of the enclosing context
@@ -870,9 +880,9 @@
// Dig out the potential archetype for this stored type.
auto pa =
- reqSigBuilder.resolveArchetype(
+ inProtoSigBuilder.resolveArchetype(
storedType,
- ArchetypeResolutionKind::AlwaysPartial);
+ ArchetypeResolutionKind::WellFormed);
auto equivClass = pa->getOrCreateEquivalenceClass();
// Find the conformance of this potential archetype to the protocol in
@@ -881,17 +891,17 @@
assert(conforms != equivClass->conformsTo.end());
// Compute the root type, canonicalizing it w.r.t. the protocol context.
- auto inProtoSig = inProtocol->getGenericSignature();
auto conformsSource = getBestRequirementSource(conforms->second);
+ assert(conformsSource != source || !requirementSignatureProto);
Type localRootType = conformsSource->getRootPotentialArchetype()
- ->getDependentType(inProtoSig->getGenericParams(),
- /*allowUnresolved*/true);
+ ->getDependentType(inProtoSig->getGenericParams());
localRootType = inProtoSig->getCanonicalTypeInContext(
localRootType,
*inProtocol->getModuleContext());
// Build the path according to the requirement signature.
- buildPath(reqSig, conformsSource, conformingProto, localRootType);
+ buildPath(inProtocol->getRequirementSignature(), conformsSource,
+ conformingProto, localRootType, inProtocol);
// We're done.
return;
@@ -899,7 +909,8 @@
// If we still have a parent, keep going.
if (source->parent) {
- buildPath(sig, source->parent, conformingProto, rootType);
+ buildPath(reqs, source->parent, conformingProto, rootType,
+ requirementSignatureProto);
return;
}
@@ -914,7 +925,7 @@
rootType->isEqual(conformingProto->getSelfInterfaceType()))
return;
- assert(hasConformanceInSignature(sig, rootType, conformingProto) &&
+ assert(hasConformanceInSignature(reqs, rootType, conformingProto) &&
"missing explicit conformance in signature");
// Add the root of the path, which starts at this explicit requirement.
@@ -925,11 +936,10 @@
auto source = getBestRequirementSource(conforms->second);
auto subjectPA = source->getRootPotentialArchetype();
subjectPA = subjectPA->getArchetypeAnchor(*subjectPA->getBuilder());
- Type rootType = subjectPA->getDependentType(getGenericParams(),
- /*allowUnresolved=*/false);
+ Type rootType = subjectPA->getDependentType(getGenericParams());
// Build the path.
- buildPath(this, source, protocol, rootType);
+ buildPath(getRequirements(), source, protocol, rootType, nullptr);
// Return the path; we're done!
return path;
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 05574b7..981d26e 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -85,9 +85,6 @@
/// The potential archetypes for the generic parameters in \c GenericParams.
SmallVector<PotentialArchetype *, 4> PotentialArchetypes;
- /// The nested types that have been renamed.
- SmallVector<PotentialArchetype *, 4> RenamedNestedTypes;
-
/// The requirement sources used in this generic signature builder.
llvm::FoldingSet<RequirementSource> RequirementSources;
@@ -1100,16 +1097,6 @@
return false;
}
-PotentialArchetype::PotentialArchetype(PotentialArchetype *parent,
- Identifier name)
- : parentOrBuilder(parent), identifier(name), isUnresolvedNestedType(true),
- IsRecursive(false), Invalid(false),
- DiagnosedRename(false)
-{
- assert(parent != nullptr && "Not an associated type?");
- getBuilder()->recordUnresolvedType(this);
-}
-
GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() {
++NumPotentialArchetypes;
@@ -1167,24 +1154,6 @@
return Depth;
}
-void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType(
- AssociatedTypeDecl *assocType,
- GenericSignatureBuilder &builder) {
- assert(isUnresolvedNestedType && "associated type is already resolved");
- isUnresolvedNestedType = false;
- identifier.assocTypeOrConcrete = assocType;
- assert(assocType->getName() == getNestedName());
-}
-
-void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType(
- TypeDecl *concreteDecl,
- GenericSignatureBuilder &builder) {
- assert(isUnresolvedNestedType && "nested type is already resolved");
- isUnresolvedNestedType = false;
- identifier.assocTypeOrConcrete = concreteDecl;
- assert(concreteDecl->getName() == getNestedName());
-}
-
Optional<ConcreteConstraint>
EquivalenceClass::findAnyConcreteConstraintAsWritten(
PotentialArchetype *preferredPA) const {
@@ -1281,13 +1250,6 @@
dump(llvm::errs());
}
-void GenericSignatureBuilder::recordUnresolvedType(
- PotentialArchetype *unresolvedPA) {
- Impl->DelayedRequirements.push_back(
- {DelayedRequirement::Unresolved, unresolvedPA, RequirementRHS(),
- FloatingRequirementSource::forAbstract()});
-}
-
ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement(
RequirementKind kind,
UnresolvedType lhs,
@@ -1338,8 +1300,7 @@
// Lookup the conformance of the concrete type to this protocol.
auto conformance =
- getLookupConformanceFn()(pa->getDependentType({ }, /*allowUnresolved=*/true)
- ->getCanonicalType(),
+ getLookupConformanceFn()(pa->getDependentType({ })->getCanonicalType(),
concrete,
proto->getDeclaredInterfaceType()
->castTo<ProtocolType>());
@@ -1369,8 +1330,7 @@
// Lookup the conformance of the superclass to this protocol.
auto conformance =
- getLookupConformanceFn()(pa->getDependentType({ }, /*allowUnresolved=*/true)
- ->getCanonicalType(),
+ getLookupConformanceFn()(pa->getDependentType({ })->getCanonicalType(),
superclass,
proto->getDeclaredInterfaceType()
->castTo<ProtocolType>());
@@ -1643,17 +1603,6 @@
return result;
}
- // Along the error path where one or both of the potential archetypes was
- // renamed due to typo correction,
- if (a->wasRenamed() || b->wasRenamed()) {
- if (a->wasRenamed() != b->wasRenamed())
- return a->wasRenamed() ? +1 : -1;
-
- if (int compareNames = a->getOriginalName().str().compare(
- b->getOriginalName().str()))
- return compareNames;
- }
-
llvm_unreachable("potential archetype total order failure");
}
@@ -1895,38 +1844,7 @@
resultPA = concreteDeclPA;
}
- if (resultPA)
- return resultPA;
-
- // Check whether we can add a missing nested type for this case.
- switch (kind) {
- case ArchetypeResolutionKind::AlwaysPartial:
- break;
-
- case ArchetypeResolutionKind::WellFormed:
- case ArchetypeResolutionKind::CompleteWellFormed:
- case ArchetypeResolutionKind::AlreadyKnown:
- return nullptr;
- }
-
- // Build an unresolved type if we don't have one yet.
- auto &nested = NestedTypes[name];
- if (nested.empty()) {
- nested.push_back(new PotentialArchetype(this, name));
-
- auto rep = getRepresentative();
- if (rep != this) {
- auto existingPA = rep->getNestedType(name, kind, builder);
-
- auto sameNamedSource =
- RequirementSource::forNestedTypeNameMatch(existingPA);
- builder.addSameTypeRequirement(
- existingPA, nested.back(), sameNamedSource,
- UnresolvedHandlingKind::GenerateConstraints);
- }
- }
-
- return nested.front();
+ return resultPA;
}
@@ -1987,20 +1905,6 @@
auto &builder = *getBuilder();
if (knownNestedTypes != NestedTypes.end()) {
for (auto existingPA : knownNestedTypes->second) {
- // Resolve an unresolved potential archetype.
- if (existingPA->isUnresolvedNestedType) {
- if (assocType) {
- existingPA->resolveAssociatedType(assocType, builder);
- } else {
- existingPA->resolveConcreteType(concreteDecl, builder);
- }
-
- // We've resolved this nested type; nothing more to do.
- resultPA = existingPA;
- shouldUpdatePA = true;
- break;
- }
-
// Do we have an associated-type match?
if (assocType && existingPA->getResolvedAssociatedType() == assocType) {
resultPA = existingPA;
@@ -2018,7 +1922,6 @@
// If we don't have a result potential archetype yet, we may need to add one.
if (!resultPA) {
switch (kind) {
- case ArchetypeResolutionKind::AlwaysPartial:
case ArchetypeResolutionKind::CompleteWellFormed:
case ArchetypeResolutionKind::WellFormed: {
if (assocType)
@@ -2087,8 +1990,7 @@
// Substitute in the type of the current PotentialArchetype in
// place of 'Self' here.
auto subMap = SubstitutionMap::getProtocolSubstitutions(
- proto, getDependentType(/*genericParams=*/{},
- /*allowUnresolved=*/true),
+ proto, getDependentType(/*genericParams=*/{}),
ProtocolConformanceRef(proto));
type = type.subst(subMap, SubstFlags::UseErrorType);
} else {
@@ -2153,8 +2055,7 @@
// If this has a recursive type, return an error type.
auto equivClass = representative->getEquivalenceClassIfPresent();
if (equivClass->recursiveConcreteType) {
- return ErrorType::get(getDependentType(genericParams,
- /*allowUnresolved=*/true));
+ return ErrorType::get(getDependentType(genericParams));
}
return genericEnv->mapTypeIntoContext(concreteType,
@@ -2181,8 +2082,7 @@
// proper nested type.
auto parentTy = parent->getTypeInContext(builder, genericEnv);
if (!parentTy)
- return ErrorType::get(getDependentType(genericParams,
- /*allowUnresolved=*/true));
+ return ErrorType::get(getDependentType(genericParams));
ParentArchetype = parentTy->getAs<ArchetypeType>();
if (!ParentArchetype) {
@@ -2191,7 +2091,7 @@
(void) resolver;
// Resolve the member type.
- auto type = getDependentType(genericParams, /*allowUnresolved=*/false);
+ auto type = getDependentType(genericParams);
if (type->hasError())
return type;
@@ -2270,8 +2170,7 @@
// If we were unable to resolve this as an associated type, produce an
// error type.
if (!assocType) {
- return ErrorType::get(getDependentType(genericParams,
- /*allowUnresolved=*/true));
+ return ErrorType::get(getDependentType(genericParams));
}
// Create a nested archetype.
@@ -2316,11 +2215,9 @@
}
Type GenericSignatureBuilder::PotentialArchetype::getDependentType(
- ArrayRef<GenericTypeParamType *> genericParams,
- bool allowUnresolved) {
+ ArrayRef<GenericTypeParamType *> genericParams){
if (auto parent = getParent()) {
- Type parentType = parent->getDependentType(genericParams,
- allowUnresolved);
+ Type parentType = parent->getDependentType(genericParams);
if (parentType->hasError())
return parentType;
@@ -2328,11 +2225,6 @@
if (auto assocType = getResolvedAssociatedType())
return DependentMemberType::get(parentType, assocType);
- // If we don't allow unresolved dependent member types, fail.
- if (!allowUnresolved)
- return ErrorType::get(getDependentType(genericParams,
- /*allowUnresolved=*/true));
-
return DependentMemberType::get(parentType, getNestedName());
}
@@ -2530,7 +2422,7 @@
// Determine what kind of resolution we want.
ArchetypeResolutionKind resolutionKind =
- ArchetypeResolutionKind::AlwaysPartial;
+ ArchetypeResolutionKind::WellFormed;
if (!source.isExplicit() && source.isRecursive(type, *this))
resolutionKind = ArchetypeResolutionKind::AlreadyKnown;
@@ -2620,7 +2512,7 @@
if (!PAT->addConformance(Proto, Source, *this))
return ConstraintResult::Resolved;
- auto concreteSelf = PAT->getDependentType({}, /*allowUnresolved=*/true);
+ auto concreteSelf = PAT->getDependentType({});
auto protocolSubMap = SubstitutionMap::getProtocolSubstitutions(
Proto, concreteSelf, ProtocolConformanceRef(Proto));
@@ -2628,12 +2520,10 @@
// cannot compute the requirement signature directly, because that may be
// infinitely recursive: this code is also used to construct it.
if (Proto->isRequirementSignatureComputed()) {
- auto reqSig = Proto->getRequirementSignature();
-
auto innerSource =
FloatingRequirementSource::viaProtocolRequirement(Source, Proto,
/*inferred=*/false);
- for (auto req : reqSig->getRequirements()) {
+ for (const auto &req : Proto->getRequirementSignature()) {
auto reqResult = addRequirement(req, innerSource, nullptr,
&protocolSubMap);
if (isErrorResult(reqResult)) return reqResult;
@@ -2904,101 +2794,6 @@
return ConstraintResult::Resolved;
}
-/// Perform typo correction on the given nested type, producing the
-/// corrected name (if successful).
-static AssociatedTypeDecl *typoCorrectNestedType(
- GenericSignatureBuilder::PotentialArchetype *pa) {
- StringRef name = pa->getNestedName().str();
-
- // Look through all of the associated types of all of the protocols
- // to which the parent conforms.
- llvm::SmallVector<AssociatedTypeDecl *, 2> bestMatches;
- unsigned bestEditDistance = UINT_MAX;
- unsigned maxScore = (name.size() + 1) / 3;
- for (auto proto : pa->getParent()->getConformsTo()) {
- for (auto member : getProtocolMembers(proto)) {
- auto assocType = dyn_cast<AssociatedTypeDecl>(member);
- if (!assocType)
- continue;
-
- unsigned dist = name.edit_distance(assocType->getName().str(),
- /*AllowReplacements=*/true,
- maxScore);
- assert(dist > 0 && "nested type should have matched associated type");
- if (dist < bestEditDistance) {
- maxScore = bestEditDistance = dist;
- bestMatches.clear();
- }
- if (dist == bestEditDistance)
- bestMatches.push_back(assocType);
- }
- }
-
- // FIXME: Look through the superclass.
-
- // If we didn't find any matches at all, fail.
- if (bestMatches.empty())
- return nullptr;
-
- // Make sure that we didn't find more than one match at the best
- // edit distance.
- for (auto other : llvm::makeArrayRef(bestMatches).slice(1)) {
- if (other != bestMatches.front())
- return nullptr;
- }
-
- return bestMatches.front();
-}
-
-ConstraintResult GenericSignatureBuilder::resolveUnresolvedType(
- PotentialArchetype *pa,
- bool allowTypoCorrection) {
- // If something else resolved this type, we're done.
- if (!pa->isUnresolved())
- return ConstraintResult::Resolved;
-
- // If the parent isn't resolved, we can't resolve this now.
- auto parentPA = pa->getParent();
- if (parentPA->isUnresolved())
- return ConstraintResult::Unresolved;
-
- // Resolve this via its parent.
- auto resolvedPA =
- parentPA->getNestedArchetypeAnchor(
- pa->getNestedName(),
- *this,
- ArchetypeResolutionKind::WellFormed);
- if (resolvedPA) {
- assert(!pa->isUnresolved() && "This type must have been resolved");
- return ConstraintResult::Resolved;
- }
-
- // If we aren't allowed to perform typo correction, we can't resolve the
- // constraint.
- if (!allowTypoCorrection)
- return ConstraintResult::Unresolved;
-
- // Try to typo correct to a nested type name.
- auto correction = typoCorrectNestedType(pa);
- if (!correction) {
- pa->setInvalid();
- return ConstraintResult::Conflicting;
- }
-
- // Note that this is being renamed.
- pa->saveNameForRenaming();
- Impl->RenamedNestedTypes.push_back(pa);
-
- // Resolve the associated type and merge the potential archetypes.
- auto replacement = pa->getParent()->getNestedType(correction, *this);
- pa->resolveAssociatedType(correction, *this);
- addSameTypeRequirement(pa, replacement,
- RequirementSource::forNestedTypeNameMatch(pa),
- UnresolvedHandlingKind::GenerateConstraints);
-
- return ConstraintResult::Resolved;
-}
-
ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect(
PotentialArchetype *PAT,
LayoutConstraint Layout,
@@ -3084,24 +2879,11 @@
}
};
- // Local function to resolve nested types found in the superclass.
- auto updateSuperclassNestedTypes = [&] {
- for (auto &nested : T->getNestedTypes()) {
- if (nested.second.empty()) continue;
- if (nested.second.front()->isUnresolved()) {
- (void)T->getNestedArchetypeAnchor(
- nested.first, *this,
- ArchetypeResolutionKind::AlreadyKnown);
- }
- }
- };
-
// If we haven't yet recorded a superclass constraint for this equivalence
// class, do so now.
if (!equivClass->superclass) {
equivClass->superclass = superclass;
updateSuperclassConformances();
- updateSuperclassNestedTypes();
// Presence of a superclass constraint implies a _Class layout
// constraint.
@@ -3133,7 +2915,6 @@
// We've strengthened the bound, so update superclass conformances.
updateSuperclassConformances();
- updateSuperclassNestedTypes();
return;
}
@@ -3180,9 +2961,7 @@
if (auto constraintPA = resolvedConstraint->getPotentialArchetype()) {
// The constraint type isn't a statically-known constraint.
if (source.getLoc().isValid()) {
- auto constraintType =
- constraintPA->getDependentType(Impl->GenericParams,
- /*allowUnresolved=*/true);
+ auto constraintType = constraintPA->getDependentType(Impl->GenericParams);
Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
1, TypeLoc::withoutLoc(constraintType), 0);
}
@@ -3199,8 +2978,7 @@
auto subjectType = subject.dyn_cast<Type>();
if (!subjectType)
subjectType = subject.get<PotentialArchetype *>()
- ->getDependentType(Impl->GenericParams,
- /*allowUnresolved=*/true);
+ ->getDependentType(Impl->GenericParams);
Diags.diagnose(source.getLoc(), diag::requires_conformance_nonprotocol,
TypeLoc::withoutLoc(subjectType),
@@ -3399,7 +3177,7 @@
}
// Recursively merge the associated types of T2 into T1.
- auto dependentT1 = T1->getDependentType({ }, /*allowUnresolved=*/true);
+ auto dependentT1 = T1->getDependentType({ });
for (auto equivT2 : equivClass2Members) {
for (auto T2Nested : equivT2->NestedTypes) {
// If T1 is concrete but T2 is not, concretize the nested types of T2.
@@ -4118,8 +3896,7 @@
equivClass->findAnyConcreteConstraintAsWritten()) {
Diags.diagnose(constraint->source->getLoc(),
diag::recursive_same_type_constraint,
- archetype->getDependentType(genericParams,
- /*allowUnresolved=*/true),
+ archetype->getDependentType(genericParams),
constraint->value);
}
@@ -4135,9 +3912,7 @@
if (auto source = equivClass->findAnySuperclassConstraintAsWritten()) {
Diags.diagnose(source->source->getLoc(),
diag::recursive_superclass_constraint,
- source->archetype->getDependentType(
- genericParams,
- /*allowUnresolved=*/true),
+ source->archetype->getDependentType(genericParams),
equivClass->superclass);
}
@@ -4177,8 +3952,7 @@
if (auto constraint = equivClass->findAnyConcreteConstraintAsWritten())
Diags.diagnose(constraint->source->getLoc(),
diag::requires_generic_param_made_equal_to_concrete,
- rep->getDependentType(genericParams,
- /*allowUnresolved=*/true));
+ rep->getDependentType(genericParams));
continue;
}
@@ -4210,8 +3984,8 @@
if (repConstraint && repConstraint->source->getLoc().isValid()) {
Diags.diagnose(repConstraint->source->getLoc(),
diag::requires_generic_params_made_equal,
- pa->getDependentType(genericParams, true),
- other->getDependentType(genericParams, true));
+ pa->getDependentType(genericParams),
+ other->getDependentType(genericParams));
}
break;
}
@@ -4219,24 +3993,6 @@
}
}
-bool GenericSignatureBuilder::diagnoseRemainingRenames(
- SourceLoc loc,
- ArrayRef<GenericTypeParamType *> genericParams) {
- bool invalid = false;
-
- for (auto pa : Impl->RenamedNestedTypes) {
- if (pa->alreadyDiagnosedRename()) continue;
-
- Diags.diagnose(loc, diag::invalid_member_type_suggest,
- pa->getParent()->getDependentType(genericParams,
- /*allowUnresolved=*/true),
- pa->getOriginalName(), pa->getNestedName());
- invalid = true;
- }
-
- return invalid;
-}
-
/// Turn a requirement right-hand side into an unresolved type.
static GenericSignatureBuilder::UnresolvedType asUnresolvedType(
GenericSignatureBuilder::RequirementRHS rhs) {
@@ -4248,17 +4004,12 @@
void GenericSignatureBuilder::processDelayedRequirements() {
bool anySolved = !Impl->DelayedRequirements.empty();
- bool allowTypoCorrection = false;
while (anySolved) {
// Steal the delayed requirements so we can reprocess them.
anySolved = false;
auto delayed = std::move(Impl->DelayedRequirements);
Impl->DelayedRequirements.clear();
- // Whether we saw any unresolve type constraints that we couldn't
- // resolve.
- bool hasUnresolvedUnresolvedTypes = false;
-
// Process delayed requirements.
for (const auto &req : delayed) {
// Reprocess the delayed requirement.
@@ -4281,12 +4032,6 @@
req.lhs, asUnresolvedType(req.rhs), req.source,
UnresolvedHandlingKind::ReturnUnresolved);
break;
-
- case DelayedRequirement::Unresolved:
- reqResult = resolveUnresolvedType(
- req.lhs.get<PotentialArchetype *>(),
- allowTypoCorrection);
- break;
}
// Update our state based on what happened.
@@ -4303,19 +4048,9 @@
case ConstraintResult::Unresolved:
// Add the requirement back.
Impl->DelayedRequirements.push_back(req);
-
- if (req.kind == DelayedRequirement::Unresolved)
- hasUnresolvedUnresolvedTypes = true;
break;
}
}
-
- // If we didn't solve anything, but we did see some unresolved types,
- // try again with typo correction enabled.
- if (!anySolved && hasUnresolvedUnresolvedTypes && !allowTypoCorrection) {
- allowTypoCorrection = true;
- anySolved = true;
- }
}
}
@@ -4418,7 +4153,7 @@
otherNoteDiag,
representativeConstraint->source->classifyDiagKind(),
representativeConstraint->archetype->
- getDependentType(genericParams, /*allowUnresolved=*/true),
+ getDependentType(genericParams),
diagValue(representativeConstraint->value));
};
@@ -4437,7 +4172,7 @@
// diagnostic.
auto getSubjectType =
[&](PotentialArchetype *pa) -> std::pair<unsigned, Type> {
- auto subjectType = pa->getDependentType(genericParams, true);
+ auto subjectType = pa->getDependentType(genericParams);
unsigned kind;
if (auto gp = subjectType->getAs<GenericTypeParamType>()) {
if (gp->getDecl() &&
@@ -4495,8 +4230,7 @@
constraint.source->getLoc().isValid()) {
Diags.diagnose(constraint.source->getLoc(),
redundancyDiag,
- constraint.archetype->getDependentType(
- genericParams, /*allowUnresolved=*/true),
+ constraint.archetype->getDependentType(genericParams),
diagValue(constraint.value));
noteRepresentativeConstraint();
@@ -4801,10 +4535,8 @@
constraint.source->getLoc().isValid()) {
Diags.diagnose(constraint.source->getLoc(),
diag::redundant_same_type_constraint,
- constraint.archetype->getDependentType(
- genericParams, true),
- constraint.value->getDependentType(
- genericParams, true));
+ constraint.archetype->getDependentType(genericParams),
+ constraint.value->getDependentType(genericParams));
}
continue;
@@ -4871,7 +4603,7 @@
diag::redundant_same_type_constraint,
diag::previous_same_type_constraint,
[&](PotentialArchetype *pa) {
- return pa->getDependentType(genericParams, true);
+ return pa->getDependentType(genericParams);
},
/*removeSelfDerived=*/false);
}
@@ -4906,16 +4638,14 @@
Diags.diagnose(lhs.constraint.source->getLoc(),
diag::redundant_same_type_constraint,
lhs.constraint.archetype->getDependentType(
- genericParams, true),
- lhs.constraint.value->getDependentType(
- genericParams, true));
+ genericParams),
+ lhs.constraint.value->getDependentType(genericParams));
Diags.diagnose(rhs.constraint.source->getLoc(),
diag::previous_same_type_constraint,
rhs.constraint.source->classifyDiagKind(),
rhs.constraint.archetype->getDependentType(
- genericParams, true),
- rhs.constraint.value->getDependentType(
- genericParams, true));
+ genericParams),
+ rhs.constraint.value->getDependentType(genericParams));
return true;
}),
intercomponentEdges.end());
@@ -4938,17 +4668,17 @@
Diags.diagnose(edge.constraint.source->getLoc(),
diag::redundant_same_type_constraint,
edge.constraint.archetype->getDependentType(
- genericParams, true),
+ genericParams),
edge.constraint.value->getDependentType(
- genericParams, true));
+ genericParams));
Diags.diagnose(firstEdge.constraint.source->getLoc(),
diag::previous_same_type_constraint,
firstEdge.constraint.source->classifyDiagKind(),
firstEdge.constraint.archetype->getDependentType(
- genericParams, true),
+ genericParams),
firstEdge.constraint.value->getDependentType(
- genericParams, true));
+ genericParams));
}
continue;
@@ -4975,7 +4705,7 @@
if (!pa)
return ErrorType::get(depTy);
- return pa->getDependentType({ }, /*allowUnresolved=*/false);
+ return pa->getDependentType({ });
}
return None;
@@ -5065,8 +4795,7 @@
representativeConstraint.archetype)) {
Diags.diagnose(existing->source->getLoc(), diag::type_does_not_inherit,
existing->archetype->getDependentType(
- genericParams,
- /*allowUnresolved=*/true),
+ genericParams),
existing->value, equivClass->superclass);
// FIXME: Note the representative constraint.
@@ -5074,8 +4803,7 @@
Diags.diagnose(representativeConstraint.source->getLoc(),
diag::type_does_not_inherit,
representativeConstraint.archetype->getDependentType(
- genericParams,
- /*allowUnresolved=*/true),
+ genericParams),
equivClass->concreteType, equivClass->superclass);
}
} else if (representativeConstraint.source->getLoc().isValid()) {
@@ -5083,8 +4811,7 @@
Diags.diagnose(representativeConstraint.source->getLoc(),
diag::redundant_superclass_constraint,
representativeConstraint.archetype->getDependentType(
- genericParams,
- /*allowUnresolved=*/true),
+ genericParams),
representativeConstraint.value);
if (auto existing = equivClass->findAnyConcreteConstraintAsWritten(
@@ -5092,9 +4819,7 @@
Diags.diagnose(existing->source->getLoc(),
diag::same_type_redundancy_here,
existing->source->classifyDiagKind(),
- existing->archetype->getDependentType(
- genericParams,
- /*allowUnresolved=*/true),
+ existing->archetype->getDependentType(genericParams),
existing->value);
}
}
@@ -5197,21 +4922,6 @@
archetypes.push_back(archetype);
});
- // Remove any invalid potential archetypes or archetypes whose parents are
- // concrete; they have no requirements.
- archetypes.erase(
- std::remove_if(archetypes.begin(), archetypes.end(),
- [&](PotentialArchetype *archetype) -> bool {
- // Invalid archetypes are never representatives in well-formed or
- // corrected signature, so we don't need to visit them.
- if (archetype->isInvalid())
- return true;
-
- // Keep it.
- return false;
- }),
- archetypes.end());
-
// Sort the archetypes in canonical order.
llvm::array_pod_sort(archetypes.begin(), archetypes.end(),
compareDependentTypes);
@@ -5440,8 +5150,7 @@
type.is<Type>()))
return;
- auto depTy = archetype->getDependentType(params,
- /*allowUnresolved=*/false);
+ auto depTy = archetype->getDependentType(params);
if (depTy->hasError())
return;
@@ -5461,7 +5170,7 @@
} else {
// ...or to a dependent type.
repTy = type.get<GenericSignatureBuilder::PotentialArchetype *>()
- ->getDependentType(params, /*allowUnresolved=*/false);
+ ->getDependentType(params);
}
if (repTy->hasError())
diff --git a/lib/AST/LookupVisibleDecls.cpp b/lib/AST/LookupVisibleDecls.cpp
index b35593a..5dd50a4 100644
--- a/lib/AST/LookupVisibleDecls.cpp
+++ b/lib/AST/LookupVisibleDecls.cpp
@@ -17,6 +17,7 @@
#include "NameLookupImpl.h"
#include "swift/AST/ASTContext.h"
+#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ProtocolConformance.h"
@@ -465,19 +466,22 @@
lookupVisibleMemberDeclsImpl(Type BaseTy, VisibleDeclConsumer &Consumer,
const DeclContext *CurrDC, LookupState LS,
DeclVisibilityKind Reason,
- LazyResolver *TypeResolver, VisitedSet &Visited);
+ LazyResolver *TypeResolver,
+ GenericSignatureBuilder *GSB,
+ VisitedSet &Visited);
static void lookupVisibleProtocolMemberDecls(
Type BaseTy, ProtocolType *PT, VisibleDeclConsumer &Consumer,
const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason,
- LazyResolver *TypeResolver, VisitedSet &Visited) {
+ LazyResolver *TypeResolver, GenericSignatureBuilder *GSB,
+ VisitedSet &Visited) {
if (!Visited.insert(PT->getDecl()).second)
return;
for (auto Proto : PT->getDecl()->getInheritedProtocols())
lookupVisibleProtocolMemberDecls(BaseTy, Proto->getDeclaredType(), Consumer, CurrDC,
LS, getReasonForSuper(Reason), TypeResolver,
- Visited);
+ GSB, Visited);
lookupTypeMembers(BaseTy, PT, Consumer, CurrDC, LS, Reason, TypeResolver);
}
@@ -485,7 +489,7 @@
static void lookupVisibleMemberDeclsImpl(
Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC,
LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver,
- VisitedSet &Visited) {
+ GenericSignatureBuilder *GSB, VisitedSet &Visited) {
// Just look through l-valueness. It doesn't affect name lookup.
assert(BaseTy && "lookup into null type");
assert(!BaseTy->hasLValueType());
@@ -507,7 +511,7 @@
// functions, and can even look up non-static functions as well (thus
// getting the address of the member).
lookupVisibleMemberDeclsImpl(Ty, Consumer, CurrDC, subLS, Reason,
- TypeResolver, Visited);
+ TypeResolver, GSB, Visited);
return;
}
@@ -531,7 +535,7 @@
// If the base is a protocol, enumerate its members.
if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) {
lookupVisibleProtocolMemberDecls(BaseTy, PT, Consumer, CurrDC, LS, Reason,
- TypeResolver, Visited);
+ TypeResolver, GSB, Visited);
return;
}
@@ -539,7 +543,7 @@
if (auto PC = BaseTy->getAs<ProtocolCompositionType>()) {
for (auto Member : PC->getMembers())
lookupVisibleMemberDeclsImpl(Member, Consumer, CurrDC, LS, Reason,
- TypeResolver, Visited);
+ TypeResolver, GSB, Visited);
return;
}
@@ -548,15 +552,43 @@
for (auto Proto : Archetype->getConformsTo())
lookupVisibleProtocolMemberDecls(
BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS,
- getReasonForSuper(Reason), TypeResolver, Visited);
+ getReasonForSuper(Reason), TypeResolver, GSB, Visited);
if (auto superclass = Archetype->getSuperclass())
lookupVisibleMemberDeclsImpl(superclass, Consumer, CurrDC, LS,
getReasonForSuper(Reason), TypeResolver,
- Visited);
+ GSB, Visited);
return;
}
+ // If we're looking into a type parameter and we have a generic signature
+ // builder, use the GSB to resolve where we should look.
+ if (BaseTy->isTypeParameter() && GSB) {
+ auto PA = GSB->resolveArchetype(
+ BaseTy,
+ ArchetypeResolutionKind::CompleteWellFormed);
+ if (!PA) return;
+
+ if (auto Concrete = PA->getConcreteType()) {
+ BaseTy = Concrete;
+ } else {
+ // Conformances
+ for (auto Proto : PA->getConformsTo()) {
+ lookupVisibleProtocolMemberDecls(
+ BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS,
+ getReasonForSuper(Reason), TypeResolver, GSB, Visited);
+ }
+
+ // Superclass.
+ if (auto Superclass = PA->getSuperclass()) {
+ lookupVisibleMemberDeclsImpl(Superclass, Consumer, CurrDC, LS,
+ getReasonForSuper(Reason), TypeResolver,
+ GSB, Visited);
+ }
+ return;
+ }
+ }
+
llvm::SmallPtrSet<ClassDecl *, 8> Ancestors;
do {
NominalTypeDecl *CurNominal = BaseTy->getAnyNominal();
@@ -766,6 +798,13 @@
VD->getDeclContext()->isTypeContext());
ModuleDecl *M = DC->getParentModule();
+ // Hack; we shouldn't be filtering at this level anyway.
+ if (!VD->hasInterfaceType()) {
+ FoundDecls[VD->getBaseName()].insert(VD);
+ DeclsToReport.insert(FoundDeclTy(VD, Reason));
+ return;
+ }
+
auto FoundSignature = VD->getOverloadSignature();
if (FoundSignature.InterfaceType && shouldSubst &&
shouldSubstIntoDeclType(FoundSignature.InterfaceType)) {
@@ -777,7 +816,7 @@
for (auto I = PossiblyConflicting.begin(), E = PossiblyConflicting.end();
I != E; ++I) {
auto *OtherVD = *I;
- if (OtherVD->isInvalid()) {
+ if (OtherVD->isInvalid() || !OtherVD->hasInterfaceType()) {
// For some invalid decls it might be impossible to compute the
// signature, for example, if the types could not be resolved.
continue;
@@ -821,11 +860,12 @@
/// binding.
static void lookupVisibleMemberDecls(
Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC,
- LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver) {
+ LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver,
+ GenericSignatureBuilder *GSB) {
OverrideFilteringConsumer ConsumerWrapper(BaseTy, CurrDC, TypeResolver);
VisitedSet Visited;
lookupVisibleMemberDeclsImpl(BaseTy, ConsumerWrapper, CurrDC, LS, Reason,
- TypeResolver, Visited);
+ TypeResolver, GSB, Visited);
// Report the declarations we found to the real consumer.
for (const auto &DeclAndReason : ConsumerWrapper.DeclsToReport)
@@ -903,7 +943,7 @@
if (BaseDecl && ExtendedType) {
::lookupVisibleMemberDecls(ExtendedType, Consumer, DC, LS, Reason,
- TypeResolver);
+ TypeResolver, nullptr);
}
// Check any generic parameters for something with the given name.
@@ -954,7 +994,8 @@
void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy,
const DeclContext *CurrDC,
LazyResolver *TypeResolver,
- bool includeInstanceMembers) {
+ bool includeInstanceMembers,
+ GenericSignatureBuilder *GSB) {
assert(CurrDC);
LookupState ls = LookupState::makeQualified();
if (includeInstanceMembers) {
@@ -963,5 +1004,5 @@
::lookupVisibleMemberDecls(BaseTy, Consumer, CurrDC, ls,
DeclVisibilityKind::MemberOfCurrentNominal,
- TypeResolver);
+ TypeResolver, GSB);
}
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index 82c49ed..eccd064 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -311,7 +311,7 @@
#if !NDEBUG
unsigned idx = 0;
- for (auto req : getProtocol()->getRequirementSignature()->getRequirements()) {
+ for (const auto &req : getProtocol()->getRequirementSignature()) {
if (req.getKind() == RequirementKind::Conformance) {
assert(idx < conformances.size());
assert(conformances[idx].getRequirement() ==
@@ -596,8 +596,7 @@
"signature conformances not yet computed");
unsigned conformanceIndex = 0;
- for (auto &reqt :
- getProtocol()->getRequirementSignature()->getRequirements()) {
+ for (const auto &reqt : getProtocol()->getRequirementSignature()) {
if (reqt.getKind() == RequirementKind::Conformance) {
// Is this the conformance we're looking for?
if (reqt.getFirstType()->isEqual(assocType) &&
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 32dab3c..0f13814 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -694,7 +694,7 @@
// Determine the input and result types of this function.
auto fnType = this->castTo<AnyFunctionType>();
- Type inputType = fnType->getInput();
+ auto inputType = fnType->getParams();
Type resultType =
fnType->getResult()->replaceCovariantResultType(newResultType,
uncurryLevel - 1);
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index 3ac1d7c..4343e1a 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -46,6 +46,7 @@
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Index/IndexingAction.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/Preprocessor.h"
@@ -705,6 +706,11 @@
invocationArgStrs.push_back(overrideResourceDir);
}
+ if (!importerOpts.IndexStorePath.empty()) {
+ invocationArgStrs.push_back("-index-store-path");
+ invocationArgStrs.push_back(importerOpts.IndexStorePath);
+ }
+
for (auto extraArg : importerOpts.ExtraArgs) {
invocationArgStrs.push_back(extraArg);
}
@@ -1306,6 +1312,7 @@
invocation->getFrontendOpts().Inputs.push_back(
clang::FrontendInputFile(headerPath, clang::IK_ObjC));
invocation->getFrontendOpts().OutputFile = outputPCHPath;
+ invocation->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
invocation->getPreprocessorOpts().resetNonModularOptions();
clang::CompilerInstance emitInstance(
@@ -1319,8 +1326,15 @@
emitInstance.createSourceManager(fileManager);
emitInstance.setTarget(&Impl.Instance->getTarget());
- clang::GeneratePCHAction action;
- emitInstance.ExecuteAction(action);
+ std::unique_ptr<clang::FrontendAction> action;
+ action.reset(new clang::GeneratePCHAction());
+ if (!emitInstance.getFrontendOpts().IndexStorePath.empty()) {
+ action = clang::index::
+ createIndexDataRecordingAction(emitInstance.getFrontendOpts(),
+ std::move(action));
+ }
+ emitInstance.ExecuteAction(*action);
+
if (emitInstance.getDiagnostics().hasErrorOccurred()) {
Impl.SwiftContext.Diags.diagnose({},
diag::bridging_header_pch_error,
@@ -1407,6 +1421,17 @@
auto importRAII = diagClient.handleImport(clangPath.front().first,
importLoc);
+ std::string preservedIndexStorePathOption;
+ auto &clangFEOpts = Impl.Instance->getFrontendOpts();
+ if (!clangFEOpts.IndexStorePath.empty()) {
+ StringRef moduleName = path[0].first->getName();
+ // Ignore the SwiftShims module for the index data.
+ if (moduleName == Impl.SwiftContext.SwiftShimsModuleName.str()) {
+ preservedIndexStorePathOption = clangFEOpts.IndexStorePath;
+ clangFEOpts.IndexStorePath.clear();
+ }
+ }
+
// FIXME: The source location here is completely bogus. It can't be
// invalid, it can't be the same thing twice in a row, and it has to come
// from an actual buffer, so we make a fake buffer and just use a counter.
@@ -1427,6 +1452,12 @@
clang::ModuleLoadResult result =
Impl.Instance->loadModule(clangImportLoc, path, visibility,
/*IsInclusionDirective=*/false);
+
+ if (!preservedIndexStorePathOption.empty()) {
+ // Restore the -index-store-path option.
+ clangFEOpts.IndexStorePath = preservedIndexStorePathOption;
+ }
+
if (result && makeVisible)
Impl.getClangPreprocessor().makeModuleVisible(result, clangImportLoc);
return result;
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 93c92fa..2e580e9 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -121,12 +121,12 @@
/// it as a member
static std::pair<VarDecl *, PatternBindingDecl *>
createVarWithPattern(ASTContext &cxt, DeclContext *dc, Identifier name, Type ty,
- bool isLet, bool isImplicit,
+ VarDecl::Specifier specifier, bool isImplicit,
Accessibility setterAccessibility) {
// Create a variable to store the underlying value.
auto var = new (cxt) VarDecl(
/*IsStatic*/false,
- /*IsLet*/isLet,
+ specifier,
/*IsCaptureList*/false,
SourceLoc(), name, dc->mapTypeIntoContext(ty), dc);
if (isImplicit)
@@ -386,7 +386,7 @@
auto selfDecl = ParamDecl::createSelf(SourceLoc(), enumDecl,
/*static*/false, /*inout*/true);
- auto param = new (C) ParamDecl(/*let*/ true, SourceLoc(),
+ auto param = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), C.Id_rawValue,
SourceLoc(), C.Id_rawValue,
enumDecl->getRawType(),
@@ -593,7 +593,8 @@
auto &C = Impl.SwiftContext;
auto selfDecl = ParamDecl::createSelf(SourceLoc(), importedDecl,
/*isStatic*/false, /*isInOut*/true);
- auto newValueDecl = new (C) ParamDecl(/*isLet */ true,SourceLoc(),SourceLoc(),
+ auto newValueDecl = new (C) ParamDecl(VarDecl::Specifier::None,
+ SourceLoc(), SourceLoc(),
Identifier(), SourceLoc(), C.Id_value,
importedFieldDecl->getType(),
importedDecl);
@@ -1127,7 +1128,7 @@
Identifier argName = generateParamName ? var->getName() : Identifier();
auto param = new (context)
- ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName,
+ ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(), argName,
SourceLoc(), var->getName(), var->getType(), structDecl);
param->setInterfaceType(var->getInterfaceType());
valueParameters.push_back(param);
@@ -1281,9 +1282,12 @@
// Create a variable to store the underlying value.
VarDecl *var;
PatternBindingDecl *patternBinding;
+ auto specifier = options.contains(MakeStructRawValuedFlags::IsLet)
+ ? VarDecl::Specifier::Let
+ : VarDecl::Specifier::Var;
std::tie(var, patternBinding) = createVarWithPattern(
cxt, structDecl, cxt.Id_rawValue, underlyingType,
- options.contains(MakeStructRawValuedFlags::IsLet),
+ specifier,
options.contains(MakeStructRawValuedFlags::IsImplicit),
setterAccessibility);
@@ -1372,13 +1376,13 @@
VarDecl *storedVar;
PatternBindingDecl *storedPatternBinding;
std::tie(storedVar, storedPatternBinding) = createVarWithPattern(
- cxt, structDecl, storedVarName, storedUnderlyingType, /*isLet=*/false,
- /*isImplicit=*/true, Accessibility::Private);
+ cxt, structDecl, storedVarName, storedUnderlyingType,
+ VarDecl::Specifier::Var, /*isImplicit=*/true, Accessibility::Private);
//
// Create a computed value variable
auto computedVar = new (cxt) VarDecl(
- /*IsStatic*/false, /*IsLet*/false, /*IsCaptureList*/false,
+ /*IsStatic*/false, VarDecl::Specifier::Var, /*IsCaptureList*/false,
SourceLoc(), computedVarName, bridgedType, structDecl);
computedVar->setInterfaceType(bridgedType);
computedVar->setImplicit();
@@ -1430,7 +1434,7 @@
return fnType;
Type interfaceType = GenericFunctionType::get(
- sig, fnType->getInput(), fnType->getResult(), AnyFunctionType::ExtInfo());
+ sig, fnType->getParams(), fnType->getResult(), AnyFunctionType::ExtInfo());
return interfaceType;
}
@@ -1497,8 +1501,9 @@
auto elementTy = dc->mapTypeIntoContext(elementInterfaceTy);
auto paramVarDecl =
- new (C) ParamDecl(/*isLet=*/false, SourceLoc(), SourceLoc(), Identifier(),
- loc, valueIndex->get(0)->getName(), elementTy, dc);
+ new (C) ParamDecl(VarDecl::Specifier::InOut, SourceLoc(), SourceLoc(),
+ Identifier(), loc, valueIndex->get(0)->getName(),
+ elementTy, dc);
paramVarDecl->setInterfaceType(elementInterfaceTy);
auto valueIndicesPL = ParameterList::create(C, {paramVarDecl, index});
@@ -1547,9 +1552,7 @@
->castTo<AnyFunctionType>()
->getResult()
->castTo<AnyFunctionType>()
- ->getInput()
- ->castTo<TupleType>()
- ->getElementType(0);
+ ->getParams().front().getType();
ParamDecl *keyDecl = PL->get(1);
return {elementType, keyDecl};
@@ -1688,7 +1691,7 @@
// Make the property decl
auto errorDomainPropertyDecl = new (C) VarDecl(
- /*IsStatic*/isStatic, /*IsLet*/false, /*IsCaptureList*/false,
+ /*IsStatic*/isStatic, VarDecl::Specifier::Var, /*IsCaptureList*/false,
SourceLoc(), C.Id_nsErrorDomain, stringTy, swiftDecl);
errorDomainPropertyDecl->setInterfaceType(stringTy);
errorDomainPropertyDecl->setAccessibility(Accessibility::Public);
@@ -2483,7 +2486,8 @@
// Create the _nsError member.
// public let _nsError: NSError
auto nsErrorType = nsErrorDecl->getDeclaredInterfaceType();
- auto nsErrorProp = new (C) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto nsErrorProp = new (C) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false,
loc, C.Id_nsError, nsErrorType,
errorWrapper);
@@ -2550,7 +2554,8 @@
auto rawValueConstructor = makeEnumRawValueConstructor(Impl, enumDecl);
auto varName = C.Id_rawValue;
- auto rawValue = new (C) VarDecl(/*IsStatic*/false, /*IsLet*/ false,
+ auto rawValue = new (C) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Var,
/*IsCaptureList*/false,
SourceLoc(), varName, underlyingType,
enumDecl);
@@ -3164,7 +3169,8 @@
// Map this indirect field to a Swift variable.
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
Accessibility::Public,
- /*IsStatic*/false, /*IsLet*/ false,
+ /*IsStatic*/false,
+ VarDecl::Specifier::Var,
/*IsCaptureList*/false,
Impl.importSourceLoc(decl->getLocStart()),
name, dc->mapTypeIntoContext(type), dc);
@@ -3385,7 +3391,8 @@
auto result =
Impl.createDeclWithClangNode<VarDecl>(decl, Accessibility::Public,
- /*IsStatic*/ false, /*IsLet*/ false,
+ /*IsStatic*/ false,
+ VarDecl::Specifier::Var,
/*IsCaptureList*/false,
Impl.importSourceLoc(decl->getLocation()),
name, dc->mapTypeIntoContext(type), dc);
@@ -3458,10 +3465,13 @@
if (dc->isTypeContext())
isStatic = true;
+ auto specifier = Impl.shouldImportGlobalAsLet(decl->getType())
+ ? VarDecl::Specifier::Let
+ : VarDecl::Specifier::Var;
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
Accessibility::Public,
/*IsStatic*/isStatic,
- /*IsLet*/Impl.shouldImportGlobalAsLet(decl->getType()),
+ specifier,
/*IsCaptureList*/false,
Impl.importSourceLoc(decl->getLocation()),
name, dc->mapTypeIntoContext(type), dc);
@@ -4159,13 +4169,13 @@
result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
result->setCheckedInheritanceClause();
- auto *env = Impl.buildGenericEnvironment(result->getGenericParams(), dc);
- result->setGenericEnvironment(env);
-
// Compute the requirement signature.
if (!result->isRequirementSignatureComputed())
result->computeRequirementSignature();
+ auto *env = Impl.buildGenericEnvironment(result->getGenericParams(), dc);
+ result->setGenericEnvironment(env);
+
result->setMemberLoader(&Impl, 0);
// Add the protocol decl to ExternalDefinitions so that IRGen can emit
@@ -4536,7 +4546,7 @@
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
getOverridableAccessibility(dc),
- /*IsStatic*/decl->isClassProperty(), /*IsLet*/false,
+ /*IsStatic*/decl->isClassProperty(), VarDecl::Specifier::Var,
/*IsCaptureList*/false, Impl.importSourceLoc(decl->getLocation()),
name, dc->mapTypeIntoContext(type), dc);
result->setInterfaceType(type);
@@ -5212,7 +5222,7 @@
// argument label
auto *paramDecl =
new (Impl.SwiftContext) ParamDecl(
- /*isLet=*/true, SourceLoc(), SourceLoc(), argNames.front(),
+ VarDecl::Specifier::Let, SourceLoc(), SourceLoc(), argNames.front(),
SourceLoc(), argNames.front(), Impl.SwiftContext.TheEmptyTupleType,
dc);
paramDecl->setInterfaceType(Impl.SwiftContext.TheEmptyTupleType);
@@ -5487,9 +5497,9 @@
return nullptr;
auto property = Impl.createDeclWithClangNode<VarDecl>(
- getter, Accessibility::Public, /*IsStatic*/isStatic, /*isLet*/false,
- /*IsCaptureList*/false, SourceLoc(), propertyName,
- dc->mapTypeIntoContext(swiftPropertyType), dc);
+ getter, Accessibility::Public, /*IsStatic*/isStatic,
+ VarDecl::Specifier::Var, /*IsCaptureList*/false, SourceLoc(),
+ propertyName, dc->mapTypeIntoContext(swiftPropertyType), dc);
property->setInterfaceType(swiftPropertyType);
// Note that we've formed this property.
@@ -6348,7 +6358,8 @@
auto conformance = ctx.getConformance(dc->getDeclaredTypeInContext(),
protocols[i], SourceLoc(), dc,
ProtocolConformanceState::Incomplete);
- Impl.scheduleFinishProtocolConformance(conformance);
+ conformance->setLazyLoader(&Impl, /*context*/0);
+ conformance->setState(ProtocolConformanceState::Complete);
conformances.push_back(conformance);
}
@@ -7286,6 +7297,9 @@
void ClangImporter::Implementation::finishPendingActions() {
while (true) {
+ // The odd shape of this loop comes from previously having more than one
+ // possible kind of pending action. It's left this way to make it easy to
+ // add another one back in an `else if` clause.
if (!RegisteredExternalDecls.empty()) {
if (hasFinishedTypeChecking()) {
RegisteredExternalDecls.clear();
@@ -7297,22 +7311,22 @@
if (!nominal->hasDelayedMembers())
typeResolver->resolveExternalDeclImplicitMembers(nominal);
}
- } else if (!DelayedProtocolConformances.empty()) {
- NormalProtocolConformance *conformance =
- DelayedProtocolConformances.pop_back_val();
- finishProtocolConformance(conformance);
} else {
break;
}
}
}
-/// Finish the given protocol conformance (for an imported type)
-/// by filling in any missing witnesses.
-void ClangImporter::Implementation::finishProtocolConformance(
- NormalProtocolConformance *conformance) {
+void ClangImporter::Implementation::finishNormalConformance(
+ NormalProtocolConformance *conformance,
+ uint64_t unused) {
+ (void)unused;
const ProtocolDecl *proto = conformance->getProtocol();
+ PrettyStackTraceType trace(SwiftContext, "completing conformance for",
+ conformance->getType());
+ PrettyStackTraceDecl traceTo("... to", proto);
+
// Create witnesses for requirements not already met.
for (auto req : proto->getMembers()) {
auto valueReq = dyn_cast<ValueDecl>(req);
@@ -7376,7 +7390,7 @@
// Collect conformances for the requirement signature.
SmallVector<ProtocolConformanceRef, 4> reqConformances;
- for (auto req : proto->getRequirementSignature()->getRequirements()) {
+ for (const auto &req : proto->getRequirementSignature()) {
if (req.getKind() != RequirementKind::Conformance)
continue;
@@ -7740,12 +7754,12 @@
VarDecl *var = nullptr;
if (ClangN) {
var = createDeclWithClangNode<VarDecl>(ClangN, Accessibility::Public,
- /*IsStatic*/isStatic, /*IsLet*/false,
+ /*IsStatic*/isStatic, VarDecl::Specifier::Var,
/*IsCaptureList*/false, SourceLoc(),
name, dc->mapTypeIntoContext(type), dc);
} else {
var = new (SwiftContext)
- VarDecl(/*IsStatic*/isStatic, /*IsLet*/false, /*IsCaptureList*/false,
+ VarDecl(/*IsStatic*/isStatic, VarDecl::Specifier::Var, /*IsCaptureList*/false,
SourceLoc(), name, dc->mapTypeIntoContext(type), dc);
}
@@ -7852,7 +7866,7 @@
// Create a new VarDecl with dummy type.
auto var = createDeclWithClangNode<VarDecl>(ClangN, Accessibility::Public,
/*IsStatic*/isStatic,
- /*IsLet*/false,
+ VarDecl::Specifier::Var,
/*IsCaptureList*/false,
SourceLoc(), name, type, dc);
var->setInterfaceType(type);
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index c195326..1550db2 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -1675,7 +1675,7 @@
// imported header unit.
auto paramInfo = createDeclWithClangNode<ParamDecl>(
param, Accessibility::Private,
- /*IsLet*/ true, SourceLoc(), SourceLoc(), name,
+ VarDecl::Specifier::None, SourceLoc(), SourceLoc(), name,
importSourceLoc(param->getLocation()), bodyName,
dc->mapTypeIntoContext(swiftParamTy),
ImportedHeaderUnit);
@@ -1696,9 +1696,11 @@
BoundGenericType::get(SwiftContext.getArrayDecl(), Type(),
{SwiftContext.TheAnyType});
auto name = SwiftContext.getIdentifier("varargs");
- auto param = new (SwiftContext)
- ParamDecl(true, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
- name, paramTy, ImportedHeaderUnit);
+ auto param = new (SwiftContext) ParamDecl(VarDecl::Specifier::None,
+ SourceLoc(), SourceLoc(),
+ Identifier(), SourceLoc(),
+ name, paramTy,
+ ImportedHeaderUnit);
param->setInterfaceType(paramTy);
param->setVariadic();
@@ -1995,7 +1997,7 @@
// It doesn't actually matter which DeclContext we use, so just
// use the imported header unit.
auto type = TupleType::getEmpty(SwiftContext);
- auto var = new (SwiftContext) ParamDecl(/*IsLet*/ true, SourceLoc(),
+ auto var = new (SwiftContext) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), argName,
SourceLoc(), argName, type,
ImportedHeaderUnit);
@@ -2113,7 +2115,7 @@
// Set up the parameter info.
auto paramInfo
= createDeclWithClangNode<ParamDecl>(param, Accessibility::Private,
- /*IsLet*/ true,
+ VarDecl::Specifier::None,
SourceLoc(), SourceLoc(), name,
importSourceLoc(param->getLocation()),
bodyName,
@@ -2237,7 +2239,7 @@
Identifier argLabel = functionName.getDeclName().getArgumentNames().front();
auto paramInfo
= createDeclWithClangNode<ParamDecl>(param, Accessibility::Private,
- /*IsLet*/true,
+ VarDecl::Specifier::None,
/*let loc*/SourceLoc(),
/*label loc*/SourceLoc(),
argLabel, nameLoc, bodyName,
diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h
index 25c964d..174e075 100644
--- a/lib/ClangImporter/ImporterImpl.h
+++ b/lib/ClangImporter/ImporterImpl.h
@@ -496,9 +496,6 @@
/// External Decls that we have imported but not passed to the ASTContext yet.
SmallVector<Decl *, 4> RegisteredExternalDecls;
- /// Protocol conformances that may be missing witnesses.
- SmallVector<NormalProtocolConformance *, 4> DelayedProtocolConformances;
-
unsigned NumCurrentImportingEntities = 0;
/// Mapping from delayed conformance IDs to the set of delayed
@@ -517,7 +514,6 @@
void startedImportingEntity();
void finishedImportingEntity();
void finishPendingActions();
- void finishProtocolConformance(NormalProtocolConformance *conformance);
struct ImportingEntityRAII {
Implementation &Impl;
@@ -567,10 +563,6 @@
RegisteredExternalDecls.push_back(D);
}
- void scheduleFinishProtocolConformance(NormalProtocolConformance *C) {
- DelayedProtocolConformances.push_back(C);
- }
-
/// \brief Retrieve the Clang AST context.
clang::ASTContext &getClangASTContext() const {
return Instance->getASTContext();
@@ -1115,6 +1107,9 @@
const Decl *D, uint64_t contextData,
SmallVectorImpl<ProtocolConformance *> &Conformances) override;
+ void finishNormalConformance(NormalProtocolConformance *conformance,
+ uint64_t unused) override;
+
template <typename DeclTy, typename ...Targs>
DeclTy *createDeclWithClangNode(ClangNode ClangN, Accessibility access,
Targs &&... Args) {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index a9f4eba..ddb0bed 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1153,6 +1153,17 @@
OI.CompilerMode = OutputInfo::Mode::SingleCompile;
break;
+ // BEGIN APPLE-ONLY OUTPUT ACTIONS
+ case options::OPT_index_file:
+ OI.CompilerMode = OutputInfo::Mode::SingleCompile;
+ OI.CompilerOutputType = types::TY_IndexData;
+ break;
+ // END APPLE-ONLY OUTPUT ACTIONS
+
+ case options::OPT_update_code:
+ OI.CompilerOutputType = types::TY_Remapping;
+ OI.LinkAction = LinkKind::None;
+ break;
case options::OPT_parse:
case options::OPT_typecheck:
case options::OPT_dump_parse:
@@ -1449,6 +1460,7 @@
case types::TY_ClangModuleFile:
case types::TY_SwiftDeps:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_PCH:
case types::TY_ImportedModules:
case types::TY_TBD:
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d54e990..9032dc3 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -231,6 +231,13 @@
case types::TY_TBD:
FrontendModeOption = "-emit-tbd";
break;
+
+ // BEGIN APPLE-ONLY OUTPUT TYPES
+ case types::TY_IndexData:
+ FrontendModeOption = "-typecheck";
+ break;
+ // END APPLE-ONLY OUTPUT TYPES
+
case types::TY_Remapping:
FrontendModeOption = "-update-code";
break;
@@ -311,6 +318,12 @@
break;
}
case OutputInfo::Mode::SingleCompile: {
+ if (context.Output.getPrimaryOutputType() == types::TY_IndexData) {
+ if (Arg *A = context.Args.getLastArg(options::OPT_index_file_path)) {
+ Arguments.push_back("-primary-file");
+ Arguments.push_back(A->getValue());
+ }
+ }
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.InputActions.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
@@ -456,6 +469,11 @@
if (context.Args.hasArg(options::OPT_embed_bitcode_marker))
Arguments.push_back("-embed-bitcode-marker");
+ if (context.Args.hasArg(options::OPT_index_store_path)) {
+ context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
+ Arguments.push_back("-index-system-modules");
+ }
+
return II;
}
@@ -541,6 +559,7 @@
case types::TY_SIL:
case types::TY_SIB:
case types::TY_PCH:
+ case types::TY_IndexData:
llvm_unreachable("Cannot be output from backend job");
case types::TY_Swift:
case types::TY_dSYM:
@@ -824,6 +843,7 @@
Arguments);
addInputsOfType(Arguments, context.InputActions, types::TY_ObjCHeader);
+ context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
if (job.isPersistentPCH()) {
Arguments.push_back("-emit-pch");
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index e6b87da..d0b60bc 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -92,6 +92,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
return false;
case types::TY_INVALID:
llvm_unreachable("Invalid type ID.");
@@ -128,6 +129,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_ModuleTrace:
return false;
case types::TY_INVALID:
@@ -165,6 +167,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_ModuleTrace:
return false;
case types::TY_INVALID:
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 1f60276..a4f5d26 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -169,6 +169,11 @@
Opts.GroupInfoPath = A->getValue();
}
+ if (const Arg *A = Args.getLastArg(OPT_index_store_path)) {
+ Opts.IndexStorePath = A->getValue();
+ }
+ Opts.IndexSystemModules |= Args.hasArg(OPT_index_system_modules);
+
Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil);
Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil);
@@ -1143,6 +1148,9 @@
if (const Arg *A = Args.getLastArg(OPT_target_cpu))
Opts.TargetCPU = A->getValue();
+ if (const Arg *A = Args.getLastArg(OPT_index_store_path))
+ Opts.IndexStorePath = A->getValue();
+
for (const Arg *A : make_range(Args.filtered_begin(OPT_Xcc),
Args.filtered_end())) {
Opts.ExtraArgs.push_back(A->getValue());
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 0704189..7075aa6 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -97,6 +97,12 @@
if (!Invocation.getFrontendOptions().ModuleDocOutputPath.empty())
Invocation.getLangOptions().AttachCommentsToDecls = true;
+ // If we are doing index-while-building, configure lexing and parsing to
+ // remember comments.
+ if (!Invocation.getFrontendOptions().IndexStorePath.empty()) {
+ Invocation.getLangOptions().AttachCommentsToDecls = true;
+ }
+
Context.reset(new ASTContext(Invocation.getLangOptions(),
Invocation.getSearchPathOptions(),
SourceMgr, Diagnostics));
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 1168a59..882b8ab 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -5,6 +5,7 @@
TBD.cpp
DEPENDS SwiftOptions
LINK_LIBRARIES
+ swiftIndex
swiftIDE
swiftTBDGen swiftIRGen swiftSIL swiftSILGen swiftSILOptimizer
swiftDemangling
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 45a5614..9e3d1de 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -48,6 +48,7 @@
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/Frontend/SerializedDiagnosticConsumer.h"
#include "swift/Immediate/Immediate.h"
+#include "swift/Index/IndexRecord.h"
#include "swift/Option/Options.h"
#include "swift/Migrator/FixitFilter.h"
#include "swift/Migrator/Migrator.h"
@@ -368,6 +369,10 @@
LLVM_BUILTIN_TRAP;
}
+static bool emitIndexData(SourceFile *PrimarySourceFile,
+ const CompilerInvocation &Invocation,
+ CompilerInstance &Instance);
+
static void countStatsPostSema(UnifiedStatsReporter &Stats,
CompilerInstance& Instance) {
auto &C = Stats.getFrontendCounters();
@@ -646,8 +651,16 @@
(void)emitLoadedModuleTrace(Context, *Instance.getDependencyTracker(),
opts);
- if (Context.hadError())
+ bool shouldIndex = !opts.IndexStorePath.empty();
+
+ if (Context.hadError()) {
+ if (shouldIndex) {
+ // Emit the index store data even if there were compiler errors.
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return true;
+ }
// FIXME: This is still a lousy approximation of whether the module file will
// be externally consumed.
@@ -661,6 +674,10 @@
if (!opts.ObjCHeaderOutputPath.empty())
return printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(),
opts.ImplicitObjCHeaderPath, moduleIsPublic);
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return Context.hadError();
}
@@ -858,8 +875,13 @@
serialize(DC, serializationOpts, SM.get());
}
- if (Action == FrontendOptions::EmitModuleOnly)
+ if (Action == FrontendOptions::EmitModuleOnly) {
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return Context.hadError();
+ }
}
assert(Action >= FrontendOptions::EmitSIL &&
@@ -918,6 +940,13 @@
&HashGlobal);
}
+ // Walk the AST for indexing after IR generation. Walking it before seems
+ // to cause miscompilation issues.
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
+
// Just because we had an AST error it doesn't mean we can't performLLVM.
bool HadError = Instance.getASTContext().hadError();
@@ -975,6 +1004,52 @@
opts.getSingleOutputFilename(), Stats) || HadError;
}
+static bool emitIndexData(SourceFile *PrimarySourceFile,
+ const CompilerInvocation &Invocation,
+ CompilerInstance &Instance) {
+ const FrontendOptions &opts = Invocation.getFrontendOptions();
+ assert(!opts.IndexStorePath.empty());
+ // FIXME: provide index unit token(s) explicitly and only use output file
+ // paths as a fallback.
+
+ bool isDebugCompilation;
+ switch (Invocation.getSILOptions().Optimization) {
+ case SILOptions::SILOptMode::NotSet:
+ case SILOptions::SILOptMode::None:
+ case SILOptions::SILOptMode::Debug:
+ isDebugCompilation = true;
+ break;
+ case SILOptions::SILOptMode::Optimize:
+ case SILOptions::SILOptMode::OptimizeUnchecked:
+ isDebugCompilation = false;
+ break;
+ }
+
+ if (PrimarySourceFile) {
+ if (index::indexAndRecord(
+ PrimarySourceFile, opts.getSingleOutputFilename(),
+ opts.IndexStorePath, opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
+ return true;
+ }
+ } else {
+ StringRef moduleToken = opts.ModuleOutputPath;
+ if (moduleToken.empty())
+ moduleToken = opts.getSingleOutputFilename();
+
+ if (index::indexAndRecord(Instance.getMainModule(), opts.OutputFilenames,
+ moduleToken, opts.IndexStorePath,
+ opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Returns true if an error occurred.
static bool dumpAPI(ModuleDecl *Mod, StringRef OutDir) {
using namespace llvm::sys;
@@ -1231,6 +1306,7 @@
DependencyTracker depTracker;
if (!Invocation.getFrontendOptions().DependenciesFilePath.empty() ||
!Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty() ||
+ !Invocation.getFrontendOptions().IndexStorePath.empty() ||
!Invocation.getFrontendOptions().LoadedModuleTracePath.empty()) {
Instance->setDependencyTracker(&depTracker);
}
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index c3b92f6..18e3154 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -338,12 +338,7 @@
NewProto = Builder.CreateCall(objc_allocateProtocol, protocolName);
// Add the parent protocols.
- auto *requirementSig = proto->getRequirementSignature();
- auto conformsTo =
- requirementSig->getConformsTo(proto->getSelfInterfaceType(),
- *IGF.IGM.getSwiftModule());
-
- for (auto parentProto : conformsTo) {
+ for (auto parentProto : proto->getInheritedProtocols()) {
if (!parentProto->isObjC())
continue;
llvm::Value *parentRef = IGM.getAddrOfObjCProtocolRef(parentProto,
@@ -626,13 +621,8 @@
std::function<void(ProtocolDecl*)> orderProtocol
= [&](ProtocolDecl *proto) {
- auto *requirementSig = proto->getRequirementSignature();
- auto conformsTo = requirementSig->getConformsTo(
- proto->getSelfInterfaceType(),
- *getSwiftModule());
-
// Recursively put parents first.
- for (auto parent : conformsTo)
+ for (auto parent : proto->getInheritedProtocols())
orderProtocol(parent);
// Skip if we don't need to reify this protocol.
diff --git a/lib/IRGen/GenProto.h b/lib/IRGen/GenProto.h
index 85cafd0..721dcef 100644
--- a/lib/IRGen/GenProto.h
+++ b/lib/IRGen/GenProto.h
@@ -122,7 +122,7 @@
WitnessMetadata *witnessMetadata,
Explosion &args);
- /// Bind the polymorphic paramater inside of a partial apply forwarding thunk.
+ /// Bind the polymorphic parameter inside of a partial apply forwarding thunk.
void bindPolymorphicParameter(IRGenFunction &IGF,
CanSILFunctionType &OrigFnType,
CanSILFunctionType &SubstFnType,
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index b936bf1..539141f 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -814,9 +814,11 @@
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex, "target-cpu", CPU);
- std::vector<std::string> &Features = ClangOpts.Features;
+ std::vector<std::string> Features = ClangOpts.Features;
if (!Features.empty()) {
SmallString<64> allFeatures;
+ // Sort so that the target features string is canonical.
+ std::sort(Features.begin(), Features.end());
interleave(Features, [&](const std::string &s) {
allFeatures.append(s);
}, [&]{
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index d91c5a8..47aee9a 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -1,6 +1,7 @@
add_swift_library(swiftIndex STATIC
Index.cpp
IndexDataConsumer.cpp
+ IndexRecord.cpp
IndexSymbol.cpp
LINK_LIBRARIES
swiftAST)
diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp
new file mode 100644
index 0000000..91be812
--- /dev/null
+++ b/lib/Index/IndexRecord.cpp
@@ -0,0 +1,747 @@
+//===--- IndexRecord.cpp --------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Index/IndexRecord.h"
+#include "swift/AST/ASTContext.h"
+#include "swift/AST/Decl.h"
+#include "swift/AST/Expr.h"
+#include "swift/AST/Module.h"
+#include "swift/AST/ParameterList.h"
+#include "swift/AST/Pattern.h"
+#include "swift/AST/Stmt.h"
+#include "swift/AST/Types.h"
+#include "swift/AST/DiagnosticsFrontend.h"
+#include "swift/AST/ModuleLoader.h"
+#include "swift/ClangImporter/ClangModule.h"
+#include "swift/Index/Index.h"
+#include "swift/Strings.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/IndexRecordWriter.h"
+#include "clang/Index/IndexUnitWriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Path.h"
+
+using namespace swift;
+using namespace swift::index;
+using clang::index::IndexUnitWriter;
+using clang::index::IndexRecordWriter;
+using clang::index::SymbolRole;
+using clang::index::SymbolRoleSet;
+
+//===----------------------------------------------------------------------===//
+// Index data collection and record writing
+//===----------------------------------------------------------------------===//
+
+namespace {
+class SymbolTracker {
+public:
+ struct SymbolRelation {
+ size_t symbolIndex;
+ SymbolRoleSet roles;
+
+ llvm::hash_code hash() const { return llvm::hash_combine(symbolIndex, roles); }
+ };
+ struct SymbolOccurrence {
+ size_t symbolIndex;
+ SymbolRoleSet roles;
+ unsigned line;
+ unsigned column;
+ SmallVector<SymbolRelation, 3> related;
+
+ llvm::hash_code hash() const {
+ auto hash = llvm::hash_combine(symbolIndex, roles, line, column);
+ for (auto &relation : related) {
+ hash = llvm::hash_combine(hash, relation.hash());
+ }
+ return hash;
+ }
+ };
+ struct Symbol {
+ StringRef name;
+ StringRef USR;
+ StringRef group;
+
+ SymbolInfo symInfo;
+ unsigned isTestCandidate : 1;
+
+ llvm::hash_code hash() const {
+ return llvm::hash_combine(
+ name, USR, group,
+ static_cast<unsigned>(symInfo.Kind),
+ static_cast<unsigned>(symInfo.SubKind),
+ symInfo.Properties, isTestCandidate);
+ }
+ };
+
+ Symbol *getSymbol(size_t index) {
+ assert(index < symbols.size());
+ return &symbols[index];
+ }
+
+ ArrayRef<SymbolOccurrence> getOccurrences() {
+ if (!sorted) {
+ std::stable_sort(occurrences.begin(), occurrences.end(),
+ [](const SymbolOccurrence &a, const SymbolOccurrence& b) {
+ if (a.line < b.line)
+ return true;
+ if (b.line < a.line)
+ return false;
+ return a.column < b.column;
+ });
+ sorted = true;
+ }
+ return occurrences;
+ }
+
+ size_t addSymbol(const IndexRelation &indexSym) {
+ auto pair = USRToSymbol.insert(std::make_pair(indexSym.USR.data(),
+ symbols.size()));
+ if (pair.second) {
+ Symbol symbol{indexSym.name,
+ indexSym.USR,
+ indexSym.group,
+ indexSym.symInfo,
+ 0};
+ recordHash = llvm::hash_combine(recordHash, symbol.hash());
+ symbols.push_back(std::move(symbol));
+ }
+
+ return pair.first->second;
+ }
+
+ void addOccurrence(const IndexSymbol &indexOccur) {
+ sorted = false;
+
+ SmallVector<SymbolRelation, 3> relations;
+ for(IndexRelation indexRel: indexOccur.Relations) {
+ relations.push_back({addSymbol(indexRel), indexRel.roles});
+ }
+
+ occurrences.push_back({/*symbolIndex=*/addSymbol(indexOccur),
+ indexOccur.roles,
+ indexOccur.line,
+ indexOccur.column,
+ std::move(relations)});
+
+ recordHash = llvm::hash_combine(recordHash, occurrences.back().hash());
+ }
+
+ llvm::hash_code hashRecord() const { return recordHash; }
+
+private:
+ llvm::DenseMap<const char *, size_t> USRToSymbol;
+ std::vector<Symbol> symbols;
+ std::vector<SymbolOccurrence> occurrences;
+ bool sorted = false;
+ llvm::hash_code recordHash = 0;
+};
+
+class IndexRecordingConsumer : public IndexDataConsumer {
+ SymbolTracker record;
+ // Keep a USR map to uniquely identify Decls.
+ // FIXME: if we just passed the original Decl * through we could use that,
+ // which would also let us avoid producing the USR/Name/etc. for decls unless
+ // we actually need it (once per Decl instead of once per occurrence).
+ std::vector<IndexSymbol> symbolStack;
+
+ std::function<void(SymbolTracker &)> onFinish;
+
+public:
+ IndexRecordingConsumer(std::function<void(SymbolTracker &)> onFinish)
+ : onFinish(std::move(onFinish)) {}
+
+ void failed(StringRef error) override {
+ // FIXME: expose errors?
+ }
+
+ bool recordHash(StringRef hash, bool isKnown) override { return true; }
+ bool startDependency(StringRef name, StringRef path, bool isClangModule,
+ bool isSystem, StringRef hash) override {
+ return true;
+ }
+ bool finishDependency(bool isClangModule) override { return true; }
+ Action startSourceEntity(const IndexSymbol &symbol) override {
+ symbolStack.push_back(symbol);
+ return Action::Continue;
+ }
+ bool finishSourceEntity(SymbolInfo sym, SymbolRoleSet roles) override {
+ IndexSymbol symbol = std::move(symbolStack.back());
+ symbolStack.pop_back();
+ assert(!symbol.USR.empty());
+ record.addOccurrence(symbol);
+ return true;
+ }
+
+ void finish() override { onFinish(record); }
+};
+
+class StdlibGroupsIndexRecordingConsumer : public IndexDataConsumer {
+ llvm::StringMap<std::unique_ptr<SymbolTracker>> TrackerByGroup;
+ // Keep a USR map to uniquely identify Decls.
+ // FIXME: if we just passed the original Decl * through we could use that,
+ // which would also let us avoid producing the USR/Name/etc. for decls unless
+ // we actually need it (once per Decl instead of once per occurrence).
+ std::vector<IndexSymbol> symbolStack;
+
+ std::function<bool(StringRef groupName, SymbolTracker &)> onFinish;
+
+public:
+ StdlibGroupsIndexRecordingConsumer(std::function<bool(StringRef groupName, SymbolTracker &)> onFinish)
+ : onFinish(std::move(onFinish)) {}
+
+ void failed(StringRef error) override {
+ // FIXME: expose errors?
+ }
+
+ bool recordHash(StringRef hash, bool isKnown) override { return true; }
+ bool startDependency(StringRef name, StringRef path, bool isClangModule,
+ bool isSystem, StringRef hash) override {
+ return true;
+ }
+ bool finishDependency(bool isClangModule) override { return true; }
+ Action startSourceEntity(const IndexSymbol &symbol) override {
+ symbolStack.push_back(symbol);
+ return Action::Continue;
+ }
+ bool finishSourceEntity(SymbolInfo sym, SymbolRoleSet roles) override {
+ IndexSymbol symbol = std::move(symbolStack.back());
+ symbolStack.pop_back();
+ assert(!symbol.USR.empty());
+ StringRef groupName = findGroupForSymbol(symbol);
+ auto &tracker = TrackerByGroup[groupName];
+ if (!tracker) {
+ tracker = llvm::make_unique<SymbolTracker>();
+ }
+ tracker->addOccurrence(symbol);
+ return true;
+ }
+
+ void finish() override {
+ for (auto &pair : TrackerByGroup) {
+ StringRef groupName = pair.first();
+ SymbolTracker &tracker = *pair.second;
+ bool cont = onFinish(groupName, tracker);
+ if (!cont)
+ break;
+ }
+ }
+
+private:
+ StringRef findGroupForSymbol(const IndexSymbol &sym);
+
+};
+} // end anonymous namespace
+
+static StringRef findGroupNameForDecl(const Decl *D) {
+ if (!D || isa<ModuleDecl>(D) || isa<TopLevelCodeDecl>(D))
+ return StringRef();
+
+ auto groupNameOpt = D->getGroupName();
+ if (groupNameOpt)
+ return *groupNameOpt;
+
+ return findGroupNameForDecl(D->getDeclContext()->getInnermostDeclarationDeclContext());
+}
+
+StringRef StdlibGroupsIndexRecordingConsumer::findGroupForSymbol(const IndexSymbol &sym) {
+ bool isDeclOrDef = sym.roles & ((SymbolRoleSet)SymbolRole::Declaration | (SymbolRoleSet)SymbolRole::Definition);
+ if (isDeclOrDef) {
+ if (!sym.group.empty())
+ return sym.group;
+ return findGroupNameForDecl(sym.decl);
+ }
+
+ for (auto &rel : sym.Relations) {
+ if (!rel.group.empty())
+ return rel.group;
+ if (rel.decl)
+ return findGroupNameForDecl(rel.decl);
+ }
+ llvm_unreachable("did not find group name for reference");
+}
+
+static bool writeRecord(SymbolTracker &record, std::string Filename,
+ std::string indexStorePath, DiagnosticEngine *diags,
+ std::string &outRecordFile) {
+ if (record.getOccurrences().empty()) {
+ outRecordFile = std::string();
+ return false;
+ }
+
+ IndexRecordWriter recordWriter(indexStorePath);
+ std::string error;
+ auto result = recordWriter.beginRecord(
+ Filename, record.hashRecord(), error, &outRecordFile);
+ switch (result) {
+ case IndexRecordWriter::Result::Failure:
+ diags->diagnose(SourceLoc(), diag::error_write_index_record, error);
+ return true;
+ case IndexRecordWriter::Result::AlreadyExists:
+ return false;
+ case IndexRecordWriter::Result::Success:
+ break;
+ }
+
+ for (auto &occurrence : record.getOccurrences()) {
+ SmallVector<clang::index::writer::SymbolRelation, 3> relations;
+ for(SymbolTracker::SymbolRelation symbolRelation: occurrence.related) {
+ relations.push_back({record.getSymbol(symbolRelation.symbolIndex), symbolRelation.roles});
+ }
+
+ recordWriter.addOccurrence(
+ record.getSymbol(occurrence.symbolIndex), occurrence.roles,
+ occurrence.line, occurrence.column, relations);
+ }
+
+ result = recordWriter.endRecord(error,
+ [&](clang::index::writer::OpaqueDecl opaqueSymbol,
+ SmallVectorImpl<char> &scratch) {
+ auto *symbol = static_cast<const SymbolTracker::Symbol *>(opaqueSymbol);
+ clang::index::writer::Symbol result;
+ result.SymInfo = symbol->symInfo;
+ result.Name = symbol->name;
+ result.USR = symbol->USR;
+ result.CodeGenName = ""; // FIXME
+ return result;
+ });
+
+ if (result == IndexRecordWriter::Result::Failure) {
+ diags->diagnose(SourceLoc(), diag::error_write_index_record, error);
+ return true;
+ }
+
+ return false;
+}
+
+static std::unique_ptr<IndexRecordingConsumer>
+makeRecordingConsumer(std::string Filename, std::string indexStorePath,
+ DiagnosticEngine *diags,
+ std::string *outRecordFile,
+ bool *outFailed) {
+ return llvm::make_unique<IndexRecordingConsumer>([=](SymbolTracker &record) {
+ *outFailed = writeRecord(record, Filename, indexStorePath, diags,
+ *outRecordFile);
+ });
+}
+
+static bool
+recordSourceFile(SourceFile *SF, StringRef indexStorePath,
+ DiagnosticEngine &diags,
+ llvm::function_ref<void(StringRef, StringRef)> callback) {
+ std::string recordFile;
+ bool failed = false;
+ auto consumer = makeRecordingConsumer(SF->getFilename(), indexStorePath,
+ &diags, &recordFile, &failed);
+ indexSourceFile(SF, /*Hash=*/"", *consumer);
+
+ if (!failed && !recordFile.empty())
+ callback(recordFile, SF->getFilename());
+ return failed;
+}
+
+//===----------------------------------------------------------------------===//
+// Index unit file writing
+//===----------------------------------------------------------------------===//
+
+// Used to get std::string pointers to pass as writer::OpaqueModule.
+namespace {
+class StringScratchSpace {
+ std::vector<const std::string *> StrsCreated;
+
+public:
+ const std::string *createString(StringRef str) {
+ auto *s = new std::string(str);
+ StrsCreated.push_back(s);
+ return s;
+ }
+
+ ~StringScratchSpace() {
+ for (auto *str : StrsCreated)
+ delete str;
+ }
+};
+}
+
+static clang::index::writer::ModuleInfo
+getModuleInfoFromOpaqueModule(clang::index::writer::OpaqueModule mod,
+ SmallVectorImpl<char> &Scratch) {
+ clang::index::writer::ModuleInfo info;
+ info.Name = *static_cast<const std::string*>(mod);
+ return info;
+}
+
+static bool
+emitDataForSwiftSerializedModule(ModuleDecl *module,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &parentUnitWriter);
+
+static void addModuleDependencies(ArrayRef<ModuleDecl::ImportedModule> imports,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &unitWriter,
+ StringScratchSpace &moduleNameScratch) {
+ auto &fileMgr = clangCI.getFileManager();
+
+ for (auto &import : imports) {
+ ModuleDecl *mod = import.second;
+ if (mod->getNameStr() == SWIFT_ONONE_SUPPORT)
+ continue; // ignore the Onone support library.
+ if (mod->isSwiftShimsModule())
+ continue;
+
+ for (auto *FU : mod->getFiles()) {
+ switch (FU->getKind()) {
+ case FileUnitKind::Source:
+ case FileUnitKind::Derived:
+ case FileUnitKind::Builtin:
+ break;
+ case FileUnitKind::SerializedAST:
+ case FileUnitKind::ClangModule: {
+ auto *LFU = cast<LoadedFile>(FU);
+ if (auto *F = fileMgr.getFile(LFU->getFilename())) {
+ std::string moduleName = mod->getNameStr();
+ bool withoutUnitName = true;
+ if (FU->getKind() == FileUnitKind::ClangModule) {
+ withoutUnitName = false;
+ auto clangModUnit = cast<ClangModuleUnit>(LFU);
+ if (auto clangMod = clangModUnit->getUnderlyingClangModule()) {
+ moduleName = clangMod->getTopLevelModuleName();
+ // FIXME: clang's -Rremarks do not seem to go through Swift's
+ // diagnostic emitter.
+ clang::index::emitIndexDataForModuleFile(clangMod,
+ clangCI, unitWriter);
+ }
+ } else {
+ // Serialized AST file.
+ // Only index system modules (essentially stdlib and overlays).
+ // We don't officially support binary swift modules, so normally
+ // the index data for user modules would get generated while
+ // building them.
+ if (mod->isSystemModule() && indexSystemModules) {
+ emitDataForSwiftSerializedModule(mod, indexStorePath,
+ indexSystemModules,
+ targetTriple, clangCI, diags,
+ unitWriter);
+ withoutUnitName = false;
+ }
+ }
+ clang::index::writer::OpaqueModule opaqMod =
+ moduleNameScratch.createString(moduleName);
+ unitWriter.addASTFileDependency(F, mod->isSystemModule(), opaqMod,
+ withoutUnitName);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/// \returns true if an error occurred.
+static bool
+emitDataForSwiftSerializedModule(ModuleDecl *module,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &parentUnitWriter) {
+ StringRef filename = module->getModuleFilename();
+ std::string moduleName = module->getNameStr();
+
+ std::string error;
+ auto isUptodateOpt = parentUnitWriter.isUnitUpToDateForOutputFile(/*FilePath=*/filename,
+ /*TimeCompareFilePath=*/filename, error);
+ if (!isUptodateOpt.hasValue()) {
+ diags.diagnose(SourceLoc(), diag::error_index_failed_status_check, error);
+ return true;
+ }
+ if (*isUptodateOpt)
+ return false;
+
+ // FIXME: Would be useful for testing if swift had clang's -Rremark system so
+ // we could output a remark here that we are going to create index data for
+ // a module file.
+
+ // Pairs of (recordFile, groupName).
+ std::vector<std::pair<std::string, std::string>> records;
+
+ if (!module->isStdlibModule()) {
+ std::string recordFile;
+ bool failed = false;
+ auto consumer = makeRecordingConsumer(filename, indexStorePath,
+ &diags, &recordFile, &failed);
+ indexModule(module, /*Hash=*/"", *consumer);
+
+ if (failed)
+ return true;
+
+ records.emplace_back(recordFile, moduleName);
+ } else {
+ // Record stdlib groups as if they were submodules.
+
+ auto makeSubmoduleNameFromGroupName = [](StringRef groupName, SmallString<128> &buf) {
+ buf += "Swift";
+ if (groupName.empty())
+ return;
+ buf += '.';
+ for (char ch : groupName) {
+ if (ch == '/')
+ buf += '.';
+ else if (ch == ' ' || ch == '-')
+ buf += '_';
+ else
+ buf += ch;
+ }
+ };
+ auto appendGroupNameForFilename = [](StringRef groupName, SmallString<256> &buf) {
+ if (groupName.empty())
+ return;
+ buf += '_';
+ for (char ch : groupName) {
+ if (ch == '/' || ch ==' ')
+ buf += '_';
+ else
+ buf += ch;
+ }
+ };
+
+ bool failed = false;
+ StdlibGroupsIndexRecordingConsumer groupIndexConsumer([&](StringRef groupName, SymbolTracker &tracker) -> bool {
+ SmallString<128> moduleName;
+ makeSubmoduleNameFromGroupName(groupName, moduleName);
+ SmallString<256> fileNameWithGroup = filename;
+ appendGroupNameForFilename(groupName, fileNameWithGroup);
+
+ std::string outRecordFile;
+ failed = failed || writeRecord(tracker, fileNameWithGroup.str(), indexStorePath, &diags, outRecordFile);
+ if (failed)
+ return false;
+ records.emplace_back(outRecordFile, moduleName.str());
+ return true;
+ });
+ indexModule(module, /*Hash=*/"", groupIndexConsumer);
+ if (failed)
+ return true;
+ }
+
+ auto &fileMgr = clangCI.getFileManager();
+ bool isSystem = module->isSystemModule();
+ // FIXME: Get real values for the following.
+ StringRef swiftVersion;
+ StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot;
+ std::string indexUnitToken = module->getModuleFilename();
+ // For indexing serialized modules 'debug compilation' is irrelevant, so
+ // set it to true by default.
+ bool isDebugCompilation = true;
+
+ IndexUnitWriter unitWriter(fileMgr, indexStorePath,
+ "swift", swiftVersion, indexUnitToken, moduleName,
+ /*MainFile=*/nullptr, isSystem, /*IsModuleUnit=*/true,
+ isDebugCompilation, targetTriple, sysrootPath, getModuleInfoFromOpaqueModule);
+
+ const clang::FileEntry *FE = fileMgr.getFile(filename);
+ bool isSystemModule = module->isSystemModule();
+ for (auto &pair : records) {
+ std::string &recordFile = pair.first;
+ std::string &groupName = pair.second;
+ if (recordFile.empty())
+ continue;
+ clang::index::writer::OpaqueModule mod = &groupName;
+ unitWriter.addRecordFile(recordFile, FE, isSystemModule, mod);
+ }
+
+ SmallVector<ModuleDecl::ImportedModule, 8> imports;
+ module->getImportedModules(imports, ModuleDecl::ImportFilter::All);
+ StringScratchSpace moduleNameScratch;
+ addModuleDependencies(imports, indexStorePath, indexSystemModules,
+ targetTriple, clangCI, diags, unitWriter, moduleNameScratch);
+
+ if (unitWriter.write(error)) {
+ diags.diagnose(SourceLoc(), diag::error_write_index_unit, error);
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+recordSourceFileUnit(SourceFile *primarySourceFile, StringRef indexUnitToken,
+ StringRef indexStorePath, bool indexSystemModules,
+ bool isDebugCompilation, StringRef targetTriple,
+ ArrayRef<const clang::FileEntry *> fileDependencies,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags) {
+ auto &fileMgr = clangCI.getFileManager();
+ auto *module = primarySourceFile->getParentModule();
+ bool isSystem = module->isSystemModule();
+ auto *mainFile = fileMgr.getFile(primarySourceFile->getFilename());
+ // FIXME: Get real values for the following.
+ StringRef swiftVersion;
+ StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot;
+
+ IndexUnitWriter unitWriter(fileMgr, indexStorePath,
+ "swift", swiftVersion, indexUnitToken, module->getNameStr(),
+ mainFile, isSystem, /*isModuleUnit=*/false, isDebugCompilation,
+ targetTriple, sysrootPath, getModuleInfoFromOpaqueModule);
+
+ // Module dependencies.
+ SmallVector<ModuleDecl::ImportedModule, 8> imports;
+ primarySourceFile->getImportedModules(imports, ModuleDecl::ImportFilter::All);
+ StringScratchSpace moduleNameScratch;
+ addModuleDependencies(imports, indexStorePath, indexSystemModules,
+ targetTriple, clangCI, diags, unitWriter, moduleNameScratch);
+
+ // File dependencies.
+ for (auto *F : fileDependencies)
+ unitWriter.addFileDependency(F, /*FIXME:isSystem=*/false, /*Module=*/nullptr);
+
+ recordSourceFile(primarySourceFile, indexStorePath, diags,
+ [&](StringRef recordFile, StringRef filename) {
+ unitWriter.addRecordFile(recordFile, fileMgr.getFile(filename),
+ module->isSystemModule(), /*Module=*/nullptr);
+ });
+
+ std::string error;
+ if (unitWriter.write(error)) {
+ diags.diagnose(SourceLoc(), diag::error_write_index_unit, error);
+ return true;
+ }
+
+ return false;
+}
+
+// Not currently used, see related comments in the call sites.
+#if 0
+static void
+collectFileDependencies(llvm::SetVector<const clang::FileEntry *> &result,
+ const DependencyTracker &dependencyTracker,
+ ModuleDecl *module, clang::FileManager &fileMgr) {
+ for (auto *F : module->getFiles()) {
+ if (auto *SF = dyn_cast<SourceFile>(F)) {
+ if (auto *dep = fileMgr.getFile(SF->getFilename())) {
+ result.insert(dep);
+ }
+ }
+ }
+ for (StringRef filename : dependencyTracker.getDependencies()) {
+ if (auto *F = fileMgr.getFile(filename))
+ result.insert(F);
+ }
+}
+#endif
+
+//===----------------------------------------------------------------------===//
+// Indexing entry points
+//===----------------------------------------------------------------------===//
+
+bool index::indexAndRecord(SourceFile *primarySourceFile,
+ StringRef indexUnitToken,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker) {
+ auto &astContext = primarySourceFile->getASTContext();
+ auto &clangCI = astContext.getClangModuleLoader()->getClangInstance();
+ auto &diags = astContext.Diags;
+
+ std::string error;
+ if (IndexUnitWriter::initIndexDirectory(indexStorePath, error)) {
+ diags.diagnose(SourceLoc(), diag::error_create_index_dir, error);
+ return true;
+ }
+
+ llvm::SetVector<const clang::FileEntry *> fileDependencies;
+ // FIXME: This is not desirable because:
+ // 1. It picks shim header files as file dependencies
+ // 2. Having all the other swift files of the module as file dependencies ends
+ // up making all of them associated with all the other files as main files.
+ // It's better to associate each swift file with the unit that recorded it
+ // as the main one.
+ // Keeping the code in case we want to revisit.
+#if 0
+ auto *module = primarySourceFile->getParentModule();
+ collectFileDependencies(fileDependencies, dependencyTracker, module, fileMgr);
+#endif
+
+ return recordSourceFileUnit(primarySourceFile, indexUnitToken,
+ indexStorePath, indexSystemModules,
+ isDebugCompilation, targetTriple,
+ fileDependencies.getArrayRef(),
+ clangCI, diags);
+}
+
+bool index::indexAndRecord(ModuleDecl *module,
+ ArrayRef<std::string> indexUnitTokens,
+ StringRef moduleUnitToken,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker) {
+ auto &astContext = module->getASTContext();
+ auto &clangCI = astContext.getClangModuleLoader()->getClangInstance();
+ auto &diags = astContext.Diags;
+
+ std::string error;
+ if (IndexUnitWriter::initIndexDirectory(indexStorePath, error)) {
+ diags.diagnose(SourceLoc(), diag::error_create_index_dir, error);
+ return true;
+ }
+
+ // Add the current module's source files to the dependencies.
+ llvm::SetVector<const clang::FileEntry *> fileDependencies;
+ // FIXME: This is not desirable because:
+ // 1. It picks shim header files as file dependencies
+ // 2. Having all the other swift files of the module as file dependencies ends
+ // up making all of them associated with all the other files as main files.
+ // It's better to associate each swift file with the unit that recorded it
+ // as the main one.
+ // Keeping the code in case we want to revisit.
+#if 0
+ collectFileDependencies(fileDependencies, dependencyTracker, module, fileMgr);
+#endif
+
+ // Write a unit for each source file.
+ unsigned unitIndex = 0;
+ for (auto *F : module->getFiles()) {
+ if (auto *SF = dyn_cast<SourceFile>(F)) {
+ if (unitIndex == indexUnitTokens.size()) {
+ diags.diagnose(SourceLoc(), diag::error_index_inputs_more_than_outputs);
+ return true;
+ }
+ if (recordSourceFileUnit(SF, indexUnitTokens[unitIndex],
+ indexStorePath, indexSystemModules,
+ isDebugCompilation, targetTriple,
+ fileDependencies.getArrayRef(),
+ clangCI, diags))
+ return true;
+ unitIndex += 1;
+ }
+ }
+
+ // In the case where inputs are swift modules, like in the merge-module step,
+ // ignore the inputs; associated unit files for the modules' source inputs
+ // should have been generated at swift module creation time.
+
+ return false;
+}
diff --git a/lib/Migrator/TupleSplatMigratorPass.cpp b/lib/Migrator/TupleSplatMigratorPass.cpp
index 8c77492..360cbe4 100644
--- a/lib/Migrator/TupleSplatMigratorPass.cpp
+++ b/lib/Migrator/TupleSplatMigratorPass.cpp
@@ -88,13 +88,7 @@
FunctionType *FuncTy = FC->getType()->getAs<FunctionType>();
- unsigned NativeArity = 0;
- if (isa<ParenType>(FuncTy->getInput().getPointer())) {
- NativeArity = 1;
- } else if (auto TT = FuncTy->getInput()->getAs<TupleType>()) {
- NativeArity = TT->getNumElements();
- }
-
+ unsigned NativeArity = FuncTy->getParams().size();
unsigned ClosureArity = Closure->getParameters()->size();
if (NativeArity <= ClosureArity)
return false;
@@ -149,10 +143,10 @@
auto fnTy = E->getFn()->getType()->getAs<FunctionType>();
if (!fnTy)
return false;
- auto parenT = dyn_cast<ParenType>(fnTy->getInput().getPointer());
- if (!parenT)
+ if (!(fnTy->getParams().size() == 1 &&
+ fnTy->getParams().front().getLabel().empty()))
return false;
- auto inp = dyn_cast<TupleType>(parenT->getUnderlyingType().getPointer());
+ auto inp = fnTy->getParams().front().getType()->getAs<TupleType>();
if (!inp)
return false;
if (inp->getNumElements() != 0)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0d396c1..4b9789f 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3503,7 +3503,8 @@
name = P.Context.getIdentifier(implName);
}
- auto result = new (P.Context) ParamDecl(/*IsLet*/true,SourceLoc(),SourceLoc(),
+ auto result = new (P.Context) ParamDecl(VarDecl::Specifier::None,
+ SourceLoc(),SourceLoc(),
Identifier(), nameLoc, name,
Type(), P.CurDeclContext);
if (isNameImplicit)
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 13aac5b..1dd4a5c 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1474,8 +1474,10 @@
peekToken().isNot(tok::period, tok::period_prefix, tok::l_paren)) {
Identifier name;
SourceLoc loc = consumeIdentifier(&name);
- auto pattern = createBindingFromPattern(loc, name,
- InVarOrLetPattern != IVOLP_InVar);
+ auto specifier = (InVarOrLetPattern != IVOLP_InVar)
+ ? VarDecl::Specifier::Let
+ : VarDecl::Specifier::Var;
+ auto pattern = createBindingFromPattern(loc, name, specifier);
Result = makeParserResult(new (Context) UnresolvedPatternExpr(pattern));
break;
}
@@ -2319,8 +2321,11 @@
// Create the VarDecl and the PatternBindingDecl for the captured
// expression. This uses the parent declcontext (not the closure) since
// the initializer expression is evaluated before the closure is formed.
+ auto specifierKind = (ownershipKind != Ownership::Weak)
+ ? VarDecl::Specifier::Let
+ : VarDecl::Specifier::Var;
auto *VD = new (Context) VarDecl(/*isStatic*/false,
- /*isLet*/ownershipKind !=Ownership::Weak,
+ specifierKind,
/*isCaptureList*/true,
nameLoc, name, Type(), CurDeclContext);
@@ -2368,7 +2373,7 @@
Identifier name = Tok.is(tok::identifier) ?
Context.getIdentifier(Tok.getText()) : Identifier();
- auto var = new (Context) ParamDecl(/*IsLet*/ true, SourceLoc(),
+ auto var = new (Context) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), Identifier(),
Tok.getLoc(), name, Type(), nullptr);
elements.push_back(var);
@@ -2667,7 +2672,7 @@
StringRef varName = ("$" + Twine(nextIdx)).toStringRef(StrBuf);
Identifier ident = Context.getIdentifier(varName);
SourceLoc varLoc = leftBraceLoc;
- auto *var = new (Context) ParamDecl(/*IsLet*/ true, SourceLoc(),SourceLoc(),
+ auto *var = new (Context) ParamDecl(VarDecl::Specifier::None, SourceLoc(),SourceLoc(),
Identifier(), varLoc, ident, Type(),
closure);
var->setImplicit();
diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp
index 0091b62..2a5a5fc 100644
--- a/lib/Parse/ParsePattern.cpp
+++ b/lib/Parse/ParsePattern.cpp
@@ -184,20 +184,20 @@
bool hasSpecifier = false;
while (Tok.isAny(tok::kw_inout, tok::kw_let, tok::kw_var)) {
if (!hasSpecifier) {
- if (Tok.is(tok::kw_let)) {
- diagnose(Tok, diag::parameter_let_as_attr)
- .fixItRemove(Tok.getLoc());
+ if (Tok.is(tok::kw_inout)) {
+ // This case is handled later when mapping to ParamDecls for
+ // better fixits.
+ param.SpecifierKind = VarDecl::Specifier::InOut;
} else {
- // We handle the var error in sema for a better fixit and inout is
- // handled later in this function for better fixits.
- param.SpecifierKind = Tok.is(tok::kw_inout) ? ParsedParameter::InOut :
- ParsedParameter::Var;
+ diagnose(Tok, diag::parameter_let_var_as_attr,
+ unsigned(Tok.is(tok::kw_let)))
+ .fixItRemove(Tok.getLoc());
}
- param.LetVarInOutLoc = consumeToken();
+ param.SpecifierLoc = consumeToken();
hasSpecifier = true;
} else {
- // Redundant specifiers are fairly common, recognize, reject, and recover
- // from this gracefully.
+ // Redundant specifiers are fairly common, recognize, reject, and
+ // recover from this gracefully.
diagnose(Tok, diag::parameter_inout_var_let_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
@@ -341,9 +341,8 @@
Identifier argName, SourceLoc argNameLoc,
Identifier paramName, SourceLoc paramNameLoc)
-> ParamDecl * {
- auto specifierKind = paramInfo.SpecifierKind;
- bool isLet = specifierKind == Parser::ParsedParameter::Let;
- auto param = new (ctx) ParamDecl(isLet, paramInfo.LetVarInOutLoc,
+ auto param = new (ctx) ParamDecl(paramInfo.SpecifierKind,
+ paramInfo.SpecifierLoc,
argNameLoc, argName,
paramNameLoc, paramName, Type(),
parser.CurDeclContext);
@@ -359,8 +358,8 @@
// If a type was provided, create the type for the parameter.
if (auto type = paramInfo.Type) {
// If 'inout' was specified, turn the type into an in-out type.
- if (specifierKind == Parser::ParsedParameter::InOut) {
- auto InOutLoc = paramInfo.LetVarInOutLoc;
+ if (paramInfo.SpecifierKind == VarDecl::Specifier::InOut) {
+ auto InOutLoc = paramInfo.SpecifierLoc;
if (isa<InOutTypeRepr>(type)) {
parser.diagnose(InOutLoc, diag::parameter_inout_var_let_repeated)
.fixItRemove(InOutLoc);
@@ -379,10 +378,10 @@
param->getTypeLoc() = TypeLoc::withoutLoc(ErrorType::get(ctx));
param->setInvalid();
- } else if (specifierKind == Parser::ParsedParameter::InOut) {
- parser.diagnose(paramInfo.LetVarInOutLoc, diag::inout_must_have_type);
- paramInfo.LetVarInOutLoc = SourceLoc();
- specifierKind = Parser::ParsedParameter::Let;
+ } else if (paramInfo.SpecifierKind == VarDecl::Specifier::InOut) {
+ parser.diagnose(paramInfo.SpecifierLoc, diag::inout_must_have_type);
+ paramInfo.SpecifierLoc = SourceLoc();
+ paramInfo.SpecifierKind = VarDecl::Specifier::None;
}
return param;
};
@@ -797,12 +796,14 @@
case tok::identifier: {
Identifier name;
SourceLoc loc = consumeIdentifier(&name);
- bool isLet = InVarOrLetPattern != IVOLP_InVar;
-
+ bool isLet = (InVarOrLetPattern != IVOLP_InVar);
+ auto specifier = isLet
+ ? VarDecl::Specifier::Let
+ : VarDecl::Specifier::Var;
if (Tok.isIdentifierOrUnderscore() && !Tok.isContextualDeclKeyword())
diagnoseConsecutiveIDs(name.str(), loc, isLet ? "constant" : "variable");
- return makeParserResult(createBindingFromPattern(loc, name, isLet));
+ return makeParserResult(createBindingFromPattern(loc, name, specifier));
}
case tok::code_complete:
@@ -856,8 +857,8 @@
}
Pattern *Parser::createBindingFromPattern(SourceLoc loc, Identifier name,
- bool isLet) {
- auto var = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/isLet,
+ VarDecl::Specifier specifier) {
+ auto var = new (Context) VarDecl(/*IsStatic*/false, specifier,
/*IsCaptureList*/false, loc, name, Type(),
CurDeclContext);
return new (Context) NamedPattern(var);
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index 821ee5e..7d2f8c6 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -5100,7 +5100,7 @@
// This is only used for parsing associated conformances, so we can
// go ahead and just search the requirement signature for something that
// matches the path.
- for (auto &reqt : proto->getRequirementSignature()->getRequirements()) {
+ for (auto &reqt : proto->getRequirementSignature()) {
if (reqt.getKind() != RequirementKind::Conformance)
continue;
CanType assocType = reqt.getFirstType()->getCanonicalType();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index fdf630c..10937cf 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -882,7 +882,8 @@
P.Tok.isAny(tok::l_brace, tok::kw_where)) {
auto loc = P.Tok.getLoc();
auto errorName = P.Context.Id_error;
- auto var = new (P.Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto var = new (P.Context) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false, loc, errorName,
Type(), P.CurDeclContext);
var->setImplicit();
diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp
index 096c24d..5f23538 100644
--- a/lib/PrintAsObjC/PrintAsObjC.cpp
+++ b/lib/PrintAsObjC/PrintAsObjC.cpp
@@ -1719,7 +1719,7 @@
os << ")(";
Type paramsTy = FT->getInput();
if (auto tupleTy = paramsTy->getAs<TupleType>()) {
- if (tupleTy->getNumElements() == 0) {
+ if (FT->getParams().empty()) {
os << "void";
} else {
interleave(tupleTy->getElements(),
diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp
index 2f002ef..1007ee7 100644
--- a/lib/SILGen/SILGenConstructor.cpp
+++ b/lib/SILGen/SILGenConstructor.cpp
@@ -34,7 +34,7 @@
Type metatype = ctor->getInterfaceType()->castTo<AnyFunctionType>()->getInput();
auto *DC = ctor->getInnermostDeclContext();
auto &AC = gen.getASTContext();
- auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(),
+ auto VD = new (AC) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
AC.getIdentifier("$metatype"), SourceLoc(),
AC.getIdentifier("$metatype"), Type(),
DC);
@@ -61,7 +61,7 @@
return tuple;
} else {
auto &AC = gen.getASTContext();
- auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(),
+ auto VD = new (AC) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
AC.getIdentifier("$implicit_value"),
SourceLoc(),
AC.getIdentifier("$implicit_value"), Type(),
@@ -88,7 +88,8 @@
SILValue resultSlot;
if (selfTy.isAddressOnly(gen.SGM.M) && gen.silConv.useLoweredAddresses()) {
auto &AC = gen.getASTContext();
- auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(),
+ auto VD = new (AC) ParamDecl(VarDecl::Specifier::InOut,
+ SourceLoc(), SourceLoc(),
AC.getIdentifier("$return_value"),
SourceLoc(),
AC.getIdentifier("$return_value"), Type(),
@@ -369,7 +370,8 @@
std::unique_ptr<Initialization> dest;
if (enumTI.isAddressOnly() && silConv.useLoweredAddresses()) {
auto &AC = getASTContext();
- auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(),
+ auto VD = new (AC) ParamDecl(VarDecl::Specifier::InOut,
+ SourceLoc(), SourceLoc(),
AC.getIdentifier("$return_value"),
SourceLoc(),
AC.getIdentifier("$return_value"), Type(),
diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp
index 3f3333d..fd32d55 100644
--- a/lib/SILGen/SILGenProlog.cpp
+++ b/lib/SILGen/SILGenProlog.cpp
@@ -484,7 +484,8 @@
return;
}
auto &ctx = gen.getASTContext();
- auto var = new (ctx) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(),
+ auto var = new (ctx) ParamDecl(VarDecl::Specifier::InOut,
+ SourceLoc(), SourceLoc(),
ctx.getIdentifier("$return_value"), SourceLoc(),
ctx.getIdentifier("$return_value"), Type(),
DC);
diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
index 89d186c..7f5b5c0 100644
--- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp
+++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
@@ -452,7 +452,7 @@
for (auto resultTy : pass.loweredFnConv.getIndirectSILResultTypes()) {
auto bodyResultTy = pass.F->mapTypeIntoContext(resultTy);
auto var = new (ctx)
- ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(),
+ ParamDecl(VarDecl::Specifier::InOut, SourceLoc(), SourceLoc(),
ctx.getIdentifier("$return_value"), SourceLoc(),
ctx.getIdentifier("$return_value"),
bodyResultTy.getSwiftRValueType(), pass.F->getDeclContext());
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 6fa592f..b71f1f2 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -6157,28 +6157,30 @@
if (!fnType)
return false;
- auto expectedArgType = FunctionType::get(fnType->getInput(), resultType,
- fnType->getExtInfo());
-
- auto expectedType =
- FunctionType::get(expectedArgType, CS->getContextualType());
-
class ClosureCalleeListener : public ExprTypeCheckListener {
- Type contextualType;
+ Type InputType;
+ Type ResultType;
public:
- explicit ClosureCalleeListener(Type contextualType)
- : contextualType(contextualType) {}
+ explicit ClosureCalleeListener(Type inputType, Type resultType)
+ : InputType(inputType), ResultType(resultType) {}
bool builtConstraints(ConstraintSystem &cs, Expr *expr) override {
+ if (!InputType || !ResultType)
+ return false;
+
+ auto expectedType = FunctionType::get(InputType, ResultType);
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
- contextualType, cs.getConstraintLocator(expr),
+ expectedType, cs.getConstraintLocator(expr),
/*isFavored*/ true);
return false;
}
};
- ClosureCalleeListener listener(expectedType);
+ auto expectedArgType = FunctionType::get(fnType->getInput(), resultType,
+ fnType->getExtInfo());
+
+ ClosureCalleeListener listener(expectedArgType, CS->getContextualType());
return !typeCheckChildIndependently(callExpr->getFn(), Type(),
CTP_CalleeResult, TCC_ForceRecheck,
&listener);
@@ -6192,7 +6194,7 @@
return false;
}
-/// Check if there failure associated with expresssion is related
+/// Check if there failure associated with expression is related
/// to given contextual type.
bool FailureDiagnosis::diagnoseCallContextualConversionErrors(
ApplyExpr *callExpr, Type contextualType) {
@@ -7165,7 +7167,7 @@
!resultType->hasTypeVariable();
};
- // If there an expected result type but it hasn't been explictly
+ // If there an expected result type but it hasn't been explicitly
// provided, let's add it to the argument.
if (hasResult(resultType) && !CE->hasExplicitResultType()) {
nameOS << " -> ";
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 70ab7b2..cb3ace4 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -696,8 +696,7 @@
auto fTy = VD->getInterfaceType()->getAs<AnyFunctionType>();
assert(fTy && "attempting to count parameters of a non-function type");
- auto inputTy = fTy->getInput();
- size_t nOperands = getOperandCount(inputTy);
+ size_t nOperands = fTy->getParams().size();
size_t nNoDefault = 0;
if (auto AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index ede0a70..14a3d5b 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1175,7 +1175,7 @@
ConstraintKind kind,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
- // FIXME: Fees like a hack.
+ // FIXME: Feels like a hack.
if (type1->is<InOutType>())
return SolutionKind::Error;
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 9589abd..6ae4189 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -60,9 +60,9 @@
StringRef name,
Type type,
Type interfaceType,
- bool isLet) {
+ VarDecl::Specifier specifier) {
auto &context = DC->getASTContext();
- auto *param = new (context) ParamDecl(isLet, SourceLoc(), SourceLoc(),
+ auto *param = new (context) ParamDecl(specifier, SourceLoc(), SourceLoc(),
Identifier(), loc,
context.getIdentifier(name),
type, DC);
@@ -75,7 +75,8 @@
StringRef name,
Type type,
Type interfaceType) {
- return buildArgument(loc, DC, name, type, interfaceType, /*isLet*/ true);
+ return buildArgument(loc, DC, name, type, interfaceType,
+ VarDecl::Specifier::None);
}
static ParamDecl *buildInOutArgument(SourceLoc loc, DeclContext *DC,
@@ -86,7 +87,7 @@
loc, DC, name,
InOutType::get(type),
InOutType::get(interfaceType),
- /*isLet*/ false);
+ VarDecl::Specifier::InOut);
}
static Type getTypeOfStorage(AbstractStorageDecl *storage,
@@ -963,7 +964,7 @@
Expr *OldValueExpr
= createPropertyLoadOrCallSuperclassGetter(Set, VD, TC);
- OldValue = new (Ctx) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ OldValue = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Ctx.getIdentifier("tmp"), Type(), Set);
OldValue->setImplicit();
@@ -1086,7 +1087,7 @@
SmallVector<ASTNode, 6> Body;
// Load the existing storage and store it into the 'tmp1' temporary.
- auto *Tmp1VD = new (Ctx) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto *Tmp1VD = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Ctx.getIdentifier("tmp1"), Type(), Get);
Tmp1VD->setImplicit();
@@ -1124,7 +1125,7 @@
/*implicit*/ true, Ctx));
- auto *Tmp2VD = new (Ctx) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto *Tmp2VD = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Ctx.getIdentifier("tmp2"), VD->getType(),
Get);
@@ -1200,8 +1201,11 @@
SmallString<64> NameBuf = VD->getName().str();
NameBuf += ".storage";
auto StorageName = Context.getIdentifier(NameBuf);
+ auto storageSpecifier = BehaviorStorage->isSettable(DC)
+ ? VarDecl::Specifier::Var
+ : VarDecl::Specifier::Let;
auto *Storage = new (Context) VarDecl(
- /*IsStatic*/VD->isStatic(), /*IsLet*/!BehaviorStorage->isSettable(DC),
+ /*IsStatic*/VD->isStatic(), storageSpecifier,
/*IsCaptureList*/false, VD->getLoc(), StorageName, SubstStorageContextTy,
DC);
Storage->setInterfaceType(SubstStorageInterfaceTy);
@@ -1387,7 +1391,8 @@
llvm::raw_svector_ostream names(ParamNameBuf);
names << "%arg." << i;
}
- auto param = new (Context) ParamDecl(/*let*/ true, SourceLoc(), SourceLoc(),
+ auto param = new (Context) ParamDecl(VarDecl::Specifier::None,
+ SourceLoc(), SourceLoc(),
Identifier(),
SourceLoc(),
Context.getIdentifier(ParamNameBuf),
@@ -1484,7 +1489,8 @@
if (!fromMutating
&& toAccessor->getImplicitSelfDecl()->isSettable(toAccessor)) {
selfExpr->setType(selfTy);
- auto var = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/false,
+ auto var = new (Context) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Var,
/*IsCaptureList*/false, SourceLoc(),
Context.getIdentifier("tempSelf"),
selfTy, fromAccessor);
@@ -1595,7 +1601,7 @@
auto StorageTy = OptionalType::get(VD->getType());
auto StorageInterfaceTy = OptionalType::get(VD->getInterfaceType());
- auto *Storage = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/false,
+ auto *Storage = new (Context) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Var,
/*IsCaptureList*/false, VD->getLoc(),
StorageName, StorageTy,
VD->getDeclContext());
@@ -1940,7 +1946,7 @@
}
// Create the parameter.
- auto *arg = new (context) ParamDecl(/*IsLet*/true, SourceLoc(),
+ auto *arg = new (context) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
Loc, var->getName(),
Loc, var->getName(), varType, decl);
arg->setInterfaceType(varInterfaceType);
diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp
index d5617a5..5b038a9 100644
--- a/lib/Sema/DerivedConformanceCodable.cpp
+++ b/lib/Sema/DerivedConformanceCodable.cpp
@@ -460,17 +460,17 @@
///
/// \param keyType The key type to bind to the container type.
///
-/// \param isLet Whether to declare the variable as immutable.
+/// \param spec Whether to declare the variable as immutable.
static VarDecl *createKeyedContainer(ASTContext &C, DeclContext *DC,
NominalTypeDecl *keyedContainerDecl,
- Type keyType, bool isLet) {
+ Type keyType, VarDecl::Specifier spec) {
// Bind Keyed*Container to Keyed*Container<KeyType>
Type boundType[1] = {keyType};
auto containerType = BoundGenericType::get(keyedContainerDecl, Type(),
C.AllocateCopy(boundType));
// let container : Keyed*Container<KeyType>
- auto *containerDecl = new (C) VarDecl(/*IsStatic=*/false, /*IsLet=*/isLet,
+ auto *containerDecl = new (C) VarDecl(/*IsStatic=*/false, spec,
/*IsCaptureList=*/false, SourceLoc(),
C.Id_container, containerType, DC);
containerDecl->setImplicit();
@@ -495,7 +495,7 @@
Expr *base, Type returnType,
NominalTypeDecl *param) {
// (keyedBy:)
- auto *keyedByDecl = new (C) ParamDecl(/*IsLet=*/true, SourceLoc(),
+ auto *keyedByDecl = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), C.Id_keyedBy, SourceLoc(),
C.Id_keyedBy, returnType, DC);
keyedByDecl->setImplicit();
@@ -568,7 +568,8 @@
auto codingKeysType = codingKeysEnum->getDeclaredType();
auto *containerDecl = createKeyedContainer(C, funcDC,
C.getKeyedEncodingContainerDecl(),
- codingKeysType, /*isLet=*/false);
+ codingKeysType,
+ VarDecl::Specifier::Var);
auto *containerExpr = new (C) DeclRefExpr(ConcreteDeclRef(containerDecl),
DeclNameLoc(), /*Implicit=*/true,
@@ -736,7 +737,7 @@
// Params: (self [implicit], Encoder)
auto *selfDecl = ParamDecl::createSelf(SourceLoc(), target);
- auto *encoderParam = new (C) ParamDecl(/*isLet=*/true, SourceLoc(),
+ auto *encoderParam = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), C.Id_to, SourceLoc(),
C.Id_encoder, encoderType, target);
encoderParam->setInterfaceType(encoderType);
@@ -833,7 +834,8 @@
auto codingKeysType = codingKeysEnum->getDeclaredType();
auto *containerDecl = createKeyedContainer(C, funcDC,
C.getKeyedDecodingContainerDecl(),
- codingKeysType, /*isLet=*/true);
+ codingKeysType,
+ VarDecl::Specifier::Let);
auto *containerExpr = new (C) DeclRefExpr(ConcreteDeclRef(containerDecl),
DeclNameLoc(), /*Implicit=*/true,
@@ -1036,7 +1038,8 @@
auto *selfDecl = ParamDecl::createSelf(SourceLoc(), target,
/*isStatic=*/false,
/*isInOut=*/inOut);
- auto *decoderParamDecl = new (C) ParamDecl(/*isLet=*/true, SourceLoc(),
+ auto *decoderParamDecl = new (C) ParamDecl(VarDecl::Specifier::None,
+ SourceLoc(),
SourceLoc(), C.Id_from,
SourceLoc(), C.Id_decoder,
decoderType, target);
diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp
index 055b973..3117c88 100644
--- a/lib/Sema/DerivedConformanceCodingKey.cpp
+++ b/lib/Sema/DerivedConformanceCodingKey.cpp
@@ -74,7 +74,7 @@
DeclNameLoc(), /*Implicit=*/true);
// rawValue param to init(rawValue:)
- auto *rawValueDecl = new (C) ParamDecl(/*IsLet=*/true, SourceLoc(),
+ auto *rawValueDecl = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), C.Id_rawValue,
SourceLoc(), C.Id_rawValue,
valueParam->getType(), parentDC);
@@ -124,7 +124,7 @@
auto *parentDC = cast<DeclContext>(parentDecl);
// rawValue
- auto *rawDecl = new (C) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(),
+ auto *rawDecl = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
paramName, SourceLoc(), paramName,
paramType, parentDC);
rawDecl->setInterfaceType(paramType);
diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp
index 6460bd3..c98fda2 100644
--- a/lib/Sema/DerivedConformanceEquatableHashable.cpp
+++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp
@@ -70,7 +70,7 @@
Type enumType = enumVarDecl->getType();
Type intType = C.getIntDecl()->getDeclaredType();
- auto indexVar = new (C) VarDecl(/*IsStatic*/false, /*IsLet*/false,
+ auto indexVar = new (C) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Var,
/*IsCaptureList*/false, SourceLoc(),
C.getIdentifier(indexName), intType,
funcDecl);
@@ -217,7 +217,7 @@
auto enumIfaceTy = parentDC->getDeclaredInterfaceType();
auto getParamDecl = [&](StringRef s) -> ParamDecl* {
- auto *param = new (C) ParamDecl(/*isLet*/true, SourceLoc(), SourceLoc(),
+ auto *param = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
Identifier(), SourceLoc(), C.getIdentifier(s),
enumTy, parentDC);
param->setInterfaceType(enumIfaceTy);
@@ -438,7 +438,7 @@
tc.Context.addExternalDecl(getterDecl);
// Create the property.
- VarDecl *hashValueDecl = new (C) VarDecl(/*IsStatic*/false, /*IsLet*/false,
+ VarDecl *hashValueDecl = new (C) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Var,
/*IsCaptureList*/false, SourceLoc(),
C.Id_hashValue, intType, parentDC);
hashValueDecl->setImplicit();
diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp
index c4a6a14..7a904ac 100644
--- a/lib/Sema/DerivedConformanceRawRepresentable.cpp
+++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp
@@ -267,7 +267,7 @@
auto *selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC,
/*static*/false, /*inout*/true);
- auto *rawDecl = new (C) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(),
+ auto *rawDecl = new (C) ParamDecl(VarDecl::Specifier::None, SourceLoc(), SourceLoc(),
C.Id_rawValue, SourceLoc(),
C.Id_rawValue, rawType, parentDC);
rawDecl->setInterfaceType(rawInterfaceType);
diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp
index 0da7a06..5c890bb 100644
--- a/lib/Sema/DerivedConformances.cpp
+++ b/lib/Sema/DerivedConformances.cpp
@@ -195,7 +195,7 @@
auto &C = tc.Context;
auto parentDC = cast<DeclContext>(parentDecl);
- VarDecl *propDecl = new (C) VarDecl(/*IsStatic*/isStatic, /*IsLet*/false,
+ VarDecl *propDecl = new (C) VarDecl(/*IsStatic*/isStatic, VarDecl::Specifier::Var,
/*IsCaptureList*/false, SourceLoc(), name,
propertyContextType, parentDC);
propDecl->setImplicit();
diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp
index 275c6ba..3aef650 100644
--- a/lib/Sema/PCMacro.cpp
+++ b/lib/Sema/PCMacro.cpp
@@ -479,7 +479,7 @@
}
VarDecl *VD =
- new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ new (Context) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Context.getIdentifier(NameBuf),
MaybeLoadInitExpr->getType(), TypeCheckDC);
diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp
index c7d0abc..a9173c1 100644
--- a/lib/Sema/PlaygroundTransform.cpp
+++ b/lib/Sema/PlaygroundTransform.cpp
@@ -744,7 +744,7 @@
}
VarDecl *VD =
- new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ new (Context) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Context.getIdentifier(NameBuf),
MaybeLoadInitExpr->getType(), TypeCheckDC);
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index 864e5a7..05917db0 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -2651,7 +2651,8 @@
PrettyStackTracePattern stackTrace(Context, "type-checking", EP);
// Create a 'let' binding to stand in for the RHS value.
- auto *matchVar = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto *matchVar = new (Context) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false,
EP->getLoc(),
Context.getIdentifier("$match"),
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 16634bb..63fe3b1 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -4709,7 +4709,9 @@
TC.checkDeclAttributes(PD);
if (TC.Context.LangOpts.DebugGenericSignatures) {
- auto requirementsSig = PD->getRequirementSignature();
+ auto requirementsSig =
+ GenericSignature::get({PD->getProtocolSelfType()},
+ PD->getRequirementSignature());
llvm::errs() << "Protocol requirement signature:\n";
PD->dumpRef(llvm::errs());
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 14d3a99..0fb3173 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -131,76 +131,89 @@
ArchetypeResolutionKind::CompleteWellFormed);
assert(basePA && "Missing potential archetype for base");
- // Local function to produce an error "no such member type" and return.
- auto invalidMemberType = [&] {
- // Complain that there is no suitable type.
- Identifier name = ref->getIdentifier();
- SourceLoc nameLoc = ref->getIdLoc();
- TC.diagnose(nameLoc, diag::invalid_member_type, name, baseTy)
- .highlight(baseRange);
- return ErrorType::get(TC.Context);
- };
-
// Retrieve the potential archetype for the nested type.
auto nestedPA = basePA->getNestedType(ref->getIdentifier(),
ArchetypeResolutionKind::WellFormed,
Builder);
- if (!nestedPA)
- return invalidMemberType();
- // If this potential archetype was renamed due to typo correction,
- // complain and fix it.
- if (nestedPA->wasRenamed()) {
- auto newName = nestedPA->getNestedName();
+ // If there was no such nested type, produce an error.
+ if (!nestedPA) {
+ // Perform typo correction.
+ LookupResult corrections;
+ TC.performTypoCorrection(DC, DeclRefKind::Ordinary,
+ MetatypeType::get(baseTy),
+ ref->getIdentifier(), ref->getIdLoc(),
+ NameLookupFlags::ProtocolMembers,
+ corrections, &Builder);
+
+ // Filter out non-types.
+ corrections.filter([](const LookupResult::Result &result) {
+ return isa<TypeDecl>(result.Decl);
+ });
+
+ // Check whether we have a single type result.
+ auto singleType = corrections.getSingleTypeResult();
+
+ // If we don't have a single result, complain and fail.
+ if (!singleType) {
+ Identifier name = ref->getIdentifier();
+ SourceLoc nameLoc = ref->getIdLoc();
+ TC.diagnose(nameLoc, diag::invalid_member_type, name, baseTy)
+ .highlight(baseRange);
+ for (const auto &suggestion : corrections)
+ TC.noteTypoCorrection(name, DeclNameLoc(nameLoc), suggestion);
+
+ return ErrorType::get(TC.Context);
+ }
+
+ // We have a single type result. Suggest it.
TC.diagnose(ref->getIdLoc(), diag::invalid_member_type_suggest,
- baseTy, ref->getIdentifier(), newName)
- .fixItReplace(ref->getIdLoc(), newName.str());
- ref->overwriteIdentifier(newName);
- nestedPA->setAlreadyDiagnosedRename();
-
- // Go get the actual nested type.
- nestedPA = basePA->getNestedType(newName,
- ArchetypeResolutionKind::WellFormed,
- Builder);
- assert(nestedPA && "Nested type should have been available");
- assert(!nestedPA->wasRenamed());
+ baseTy, ref->getIdentifier(),
+ singleType->getBaseName().getIdentifier())
+ .fixItReplace(ref->getIdLoc(),
+ singleType->getBaseName().userFacingName());
+
+ // Correct to the single type result.
+ ref->overwriteIdentifier(singleType->getBaseName().getIdentifier());
+ ref->setValue(singleType);
+ } else if (auto assocType = nestedPA->getResolvedAssociatedType()) {
+ ref->setValue(assocType);
+ } else {
+ assert(nestedPA->getConcreteTypeDecl());
+ ref->setValue(nestedPA->getConcreteTypeDecl());
}
// If the nested type has been resolved to an associated type, use it.
- if (auto assocType = nestedPA->getResolvedAssociatedType()) {
- ref->setValue(assocType);
+ if (auto assocType = dyn_cast<AssociatedTypeDecl>(ref->getBoundDecl())) {
return DependentMemberType::get(baseTy, assocType);
}
- // If the nested type comes from a concrete type, substitute the base type
- // into it.
- if (auto concrete = nestedPA->getConcreteTypeDecl()) {
- ref->setValue(concrete);
-
- if (baseTy->isTypeParameter()) {
- if (auto proto =
- concrete->getDeclContext()
- ->getAsProtocolOrProtocolExtensionContext()) {
- TC.validateDecl(proto);
- auto subMap = SubstitutionMap::getProtocolSubstitutions(
- proto, baseTy, ProtocolConformanceRef(proto));
- return concrete->getDeclaredInterfaceType().subst(subMap);
- }
-
- if (auto superclass = basePA->getSuperclass()) {
- return superclass->getTypeOfMember(
- DC->getParentModule(), concrete,
- concrete->getDeclaredInterfaceType());
- }
-
- llvm_unreachable("shouldn't have a concrete decl here");
+ // Otherwise, the nested type comes from a concrete tpye. Substitute the
+ // base type into it.
+ auto concrete = ref->getBoundDecl();
+ TC.validateDeclForNameLookup(concrete);
+ if (!concrete->hasInterfaceType())
+ return ErrorType::get(TC.Context);
+ if (baseTy->isTypeParameter()) {
+ if (auto proto =
+ concrete->getDeclContext()
+ ->getAsProtocolOrProtocolExtensionContext()) {
+ TC.validateDecl(proto);
+ auto subMap = SubstitutionMap::getProtocolSubstitutions(
+ proto, baseTy, ProtocolConformanceRef(proto));
+ return concrete->getDeclaredInterfaceType().subst(subMap);
}
- return TC.substMemberTypeWithBase(DC->getParentModule(), concrete, baseTy);
+ if (auto superclass = basePA->getSuperclass()) {
+ return superclass->getTypeOfMember(
+ DC->getParentModule(), concrete,
+ concrete->getDeclaredInterfaceType());
+ }
+
+ llvm_unreachable("shouldn't have a concrete decl here");
}
- assert(nestedPA->isUnresolved() && "meaningless unresolved type");
- return invalidMemberType();
+ return TC.substMemberTypeWithBase(DC->getParentModule(), concrete, baseTy);
}
bool CompleteGenericTypeResolver::areSameType(Type type1, Type type2) {
@@ -747,8 +760,6 @@
allGenericParams);
if (checkGenericFuncSignature(*this, nullptr, func, completeResolver))
invalid = true;
- if (builder.diagnoseRemainingRenames(func->getLoc(), allGenericParams))
- invalid = true;
// The generic function signature is complete and well-formed. Determine
// the type of the generic function.
@@ -981,8 +992,6 @@
allGenericParams);
if (checkGenericSubscriptSignature(*this, nullptr, subscript, completeResolver))
invalid = true;
- if (builder.diagnoseRemainingRenames(subscript->getLoc(), allGenericParams))
- invalid = true;
// The generic subscript signature is complete and well-formed. Determine
// the type of the generic subscript.
@@ -1124,10 +1133,6 @@
&completeResolver);
}
- // Complain about any other renamed references.
- (void)builder.diagnoseRemainingRenames(genericParams->getSourceRange().Start,
- allGenericParams);
-
// Record the generic type parameter types and the requirements.
auto sig = builder.getGenericSignature();
diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp
index 7dfa084..939b307 100644
--- a/lib/Sema/TypeCheckNameLookup.cpp
+++ b/lib/Sema/TypeCheckNameLookup.cpp
@@ -562,6 +562,7 @@
SourceLoc nameLoc,
NameLookupOptions lookupOptions,
LookupResult &result,
+ GenericSignatureBuilder *gsb,
unsigned maxResults) {
// Disable typo-correction if we won't show the diagnostic anyway.
if (getLangOpts().DisableTypoCorrection ||
@@ -602,7 +603,7 @@
TypoCorrectionResolver resolver(*this, nameLoc);
if (baseTypeOrNull) {
lookupVisibleMemberDecls(consumer, baseTypeOrNull, DC, &resolver,
- /*include instance members*/ true);
+ /*include instance members*/ true, gsb);
} else {
lookupVisibleDecls(consumer, DC, &resolver, /*top level*/ true, nameLoc);
}
diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp
index e3bfc9c..0556b0e 100644
--- a/lib/Sema/TypeCheckPattern.cpp
+++ b/lib/Sema/TypeCheckPattern.cpp
@@ -671,74 +671,6 @@
return hadError;
}
-static void diagnoseAndMigrateVarParameterToBody(ParamDecl *decl,
- AbstractFunctionDecl *func,
- TypeChecker &TC) {
- if (!func || !func->hasBody()) {
- // If there is no function body, just suggest removal.
- TC.diagnose(decl->getLetVarInOutLoc(),
- diag::var_parameter_not_allowed)
- .fixItRemove(decl->getLetVarInOutLoc());
- return;
- }
- // Insert the shadow copy. The computations that follow attempt to
- // 'best guess' the indentation and new lines so that the user
- // doesn't have to add any whitespace.
- auto declBody = func->getBody();
-
- auto &SM = TC.Context.SourceMgr;
-
- SourceLoc insertionStartLoc;
- std::string start;
- std::string end;
-
- auto lBraceLine = SM.getLineNumber(declBody->getLBraceLoc());
- auto rBraceLine = SM.getLineNumber(declBody->getRBraceLoc());
-
- if (!declBody->getNumElements()) {
-
- // Empty function body.
- insertionStartLoc = declBody->getRBraceLoc();
-
- if (lBraceLine == rBraceLine) {
- // Same line braces, means we probably have something
- // like {} as the func body. Insert directly into body with spaces.
- start = " ";
- end = " ";
- } else {
- // Different line braces, so use RBrace's indentation.
- end = "\n" + Lexer::getIndentationForLine(SM, declBody->
- getRBraceLoc()).str();
- start = " "; // Guess 4 spaces as extra indentation.
- }
- } else {
- auto firstLine = declBody->getElement(0);
- insertionStartLoc = firstLine.getStartLoc();
- if (lBraceLine == SM.getLineNumber(firstLine.getStartLoc())) {
- // Function on same line, insert with semi-colon. Not ideal but
- // better than weird space alignment.
- start = "";
- end = "; ";
- } else {
- start = "";
- end = "\n" + Lexer::getIndentationForLine(SM, firstLine.
- getStartLoc()).str();
- }
- }
- if (insertionStartLoc.isInvalid()) {
- TC.diagnose(decl->getLetVarInOutLoc(),
- diag::var_parameter_not_allowed)
- .fixItRemove(decl->getLetVarInOutLoc());
- return;
- }
- auto parameterName = decl->getNameStr().str();
- TC.diagnose(decl->getLetVarInOutLoc(),
- diag::var_parameter_not_allowed)
- .fixItRemove(decl->getLetVarInOutLoc())
- .fixItInsert(insertionStartLoc, start + "var " + parameterName + " = " +
- parameterName + end);
-}
-
static bool validateParameterType(ParamDecl *decl, DeclContext *DC,
TypeResolutionOptions options,
GenericTypeResolver &resolver,
@@ -772,7 +704,7 @@
// If the user did not explicitly write 'let', 'var', or 'inout', we'll let
// type inference figure out what went wrong in detail.
- if (decl->getLetVarInOutLoc().isValid()) {
+ if (decl->getSpecifierLoc().isValid()) {
// If the param is not a 'let' and it is not an 'inout'.
// It must be a 'var'. Provide helpful diagnostics like a shadow copy
// in the function body to fix the 'var' attribute.
@@ -780,8 +712,6 @@
!decl->isImplicit() &&
(Ty.isNull() || !Ty->is<InOutType>()) &&
!hadError) {
- auto func = dyn_cast_or_null<AbstractFunctionDecl>(DC);
- diagnoseAndMigrateVarParameterToBody(decl, func, TC);
decl->setInvalid();
hadError = true;
}
@@ -984,7 +914,8 @@
}
// Create a new match variable $match.
- auto *matchVar = new (tc.Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto *matchVar = new (tc.Context) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false,
pattern->getLoc(),
tc.Context.getIdentifier("$match"),
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index e8336d2..fc52a57 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -4338,7 +4338,9 @@
Proto, Conformance->getType(),
ProtocolConformanceRef(Conformance));
- auto requirementSig = Proto->getRequirementSignature();
+ auto requirementSig =
+ GenericSignature::get({Proto->getProtocolSelfType()},
+ Proto->getRequirementSignature());
auto result =
TC.checkGenericArguments(DC, SourceLoc(), SourceLoc(),
Conformance->getType(), requirementSig,
@@ -5006,7 +5008,8 @@
CheckedRequirementSignature = true;
- auto reqSig = proto->getRequirementSignature();
+ auto reqSig = GenericSignature::get({proto->getProtocolSelfType()},
+ proto->getRequirementSignature());
auto substitutions = SubstitutionMap::getProtocolSubstitutions(
proto, Conformance->getType(), ProtocolConformanceRef(Conformance));
diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp
index d4bb655..3ec7e36 100644
--- a/lib/Sema/TypeCheckREPL.cpp
+++ b/lib/Sema/TypeCheckREPL.cpp
@@ -229,7 +229,7 @@
TopLevelCodeDecl *newTopLevel = new (Context) TopLevelCodeDecl(&SF);
// Build function of type T->() which prints the operand.
- auto *Arg = new (Context) ParamDecl(/*isLet=*/true, SourceLoc(),
+ auto *Arg = new (Context) ParamDecl(VarDecl::Specifier::None, SourceLoc(),
SourceLoc(), Identifier(),
Loc, Context.getIdentifier("arg"),
E->getType(), /*DC*/ newTopLevel);
@@ -308,7 +308,8 @@
// Create the meta-variable, let the typechecker name it.
Identifier name = TC.getNextResponseVariableName(SF.getParentModule());
- VarDecl *vd = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ VarDecl *vd = new (Context) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false, E->getStartLoc(),
name, E->getType(), &SF);
vd->setInterfaceType(E->getType());
@@ -381,7 +382,8 @@
// Create the meta-variable, let the typechecker name it.
Identifier name = TC.getNextResponseVariableName(SF.getParentModule());
- VarDecl *vd = new (Context) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ VarDecl *vd = new (Context) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false,
PBD->getStartLoc(), name,
pattern->getType(), &SF);
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index 60633a6..da46efd 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -664,7 +664,7 @@
name = "$"+np->getBoundName().str().str();
name += "$generator";
generator = new (TC.Context)
- VarDecl(/*IsStatic*/false, /*IsLet*/false, /*IsCaptureList*/false,
+ VarDecl(/*IsStatic*/false, VarDecl::Specifier::Var, /*IsCaptureList*/false,
S->getInLoc(), TC.Context.getIdentifier(name), generatorTy, DC);
generator->setInterfaceType(DC->mapTypeOutOfContext(generatorTy));
generator->setImplicit();
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index bddca16..212a92c 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -2365,6 +2365,7 @@
SourceLoc lookupLoc,
NameLookupOptions lookupOptions,
LookupResult &result,
+ GenericSignatureBuilder *gsb = nullptr,
unsigned maxResults = 4);
void noteTypoCorrection(DeclName name, DeclNameLoc nameLoc,
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 5b53160..dc68761 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -654,16 +654,6 @@
dc->getAsNominalTypeOrNominalTypeExtensionContext()
->registerProtocolConformance(conformance);
- // Read requirement signature conformances.
- SmallVector<ProtocolConformanceRef, 4> reqConformances;
- for (auto req : proto->getRequirementSignature()->getRequirements()) {
- if (req.getKind() == RequirementKind::Conformance) {
- auto reqConformance = readConformance(DeclTypeCursor);
- reqConformances.push_back(reqConformance);
- }
- }
- conformance->setSignatureConformances(reqConformances);
-
// If the conformance is complete, we're done.
if (conformance->isComplete())
return conformance;
@@ -2692,7 +2682,8 @@
case decls_block::VAR_DECL: {
IdentifierID nameID;
DeclContextID contextID;
- bool isImplicit, isObjC, isStatic, isLet, hasNonPatternBindingInit;
+ bool isImplicit, isObjC, isStatic, hasNonPatternBindingInit;
+ unsigned specifier;
uint8_t storageKind, rawAccessLevel, rawSetterAccessLevel;
TypeID interfaceTypeID;
DeclID getterID, setterID, materializeForSetID, willSetID, didSetID;
@@ -2700,7 +2691,7 @@
ArrayRef<uint64_t> dependencyIDs;
decls_block::VarLayout::readRecord(scratch, nameID, contextID,
- isImplicit, isObjC, isStatic, isLet,
+ isImplicit, isObjC, isStatic, specifier,
hasNonPatternBindingInit, storageKind,
interfaceTypeID,
getterID, setterID, materializeForSetID,
@@ -2729,7 +2720,8 @@
if (declOrOffset.isComplete())
return declOrOffset;
- auto var = createDecl<VarDecl>(/*IsStatic*/isStatic, /*IsLet*/isLet,
+ auto var = createDecl<VarDecl>(/*IsStatic*/isStatic,
+ (VarDecl::Specifier)specifier,
/*IsCaptureList*/false, SourceLoc(), name,
Type(), DC);
var->setHasNonPatternBindingInit(hasNonPatternBindingInit);
@@ -2774,17 +2766,18 @@
case decls_block::PARAM_DECL: {
IdentifierID argNameID, paramNameID;
DeclContextID contextID;
- bool isLet;
+ unsigned specifier;
TypeID interfaceTypeID;
decls_block::ParamLayout::readRecord(scratch, argNameID, paramNameID,
- contextID, isLet, interfaceTypeID);
+ contextID, specifier, interfaceTypeID);
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
if (declOrOffset.isComplete())
return declOrOffset;
- auto param = createDecl<ParamDecl>(isLet, SourceLoc(), SourceLoc(),
+ auto param = createDecl<ParamDecl>((VarDecl::Specifier)specifier,
+ SourceLoc(), SourceLoc(),
getIdentifier(argNameID), SourceLoc(),
getIdentifier(paramNameID), Type(), DC);
@@ -3066,9 +3059,7 @@
proto->setImplicit();
proto->computeType();
- auto signature = GenericSignature::get(
- { proto->getProtocolSelfType() }, requirements);
- proto->setRequirementSignature(signature);
+ proto->setRequirementSignature(requirements);
proto->setMemberLoader(this, DeclTypeCursor.GetCurrentBitNo());
proto->setCircularityCheck(CircularityCheck::Checked);
@@ -4596,13 +4587,16 @@
typeCount,
rawIDs);
- // Skip requirement signature conformances.
- auto proto = conformance->getProtocol();
- for (auto req : proto->getRequirementSignature()->getRequirements()) {
+ // Read requirement signature conformances.
+ const ProtocolDecl *proto = conformance->getProtocol();
+ SmallVector<ProtocolConformanceRef, 4> reqConformances;
+ for (const auto &req : proto->getRequirementSignature()) {
if (req.getKind() == RequirementKind::Conformance) {
- (void)readConformance(DeclTypeCursor);
+ auto reqConformance = readConformance(DeclTypeCursor);
+ reqConformances.push_back(reqConformance);
}
}
+ conformance->setSignatureConformances(reqConformances);
ArrayRef<uint64_t>::iterator rawIDIter = rawIDs.begin();
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index c78de3f..f43d585 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -2291,6 +2291,20 @@
llvm_unreachable("Unhandled ForeignErrorConvention in switch.");
}
+/// Translate from the AST VarDeclSpecifier enum to the
+/// Serialization enum values, which are guaranteed to be stable.
+static uint8_t getRawStableVarDeclSpecifier(swift::VarDecl::Specifier sf) {
+ switch (sf) {
+ case swift::VarDecl::Specifier::Let:
+ return uint8_t(serialization::VarDeclSpecifier::Let);
+ case swift::VarDecl::Specifier::Var:
+ return uint8_t(serialization::VarDeclSpecifier::Var);
+ case swift::VarDecl::Specifier::InOut:
+ return uint8_t(serialization::VarDeclSpecifier::InOut);
+ }
+ llvm_unreachable("bad variable decl specifier kind");
+}
+
void Serializer::writeForeignErrorConvention(const ForeignErrorConvention &fec){
using namespace decls_block;
@@ -2807,7 +2821,7 @@
writeGenericParams(proto->getGenericParams());
writeGenericRequirements(
- proto->getRequirementSignature()->getRequirements(), DeclTypeAbbrCodes);
+ proto->getRequirementSignature(), DeclTypeAbbrCodes);
writeMembers(proto->getMembers(), true);
writeDefaultWitnessTable(proto, DeclTypeAbbrCodes);
break;
@@ -2818,7 +2832,7 @@
verifyAttrSerializable(var);
auto contextID = addDeclContextRef(var->getDeclContext());
-
+
Accessors accessors = getAccessors(var);
uint8_t rawAccessLevel =
getRawStableAccessibility(var->getFormalAccess());
@@ -2839,7 +2853,7 @@
var->isImplicit(),
var->isObjC(),
var->isStatic(),
- var->isLet(),
+ getRawStableVarDeclSpecifier(var->getSpecifier()),
var->hasNonPatternBindingInit(),
(unsigned) accessors.Kind,
addTypeRef(ty),
@@ -2868,7 +2882,7 @@
addDeclBaseNameRef(param->getArgumentName()),
addDeclBaseNameRef(param->getName()),
contextID,
- param->isLet(),
+ getRawStableVarDeclSpecifier(param->getSpecifier()),
addTypeRef(interfaceType));
if (interfaceType->hasError()) {
diff --git a/stdlib/public/SDK/Foundation/JSONEncoder.swift b/stdlib/public/SDK/Foundation/JSONEncoder.swift
index c6367be..c7ee7cb 100644
--- a/stdlib/public/SDK/Foundation/JSONEncoder.swift
+++ b/stdlib/public/SDK/Foundation/JSONEncoder.swift
@@ -159,23 +159,23 @@
// MARK: Properties
/// The encoder's storage.
- var storage: _JSONEncodingStorage
+ fileprivate var storage: _JSONEncodingStorage
/// Options set on the top-level encoder.
- let options: JSONEncoder._Options
+ fileprivate let options: JSONEncoder._Options
/// The path to the current point in encoding.
- var codingPath: [CodingKey?]
+ public var codingPath: [CodingKey?]
/// Contextual user-provided information for use during encoding.
- var userInfo: [CodingUserInfoKey : Any] {
+ public var userInfo: [CodingUserInfoKey : Any] {
return self.options.userInfo
}
// MARK: - Initialization
/// Initializes `self` with the given top-level encoder options.
- init(options: JSONEncoder._Options, codingPath: [CodingKey?] = []) {
+ fileprivate init(options: JSONEncoder._Options, codingPath: [CodingKey?] = []) {
self.options = options
self.storage = _JSONEncodingStorage()
self.codingPath = codingPath
@@ -187,7 +187,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -197,7 +197,7 @@
/// Returns whether a new element can be encoded at this coding path.
///
/// `true` if an element has not yet been encoded at this coding path; `false` otherwise.
- var canEncodeNewValue: Bool {
+ fileprivate var canEncodeNewValue: Bool {
// Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container).
// At the same time, every time a container is requested, a new value gets pushed onto the storage stack.
// If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition.
@@ -208,7 +208,7 @@
}
// MARK: - Encoder Methods
- func container<Key>(keyedBy: Key.Type) -> KeyedEncodingContainer<Key> {
+ public func container<Key>(keyedBy: Key.Type) -> KeyedEncodingContainer<Key> {
// If an existing keyed container was already requested, return that one.
let topContainer: NSMutableDictionary
if self.canEncodeNewValue {
@@ -226,7 +226,7 @@
return KeyedEncodingContainer(container)
}
- func unkeyedContainer() -> UnkeyedEncodingContainer {
+ public func unkeyedContainer() -> UnkeyedEncodingContainer {
// If an existing unkeyed container was already requested, return that one.
let topContainer: NSMutableArray
if self.canEncodeNewValue {
@@ -243,7 +243,7 @@
return _JSONUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer)
}
- func singleValueContainer() -> SingleValueEncodingContainer {
+ public func singleValueContainer() -> SingleValueEncodingContainer {
return self
}
}
@@ -255,36 +255,36 @@
/// The container stack.
/// Elements may be any one of the JSON types (NSNull, NSNumber, NSString, NSArray, NSDictionary).
- private(set) var containers: [NSObject] = []
+ private(set) fileprivate var containers: [NSObject] = []
// MARK: - Initialization
/// Initializes `self` with no containers.
- init() {}
+ fileprivate init() {}
// MARK: - Modifying the Stack
- var count: Int {
+ fileprivate var count: Int {
return self.containers.count
}
- mutating func pushKeyedContainer() -> NSMutableDictionary {
+ fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary {
let dictionary = NSMutableDictionary()
self.containers.append(dictionary)
return dictionary
}
- mutating func pushUnkeyedContainer() -> NSMutableArray {
+ fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray {
let array = NSMutableArray()
self.containers.append(array)
return array
}
- mutating func push(container: NSObject) {
+ fileprivate mutating func push(container: NSObject) {
self.containers.append(container)
}
- mutating func popContainer() -> NSObject {
+ fileprivate mutating func popContainer() -> NSObject {
precondition(self.containers.count > 0, "Empty container stack.")
return self.containers.popLast()!
}
@@ -298,18 +298,18 @@
// MARK: Properties
/// A reference to the encoder we're writing to.
- let encoder: _JSONEncoder
+ private let encoder: _JSONEncoder
/// A reference to the container we're writing to.
- let container: NSMutableDictionary
+ private let container: NSMutableDictionary
/// The path of coding keys taken to get to this point in encoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
// MARK: - Initialization
/// Initializes `self` with the given references.
- init(referencing encoder: _JSONEncoder, codingPath: [CodingKey?], wrapping container: NSMutableDictionary) {
+ fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey?], wrapping container: NSMutableDictionary) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -321,7 +321,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -330,40 +330,41 @@
// MARK: - KeyedEncodingContainerProtocol Methods
- mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: String, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encodeNil(forKey key: Key) throws { self.container[key.stringValue] = NSNull() }
+ public mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: String, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Float, forKey key: Key) throws {
+ public mutating func encode(_ value: Float, forKey key: Key) throws {
// Since the float may be invalid and throw, the coding path needs to contain this key.
try self.encoder.with(pushedKey: key) {
self.container[key.stringValue] = try self.encoder.box(value)
}
}
- mutating func encode(_ value: Double, forKey key: Key) throws {
+ public mutating func encode(_ value: Double, forKey key: Key) throws {
// Since the double may be invalid and throw, the coding path needs to contain this key.
try self.encoder.with(pushedKey: key) {
self.container[key.stringValue] = try self.encoder.box(value)
}
}
- mutating func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
+ public mutating func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
try self.encoder.with(pushedKey: key) {
self.container[key.stringValue] = try self.encoder.box(value)
}
}
- mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
+ public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
let dictionary = NSMutableDictionary()
self.container[key.stringValue] = dictionary
@@ -373,7 +374,7 @@
}
}
- mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
+ public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
let array = NSMutableArray()
self.container[key.stringValue] = array
@@ -382,11 +383,11 @@
}
}
- mutating func superEncoder() -> Encoder {
+ public mutating func superEncoder() -> Encoder {
return _JSONReferencingEncoder(referencing: self.encoder, at: _JSONSuperKey.super, wrapping: self.container)
}
- mutating func superEncoder(forKey key: Key) -> Encoder {
+ public mutating func superEncoder(forKey key: Key) -> Encoder {
return _JSONReferencingEncoder(referencing: self.encoder, at: key, wrapping: self.container)
}
}
@@ -395,18 +396,18 @@
// MARK: Properties
/// A reference to the encoder we're writing to.
- let encoder: _JSONEncoder
+ private let encoder: _JSONEncoder
/// A reference to the container we're writing to.
- let container: NSMutableArray
+ private let container: NSMutableArray
/// The path of coding keys taken to get to this point in encoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
// MARK: - Initialization
/// Initializes `self` with the given references.
- init(referencing encoder: _JSONEncoder, codingPath: [CodingKey?], wrapping container: NSMutableArray) {
+ fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey?], wrapping container: NSMutableArray) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -418,7 +419,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -427,40 +428,41 @@
// MARK: - UnkeyedEncodingContainer Methods
- mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encodeNil() throws { self.container.add(NSNull()) }
+ public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Float) throws {
+ public mutating func encode(_ value: Float) throws {
// Since the float may be invalid and throw, the coding path needs to contain this key.
try self.encoder.with(pushedKey: nil) {
self.container.add(try self.encoder.box(value))
}
}
- mutating func encode(_ value: Double) throws {
+ public mutating func encode(_ value: Double) throws {
// Since the double may be invalid and throw, the coding path needs to contain this key.
try self.encoder.with(pushedKey: nil) {
self.container.add(try self.encoder.box(value))
}
}
- mutating func encode<T : Encodable>(_ value: T) throws {
+ public mutating func encode<T : Encodable>(_ value: T) throws {
try self.encoder.with(pushedKey: nil) {
self.container.add(try self.encoder.box(value))
}
}
- mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
+ public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
let dictionary = NSMutableDictionary()
self.container.add(dictionary)
@@ -470,7 +472,7 @@
}
}
- mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
+ public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
let array = NSMutableArray()
self.container.add(array)
@@ -479,7 +481,7 @@
}
}
- mutating func superEncoder() -> Encoder {
+ public mutating func superEncoder() -> Encoder {
return _JSONReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container)
}
}
@@ -487,86 +489,86 @@
extension _JSONEncoder : SingleValueEncodingContainer {
// MARK: - SingleValueEncodingContainer Methods
- func assertCanEncodeNewValue() {
+ fileprivate func assertCanEncodeNewValue() {
precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.")
}
- func encodeNil() throws {
+ public func encodeNil() throws {
assertCanEncodeNewValue()
self.storage.push(container: NSNull())
}
- func encode(_ value: Bool) throws {
+ public func encode(_ value: Bool) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int) throws {
+ public func encode(_ value: Int) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int8) throws {
+ public func encode(_ value: Int8) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int16) throws {
+ public func encode(_ value: Int16) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int32) throws {
+ public func encode(_ value: Int32) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int64) throws {
+ public func encode(_ value: Int64) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt) throws {
+ public func encode(_ value: UInt) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt8) throws {
+ public func encode(_ value: UInt8) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt16) throws {
+ public func encode(_ value: UInt16) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt32) throws {
+ public func encode(_ value: UInt32) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt64) throws {
+ public func encode(_ value: UInt64) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: String) throws {
+ public func encode(_ value: String) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Float) throws {
+ public func encode(_ value: Float) throws {
assertCanEncodeNewValue()
try self.storage.push(container: box(value))
}
- func encode(_ value: Double) throws {
+ public func encode(_ value: Double) throws {
assertCanEncodeNewValue()
try self.storage.push(container: box(value))
}
- func encode<T : Encodable>(_ value: T) throws {
+ public func encode<T : Encodable>(_ value: T) throws {
assertCanEncodeNewValue()
try self.storage.push(container: box(value))
}
@@ -727,7 +729,7 @@
// MARK: Reference types.
/// The type of container we're referencing.
- enum Reference {
+ private enum Reference {
/// Referencing a specific index in an array container.
case array(NSMutableArray, Int)
@@ -738,15 +740,15 @@
// MARK: - Properties
/// The encoder we're referencing.
- let encoder: _JSONEncoder
+ fileprivate let encoder: _JSONEncoder
/// The container reference itself.
- let reference: Reference
+ private let reference: Reference
// MARK: - Initialization
/// Initializes `self` by referencing the given array container in the given encoder.
- init(referencing encoder: _JSONEncoder, at index: Int, wrapping array: NSMutableArray) {
+ fileprivate init(referencing encoder: _JSONEncoder, at index: Int, wrapping array: NSMutableArray) {
self.encoder = encoder
self.reference = .array(array, index)
super.init(options: encoder.options, codingPath: encoder.codingPath)
@@ -755,7 +757,7 @@
}
/// Initializes `self` by referencing the given dictionary container in the given encoder.
- init(referencing encoder: _JSONEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) {
+ fileprivate init(referencing encoder: _JSONEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) {
self.encoder = encoder
self.reference = .dictionary(dictionary, key.stringValue)
super.init(options: encoder.options, codingPath: encoder.codingPath)
@@ -765,7 +767,7 @@
// MARK: - Coding Path Operations
- override var canEncodeNewValue: Bool {
+ fileprivate override var canEncodeNewValue: Bool {
// With a regular encoder, the storage and coding path grow together.
// A referencing encoder, however, inherits its parents coding path, as well as the key it was created for.
// We have to take this into account.
@@ -905,23 +907,23 @@
// MARK: Properties
/// The decoder's storage.
- var storage: _JSONDecodingStorage
+ fileprivate var storage: _JSONDecodingStorage
/// Options set on the top-level decoder.
- let options: JSONDecoder._Options
+ fileprivate let options: JSONDecoder._Options
/// The path to the current point in encoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
/// Contextual user-provided information for use during encoding.
- var userInfo: [CodingUserInfoKey : Any] {
+ public var userInfo: [CodingUserInfoKey : Any] {
return self.options.userInfo
}
// MARK: - Initialization
/// Initializes `self` with the given top-level container and options.
- init(referencing container: Any, at codingPath: [CodingKey?] = [], options: JSONDecoder._Options) {
+ fileprivate init(referencing container: Any, at codingPath: [CodingKey?] = [], options: JSONDecoder._Options) {
self.storage = _JSONDecodingStorage()
self.storage.push(container: container)
self.codingPath = codingPath
@@ -934,7 +936,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -943,7 +945,7 @@
// MARK: - Decoder Methods
- func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
+ public func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
guard !(self.storage.topContainer is NSNull) else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<Key>.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -958,7 +960,7 @@
return KeyedDecodingContainer(container)
}
- func unkeyedContainer() throws -> UnkeyedDecodingContainer {
+ public func unkeyedContainer() throws -> UnkeyedDecodingContainer {
guard !(self.storage.topContainer is NSNull) else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -972,7 +974,7 @@
return _JSONUnkeyedDecodingContainer(referencing: self, wrapping: topContainer)
}
- func singleValueContainer() throws -> SingleValueDecodingContainer {
+ public func singleValueContainer() throws -> SingleValueDecodingContainer {
return self
}
}
@@ -984,29 +986,29 @@
/// The container stack.
/// Elements may be any one of the JSON types (NSNull, NSNumber, String, Array, [String : Any]).
- private(set) var containers: [Any] = []
+ private(set) fileprivate var containers: [Any] = []
// MARK: - Initialization
/// Initializes `self` with no containers.
- init() {}
+ fileprivate init() {}
// MARK: - Modifying the Stack
- var count: Int {
+ fileprivate var count: Int {
return self.containers.count
}
- var topContainer: Any {
+ fileprivate var topContainer: Any {
precondition(self.containers.count > 0, "Empty container stack.")
return self.containers.last!
}
- mutating func push(container: Any) {
+ fileprivate mutating func push(container: Any) {
self.containers.append(container)
}
- mutating func popContainer() {
+ fileprivate mutating func popContainer() {
precondition(self.containers.count > 0, "Empty container stack.")
self.containers.removeLast()
}
@@ -1020,18 +1022,18 @@
// MARK: Properties
/// A reference to the decoder we're reading from.
- let decoder: _JSONDecoder
+ private let decoder: _JSONDecoder
/// A reference to the container we're reading from.
- let container: [String : Any]
+ private let container: [String : Any]
/// The path of coding keys taken to get to this point in decoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
// MARK: - Initialization
/// Initializes `self` by referencing the given decoder and container.
- init(referencing decoder: _JSONDecoder, wrapping container: [String : Any]) {
+ fileprivate init(referencing decoder: _JSONDecoder, wrapping container: [String : Any]) {
self.decoder = decoder
self.container = container
self.codingPath = decoder.codingPath
@@ -1039,111 +1041,233 @@
// MARK: - KeyedDecodingContainerProtocol Methods
- var allKeys: [Key] {
+ public var allKeys: [Key] {
return self.container.keys.flatMap { Key(stringValue: $0) }
}
- func contains(_ key: Key) -> Bool {
+ public func contains(_ key: Key) -> Bool {
return self.container[key.stringValue] != nil
}
- func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
+ public func decodeNil(forKey key: Key) throws -> Bool {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
+ return entry is NSNull
+ }
+
+ public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Bool.self)
+ guard let value = try self.decoder.unbox(entry, as: Bool.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int.Type, forKey key: Key) throws -> Int? {
+ public func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int.self)
+ guard let value = try self.decoder.unbox(entry, as: Int.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int8.Type, forKey key: Key) throws -> Int8? {
+ public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int8.self)
+ guard let value = try self.decoder.unbox(entry, as: Int8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int16.Type, forKey key: Key) throws -> Int16? {
+ public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int16.self)
+ guard let value = try self.decoder.unbox(entry, as: Int16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int32.Type, forKey key: Key) throws -> Int32? {
+ public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int32.self)
+ guard let value = try self.decoder.unbox(entry, as: Int32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int64.Type, forKey key: Key) throws -> Int64? {
+ public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int64.self)
+ guard let value = try self.decoder.unbox(entry, as: Int64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt.Type, forKey key: Key) throws -> UInt? {
+ public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt8.Type, forKey key: Key) throws -> UInt8? {
+ public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt8.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt16.Type, forKey key: Key) throws -> UInt16? {
+ public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt16.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt32.Type, forKey key: Key) throws -> UInt32? {
+ public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt32.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt64.Type, forKey key: Key) throws -> UInt64? {
+ public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt64.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Float.Type, forKey key: Key) throws -> Float? {
+ public func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Float.self)
+ guard let value = try self.decoder.unbox(entry, as: Float.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Double.Type, forKey key: Key) throws -> Double? {
+ public func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Double.self)
+ guard let value = try self.decoder.unbox(entry, as: Double.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: String.Type, forKey key: Key) throws -> String? {
+ public func decode(_ type: String.Type, forKey key: Key) throws -> String {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: String.self)
+ guard let value = try self.decoder.unbox(entry, as: String.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Data.Type, forKey key: Key) throws -> Data? {
+ public func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Data.self)
+ guard let value = try self.decoder.unbox(entry, as: T.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T? {
- return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: T.self)
- }
- }
-
- func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
+ public func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
return try self.decoder.with(pushedKey: key) {
guard let value = self.container[key.stringValue] else {
throw DecodingError.keyNotFound(key,
@@ -1160,7 +1284,7 @@
}
}
- func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
+ public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
return try self.decoder.with(pushedKey: key) {
guard let value = self.container[key.stringValue] else {
throw DecodingError.keyNotFound(key,
@@ -1176,23 +1300,18 @@
}
}
- func _superDecoder(forKey key: CodingKey) throws -> Decoder {
- return try self.decoder.with(pushedKey: key) {
- guard let value = self.container[key.stringValue] else {
- throw DecodingError.keyNotFound(key,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Cannot get superDecoder() -- no value found for key \"\(key.stringValue)\""))
- }
-
+ private func _superDecoder(forKey key: CodingKey) throws -> Decoder {
+ return self.decoder.with(pushedKey: key) {
+ let value: Any = self.container[key.stringValue] ?? NSNull()
return _JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options)
}
}
- func superDecoder() throws -> Decoder {
+ public func superDecoder() throws -> Decoder {
return try _superDecoder(forKey: _JSONSuperKey.super)
}
- func superDecoder(forKey key: Key) throws -> Decoder {
+ public func superDecoder(forKey key: Key) throws -> Decoder {
return try _superDecoder(forKey: key)
}
}
@@ -1201,21 +1320,21 @@
// MARK: Properties
/// A reference to the decoder we're reading from.
- let decoder: _JSONDecoder
+ private let decoder: _JSONDecoder
/// A reference to the container we're reading from.
- let container: [Any]
+ private let container: [Any]
/// The path of coding keys taken to get to this point in decoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
/// The index of the element we're about to decode.
- var currentIndex: Int
+ private var currentIndex: Int
// MARK: - Initialization
/// Initializes `self` by referencing the given decoder and container.
- init(referencing decoder: _JSONDecoder, wrapping container: [Any]) {
+ fileprivate init(referencing decoder: _JSONDecoder, wrapping container: [Any]) {
self.decoder = decoder
self.container = container
self.codingPath = decoder.codingPath
@@ -1224,175 +1343,253 @@
// MARK: - UnkeyedDecodingContainer Methods
- var count: Int? {
+ public var count: Int? {
return self.container.count
}
- var isAtEnd: Bool {
+ public var isAtEnd: Bool {
return self.currentIndex >= self.count!
}
- mutating func decodeIfPresent(_ type: Bool.Type) throws -> Bool? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decodeNil() throws -> Bool {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
+
+ if self.container[self.currentIndex] is NSNull {
+ self.currentIndex += 1
+ return true
+ } else {
+ return false
+ }
+ }
+
+ public mutating func decode(_ type: Bool.Type) throws -> Bool {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int.Type) throws -> Int? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int.Type) throws -> Int {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int8.Type) throws -> Int8? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int8.Type) throws -> Int8 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int16.Type) throws -> Int16? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int16.Type) throws -> Int16 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int32.Type) throws -> Int32? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int32.Type) throws -> Int32 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int64.Type) throws -> Int64? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int64.Type) throws -> Int64 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt.Type) throws -> UInt? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt.Type) throws -> UInt {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt8.Type) throws -> UInt8? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt8.Type) throws -> UInt8 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt16.Type) throws -> UInt16? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt16.Type) throws -> UInt16 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt32.Type) throws -> UInt32? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt32.Type) throws -> UInt32 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt64.Type) throws -> UInt64? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt64.Type) throws -> UInt64 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Float.Type) throws -> Float? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Float.Type) throws -> Float {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Double.Type) throws -> Double? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Double.Type) throws -> Double {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: String.Type) throws -> String? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: String.Type) throws -> String {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Data.Type) throws -> Data? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode<T : Decodable>(_ type: T.Type) throws -> T {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Data.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: T.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent<T : Decodable>(_ type: T.Type) throws -> T? {
- guard !self.isAtEnd else { return nil }
-
- return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: T.self)
- self.currentIndex += 1
- return decoded
- }
- }
-
- mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
+ public mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
return try self.decoder.with(pushedKey: nil) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<NestedKey>.self,
@@ -1417,7 +1614,7 @@
}
}
- mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
+ public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
return try self.decoder.with(pushedKey: nil) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
@@ -1441,7 +1638,7 @@
}
}
- mutating func superDecoder() throws -> Decoder {
+ public mutating func superDecoder() throws -> Decoder {
return try self.decoder.with(pushedKey: nil) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(Decoder.self,
@@ -1450,12 +1647,6 @@
}
let value = self.container[self.currentIndex]
- guard !(value is NSNull) else {
- throw DecodingError.valueNotFound(Decoder.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Cannot get superDecoder() -- found null value instead."))
- }
-
self.currentIndex += 1
return _JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options)
}
@@ -1465,159 +1656,89 @@
extension _JSONDecoder : SingleValueDecodingContainer {
// MARK: SingleValueDecodingContainer Methods
- func decodeNil() -> Bool {
+ private func expectNonNull<T>(_ type: T.Type) throws {
+ guard !self.decodeNil() else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected \(type) but found null value instead."))
+ }
+ }
+
+ public func decodeNil() -> Bool {
return self.storage.topContainer is NSNull
}
- // These all unwrap the result, since we couldn't have gotten a single value container if the topContainer was null.
- func decode(_ type: Bool.Type) throws -> Bool {
- guard let value = try self.unbox(self.storage.topContainer, as: Bool.self) else {
- throw DecodingError.valueNotFound(Bool.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Bool but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Bool.Type) throws -> Bool {
+ try expectNonNull(Bool.self)
+ return try self.unbox(self.storage.topContainer, as: Bool.self)!
}
- func decode(_ type: Int.Type) throws -> Int {
- guard let value = try self.unbox(self.storage.topContainer, as: Int.self) else {
- throw DecodingError.valueNotFound(Int.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int.Type) throws -> Int {
+ try expectNonNull(Int.self)
+ return try self.unbox(self.storage.topContainer, as: Int.self)!
}
- func decode(_ type: Int8.Type) throws -> Int8 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int8.self) else {
- throw DecodingError.valueNotFound(Int8.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int8 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int8.Type) throws -> Int8 {
+ try expectNonNull(Int8.self)
+ return try self.unbox(self.storage.topContainer, as: Int8.self)!
}
- func decode(_ type: Int16.Type) throws -> Int16 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int16.self) else {
- throw DecodingError.valueNotFound(Int16.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int16 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int16.Type) throws -> Int16 {
+ try expectNonNull(Int16.self)
+ return try self.unbox(self.storage.topContainer, as: Int16.self)!
}
- func decode(_ type: Int32.Type) throws -> Int32 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int32.self) else {
- throw DecodingError.valueNotFound(Int32.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int32 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int32.Type) throws -> Int32 {
+ try expectNonNull(Int32.self)
+ return try self.unbox(self.storage.topContainer, as: Int32.self)!
}
- func decode(_ type: Int64.Type) throws -> Int64 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int64.self) else {
- throw DecodingError.valueNotFound(Int64.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int64 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int64.Type) throws -> Int64 {
+ try expectNonNull(Int64.self)
+ return try self.unbox(self.storage.topContainer, as: Int64.self)!
}
- func decode(_ type: UInt.Type) throws -> UInt {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt.self) else {
- throw DecodingError.valueNotFound(UInt.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt.Type) throws -> UInt {
+ try expectNonNull(UInt.self)
+ return try self.unbox(self.storage.topContainer, as: UInt.self)!
}
- func decode(_ type: UInt8.Type) throws -> UInt8 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt8.self) else {
- throw DecodingError.valueNotFound(UInt8.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt8 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt8.Type) throws -> UInt8 {
+ try expectNonNull(UInt8.self)
+ return try self.unbox(self.storage.topContainer, as: UInt8.self)!
}
- func decode(_ type: UInt16.Type) throws -> UInt16 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt16.self) else {
- throw DecodingError.valueNotFound(UInt16.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt16 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt16.Type) throws -> UInt16 {
+ try expectNonNull(UInt16.self)
+ return try self.unbox(self.storage.topContainer, as: UInt16.self)!
}
- func decode(_ type: UInt32.Type) throws -> UInt32 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt32.self) else {
- throw DecodingError.valueNotFound(UInt32.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt32 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt32.Type) throws -> UInt32 {
+ try expectNonNull(UInt32.self)
+ return try self.unbox(self.storage.topContainer, as: UInt32.self)!
}
- func decode(_ type: UInt64.Type) throws -> UInt64 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt64.self) else {
- throw DecodingError.valueNotFound(UInt64.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt64 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt64.Type) throws -> UInt64 {
+ try expectNonNull(UInt64.self)
+ return try self.unbox(self.storage.topContainer, as: UInt64.self)!
}
- func decode(_ type: Float.Type) throws -> Float {
- guard let value = try self.unbox(self.storage.topContainer, as: Float.self) else {
- throw DecodingError.valueNotFound(Float.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Float but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Float.Type) throws -> Float {
+ try expectNonNull(Float.self)
+ return try self.unbox(self.storage.topContainer, as: Float.self)!
}
- func decode(_ type: Double.Type) throws -> Double {
- guard let value = try self.unbox(self.storage.topContainer, as: Double.self) else {
- throw DecodingError.valueNotFound(Double.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Double but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Double.Type) throws -> Double {
+ try expectNonNull(Double.self)
+ return try self.unbox(self.storage.topContainer, as: Double.self)!
}
- func decode(_ type: String.Type) throws -> String {
- guard let value = try self.unbox(self.storage.topContainer, as: String.self) else {
- throw DecodingError.valueNotFound(String.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected String but found null value instead."))
- }
-
- return value
+ public func decode(_ type: String.Type) throws -> String {
+ try expectNonNull(String.self)
+ return try self.unbox(self.storage.topContainer, as: String.self)!
}
- func decode<T : Decodable>(_ type: T.Type) throws -> T {
- guard let value = try self.unbox(self.storage.topContainer, as: T.self) else {
- throw DecodingError.valueNotFound(T.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected \(T.self) but found null value instead."))
- }
-
- return value
+ public func decode<T : Decodable>(_ type: T.Type) throws -> T {
+ try expectNonNull(T.self)
+ return try self.unbox(self.storage.topContainer, as: T.self)!
}
}
@@ -1625,8 +1746,7 @@
extension _JSONDecoder {
/// Returns the given value unboxed from a container.
- fileprivate func unbox(_ value: Any?, as type: Bool.Type) throws -> Bool? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? {
guard !(value is NSNull) else { return nil }
if let number = value as? NSNumber {
@@ -1647,8 +1767,7 @@
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
- fileprivate func unbox(_ value: Any?, as type: Int.Type) throws -> Int? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1663,8 +1782,7 @@
return int
}
- fileprivate func unbox(_ value: Any?, as type: Int8.Type) throws -> Int8? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1679,8 +1797,7 @@
return int8
}
- fileprivate func unbox(_ value: Any?, as type: Int16.Type) throws -> Int16? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1695,8 +1812,7 @@
return int16
}
- fileprivate func unbox(_ value: Any?, as type: Int32.Type) throws -> Int32? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1711,8 +1827,7 @@
return int32
}
- fileprivate func unbox(_ value: Any?, as type: Int64.Type) throws -> Int64? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1727,8 +1842,7 @@
return int64
}
- fileprivate func unbox(_ value: Any?, as type: UInt.Type) throws -> UInt? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1743,8 +1857,7 @@
return uint
}
- fileprivate func unbox(_ value: Any?, as type: UInt8.Type) throws -> UInt8? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1759,8 +1872,7 @@
return uint8
}
- fileprivate func unbox(_ value: Any?, as type: UInt16.Type) throws -> UInt16? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1775,8 +1887,7 @@
return uint16
}
- fileprivate func unbox(_ value: Any?, as type: UInt32.Type) throws -> UInt32? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1791,8 +1902,7 @@
return uint32
}
- fileprivate func unbox(_ value: Any?, as type: UInt64.Type) throws -> UInt64? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? {
guard !(value is NSNull) else { return nil }
guard let number = value as? NSNumber else {
@@ -1807,8 +1917,7 @@
return uint64
}
- fileprivate func unbox(_ value: Any?, as type: Float.Type) throws -> Float? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? {
guard !(value is NSNull) else { return nil }
if let number = value as? NSNumber {
@@ -1854,8 +1963,7 @@
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
- func unbox(_ value: Any?, as type: Double.Type) throws -> Double? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? {
guard !(value is NSNull) else { return nil }
if let number = value as? NSNumber {
@@ -1890,8 +1998,7 @@
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
- func unbox(_ value: Any?, as type: String.Type) throws -> String? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? {
guard !(value is NSNull) else { return nil }
guard let string = value as? String else {
@@ -1901,8 +2008,7 @@
return string
}
- func unbox(_ value: Any?, as type: Date.Type) throws -> Date? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Date.Type) throws -> Date? {
guard !(value is NSNull) else { return nil }
switch self.options.dateDecodingStrategy {
@@ -1948,8 +2054,7 @@
}
}
- func unbox(_ value: Any?, as type: Data.Type) throws -> Data? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? {
guard !(value is NSNull) else { return nil }
switch self.options.dataDecodingStrategy {
@@ -1978,8 +2083,7 @@
}
}
- func unbox(_ value: Any?, as type: Decimal.Type) throws -> Decimal? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Decimal.Type) throws -> Decimal? {
guard !(value is NSNull) else { return nil }
// Attempt to bridge from NSDecimalNumber.
@@ -1991,15 +2095,14 @@
}
}
- func unbox<T : Decodable>(_ value: Any?, as type: T.Type) throws -> T? {
- guard let value = value else { return nil }
- guard !(value is NSNull) else { return nil }
-
+ fileprivate func unbox<T : Decodable>(_ value: Any, as type: T.Type) throws -> T? {
let decoded: T
if T.self == Date.self {
- decoded = (try self.unbox(value, as: Date.self) as! T)
+ guard let date = try self.unbox(value, as: Date.self) else { return nil }
+ decoded = date as! T
} else if T.self == Data.self {
- decoded = (try self.unbox(value, as: Data.self) as! T)
+ guard let data = try self.unbox(value, as: Data.self) else { return nil }
+ decoded = data as! T
} else if T.self == URL.self {
guard let urlString = try self.unbox(value, as: String.self) else {
return nil
@@ -2012,7 +2115,8 @@
decoded = (url as! T)
} else if T.self == Decimal.self {
- decoded = (try self.unbox(value, as: Decimal.self) as! T)
+ guard let decimal = try self.unbox(value, as: Decimal.self) else { return nil }
+ decoded = decimal as! T
} else {
self.storage.push(container: value)
decoded = try T(from: self)
diff --git a/stdlib/public/SDK/Foundation/PlistEncoder.swift b/stdlib/public/SDK/Foundation/PlistEncoder.swift
index f5514ff..404ca71 100644
--- a/stdlib/public/SDK/Foundation/PlistEncoder.swift
+++ b/stdlib/public/SDK/Foundation/PlistEncoder.swift
@@ -88,23 +88,23 @@
// MARK: Properties
/// The encoder's storage.
- var storage: _PlistEncodingStorage
+ fileprivate var storage: _PlistEncodingStorage
/// Options set on the top-level encoder.
- let options: PropertyListEncoder._Options
+ fileprivate let options: PropertyListEncoder._Options
/// The path to the current point in encoding.
- var codingPath: [CodingKey?]
+ fileprivate(set) public var codingPath: [CodingKey?]
/// Contextual user-provided information for use during encoding.
- var userInfo: [CodingUserInfoKey : Any] {
+ public var userInfo: [CodingUserInfoKey : Any] {
return self.options.userInfo
}
// MARK: - Initialization
/// Initializes `self` with the given top-level encoder options.
- init(options: PropertyListEncoder._Options, codingPath: [CodingKey?] = []) {
+ fileprivate init(options: PropertyListEncoder._Options, codingPath: [CodingKey?] = []) {
self.options = options
self.storage = _PlistEncodingStorage()
self.codingPath = codingPath
@@ -116,7 +116,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -126,7 +126,7 @@
/// Returns whether a new element can be encoded at this coding path.
///
/// `true` if an element has not yet been encoded at this coding path; `false` otherwise.
- var canEncodeNewValue: Bool {
+ fileprivate var canEncodeNewValue: Bool {
// Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container).
// At the same time, every time a container is requested, a new value gets pushed onto the storage stack.
// If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition.
@@ -137,7 +137,7 @@
}
// MARK: - Encoder Methods
- func container<Key>(keyedBy: Key.Type) -> KeyedEncodingContainer<Key> {
+ public func container<Key>(keyedBy: Key.Type) -> KeyedEncodingContainer<Key> {
// If an existing keyed container was already requested, return that one.
let topContainer: NSMutableDictionary
if self.canEncodeNewValue {
@@ -155,7 +155,7 @@
return KeyedEncodingContainer(container)
}
- func unkeyedContainer() -> UnkeyedEncodingContainer {
+ public func unkeyedContainer() -> UnkeyedEncodingContainer {
// If an existing unkeyed container was already requested, return that one.
let topContainer: NSMutableArray
if self.canEncodeNewValue {
@@ -172,7 +172,7 @@
return _PlistUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer)
}
- func singleValueContainer() -> SingleValueEncodingContainer {
+ public func singleValueContainer() -> SingleValueEncodingContainer {
return self
}
}
@@ -184,36 +184,36 @@
/// The container stack.
/// Elements may be any one of the plist types (NSNumber, NSString, NSDate, NSArray, NSDictionary).
- private(set) var containers: [NSObject] = []
+ private(set) fileprivate var containers: [NSObject] = []
// MARK: - Initialization
/// Initializes `self` with no containers.
- init() {}
+ fileprivate init() {}
// MARK: - Modifying the Stack
- var count: Int {
+ fileprivate var count: Int {
return self.containers.count
}
- mutating func pushKeyedContainer() -> NSMutableDictionary {
+ fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary {
let dictionary = NSMutableDictionary()
self.containers.append(dictionary)
return dictionary
}
- mutating func pushUnkeyedContainer() -> NSMutableArray {
+ fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray {
let array = NSMutableArray()
self.containers.append(array)
return array
}
- mutating func push(container: NSObject) {
+ fileprivate mutating func push(container: NSObject) {
self.containers.append(container)
}
- mutating func popContainer() -> NSObject {
+ fileprivate mutating func popContainer() -> NSObject {
precondition(self.containers.count > 0, "Empty container stack.")
return self.containers.popLast()!
}
@@ -227,18 +227,18 @@
// MARK: Properties
/// A reference to the encoder we're writing to.
- let encoder: _PlistEncoder
+ private let encoder: _PlistEncoder
/// A reference to the container we're writing to.
- let container: NSMutableDictionary
+ private let container: NSMutableDictionary
/// The path of coding keys taken to get to this point in encoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
// MARK: - Initialization
/// Initializes `self` with the given references.
- init(referencing encoder: _PlistEncoder, codingPath: [CodingKey?], wrapping container: NSMutableDictionary) {
+ fileprivate init(referencing encoder: _PlistEncoder, codingPath: [CodingKey?], wrapping container: NSMutableDictionary) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -250,7 +250,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -259,28 +259,29 @@
// MARK: - KeyedEncodingContainerProtocol Methods
- mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: String, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Float, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode(_ value: Double, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encodeNil(forKey key: Key) throws { self.container[key.stringValue] = _plistNullNSString }
+ public mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: String, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Float, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
+ public mutating func encode(_ value: Double, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) }
- mutating func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
+ public mutating func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
try self.encoder.with(pushedKey: key) {
self.container[key.stringValue] = try self.encoder.box(value)
}
}
- mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
+ public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
let dictionary = NSMutableDictionary()
self.container[key.stringValue] = dictionary
@@ -290,7 +291,7 @@
}
}
- mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
+ public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
let array = NSMutableArray()
self.container[key.stringValue] = array
@@ -299,11 +300,11 @@
}
}
- mutating func superEncoder() -> Encoder {
+ public mutating func superEncoder() -> Encoder {
return _PlistReferencingEncoder(referencing: self.encoder, at: _PlistSuperKey.super, wrapping: self.container)
}
- mutating func superEncoder(forKey key: Key) -> Encoder {
+ public mutating func superEncoder(forKey key: Key) -> Encoder {
return _PlistReferencingEncoder(referencing: self.encoder, at: key, wrapping: self.container)
}
}
@@ -312,18 +313,18 @@
// MARK: Properties
/// A reference to the encoder we're writing to.
- let encoder: _PlistEncoder
+ private let encoder: _PlistEncoder
/// A reference to the container we're writing to.
- let container: NSMutableArray
+ private let container: NSMutableArray
/// The path of coding keys taken to get to this point in encoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
// MARK: - Initialization
/// Initializes `self` with the given references.
- init(referencing encoder: _PlistEncoder, codingPath: [CodingKey?], wrapping container: NSMutableArray) {
+ fileprivate init(referencing encoder: _PlistEncoder, codingPath: [CodingKey?], wrapping container: NSMutableArray) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -335,7 +336,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -344,28 +345,29 @@
// MARK: - UnkeyedEncodingContainer Methods
- mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Float) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: Double) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encodeNil() throws { self.container.add(_plistNullNSString) }
+ public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Float) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: Double) throws { self.container.add(self.encoder.box(value)) }
+ public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) }
- mutating func encode<T : Encodable>(_ value: T) throws {
+ public mutating func encode<T : Encodable>(_ value: T) throws {
try self.encoder.with(pushedKey: nil) {
self.container.add(try self.encoder.box(value))
}
}
- mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
+ public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
let dictionary = NSMutableDictionary()
self.container.add(dictionary)
@@ -375,7 +377,7 @@
}
}
- mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
+ public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
let array = NSMutableArray()
self.container.add(array)
@@ -384,7 +386,7 @@
}
}
- mutating func superEncoder() -> Encoder {
+ public mutating func superEncoder() -> Encoder {
return _PlistReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container)
}
}
@@ -392,86 +394,86 @@
extension _PlistEncoder : SingleValueEncodingContainer {
// MARK: - SingleValueEncodingContainer Methods
- func assertCanEncodeNewValue() {
+ private func assertCanEncodeNewValue() {
precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.")
}
- func encodeNil() throws {
+ public func encodeNil() throws {
assertCanEncodeNewValue()
self.storage.push(container: _plistNullNSString)
}
- func encode(_ value: Bool) throws {
+ public func encode(_ value: Bool) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int) throws {
+ public func encode(_ value: Int) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int8) throws {
+ public func encode(_ value: Int8) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int16) throws {
+ public func encode(_ value: Int16) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int32) throws {
+ public func encode(_ value: Int32) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Int64) throws {
+ public func encode(_ value: Int64) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt) throws {
+ public func encode(_ value: UInt) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt8) throws {
+ public func encode(_ value: UInt8) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt16) throws {
+ public func encode(_ value: UInt16) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt32) throws {
+ public func encode(_ value: UInt32) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: UInt64) throws {
+ public func encode(_ value: UInt64) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: String) throws {
+ public func encode(_ value: String) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Float) throws {
+ public func encode(_ value: Float) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode(_ value: Double) throws {
+ public func encode(_ value: Double) throws {
assertCanEncodeNewValue()
self.storage.push(container: box(value))
}
- func encode<T : Encodable>(_ value: T) throws {
+ public func encode<T : Encodable>(_ value: T) throws {
assertCanEncodeNewValue()
try self.storage.push(container: box(value))
}
@@ -529,7 +531,7 @@
// MARK: Reference types.
/// The type of container we're referencing.
- enum Reference {
+ private enum Reference {
/// Referencing a specific index in an array container.
case array(NSMutableArray, Int)
@@ -540,15 +542,15 @@
// MARK: - Properties
/// The encoder we're referencing.
- let encoder: _PlistEncoder
+ private let encoder: _PlistEncoder
/// The container reference itself.
- let reference: Reference
+ private let reference: Reference
// MARK: - Initialization
/// Initializes `self` by referencing the given array container in the given encoder.
- init(referencing encoder: _PlistEncoder, at index: Int, wrapping array: NSMutableArray) {
+ fileprivate init(referencing encoder: _PlistEncoder, at index: Int, wrapping array: NSMutableArray) {
self.encoder = encoder
self.reference = .array(array, index)
super.init(options: encoder.options, codingPath: encoder.codingPath)
@@ -557,7 +559,7 @@
}
/// Initializes `self` by referencing the given dictionary container in the given encoder.
- init(referencing encoder: _PlistEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) {
+ fileprivate init(referencing encoder: _PlistEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) {
self.encoder = encoder
self.reference = .dictionary(dictionary, key.stringValue)
super.init(options: encoder.options, codingPath: encoder.codingPath)
@@ -567,7 +569,7 @@
// MARK: - Coding Path Operations
- override var canEncodeNewValue: Bool {
+ fileprivate override var canEncodeNewValue: Bool {
// With a regular encoder, the storage and coding path grow together.
// A referencing encoder, however, inherits its parents coding path, as well as the key it was created for.
// We have to take this into account.
@@ -661,23 +663,23 @@
// MARK: Properties
/// The decoder's storage.
- var storage: _PlistDecodingStorage
+ fileprivate var storage: _PlistDecodingStorage
/// Options set on the top-level decoder.
- let options: PropertyListDecoder._Options
+ fileprivate let options: PropertyListDecoder._Options
/// The path to the current point in encoding.
- var codingPath: [CodingKey?]
+ fileprivate(set) public var codingPath: [CodingKey?]
/// Contextual user-provided information for use during encoding.
- var userInfo: [CodingUserInfoKey : Any] {
+ public var userInfo: [CodingUserInfoKey : Any] {
return self.options.userInfo
}
// MARK: - Initialization
/// Initializes `self` with the given top-level container and options.
- init(referencing container: Any, at codingPath: [CodingKey?] = [], options: PropertyListDecoder._Options) {
+ fileprivate init(referencing container: Any, at codingPath: [CodingKey?] = [], options: PropertyListDecoder._Options) {
self.storage = _PlistDecodingStorage()
self.storage.push(container: container)
self.codingPath = codingPath
@@ -690,7 +692,7 @@
///
/// - parameter key: The key to push. May be nil for unkeyed containers.
/// - parameter work: The work to perform with the key in the path.
- func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -699,7 +701,7 @@
// MARK: - Decoder Methods
- func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
+ public func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
guard !(self.storage.topContainer is NSNull) else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<Key>.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -714,7 +716,7 @@
return KeyedDecodingContainer(container)
}
- func unkeyedContainer() throws -> UnkeyedDecodingContainer {
+ public func unkeyedContainer() throws -> UnkeyedDecodingContainer {
guard !(self.storage.topContainer is NSNull) else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -728,7 +730,7 @@
return _PlistUnkeyedDecodingContainer(referencing: self, wrapping: topContainer)
}
- func singleValueContainer() throws -> SingleValueDecodingContainer {
+ public func singleValueContainer() throws -> SingleValueDecodingContainer {
return self
}
}
@@ -740,29 +742,29 @@
/// The container stack.
/// Elements may be any one of the plist types (NSNumber, Date, String, Array, [String : Any]).
- private(set) var containers: [Any] = []
+ private(set) fileprivate var containers: [Any] = []
// MARK: - Initialization
/// Initializes `self` with no containers.
- init() {}
+ fileprivate init() {}
// MARK: - Modifying the Stack
- var count: Int {
+ fileprivate var count: Int {
return self.containers.count
}
- var topContainer: Any {
+ fileprivate var topContainer: Any {
precondition(self.containers.count > 0, "Empty container stack.")
return self.containers.last!
}
- mutating func push(container: Any) {
+ fileprivate mutating func push(container: Any) {
self.containers.append(container)
}
- mutating func popContainer() {
+ fileprivate mutating func popContainer() {
precondition(self.containers.count > 0, "Empty container stack.")
self.containers.removeLast()
}
@@ -776,18 +778,18 @@
// MARK: Properties
/// A reference to the decoder we're reading from.
- let decoder: _PlistDecoder
+ private let decoder: _PlistDecoder
/// A reference to the container we're reading from.
- let container: [String : Any]
+ private let container: [String : Any]
/// The path of coding keys taken to get to this point in decoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
// MARK: - Initialization
/// Initializes `self` by referencing the given decoder and container.
- init(referencing decoder: _PlistDecoder, wrapping container: [String : Any]) {
+ fileprivate init(referencing decoder: _PlistDecoder, wrapping container: [String : Any]) {
self.decoder = decoder
self.container = container
self.codingPath = decoder.codingPath
@@ -795,111 +797,237 @@
// MARK: - KeyedDecodingContainerProtocol Methods
- var allKeys: [Key] {
+ public var allKeys: [Key] {
return self.container.keys.flatMap { Key(stringValue: $0) }
}
- func contains(_ key: Key) -> Bool {
+ public func contains(_ key: Key) -> Bool {
return self.container[key.stringValue] != nil
}
- func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
+ public func decodeNil(forKey key: Key) throws -> Bool {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
+ guard let value = entry as? String else {
+ return false
+ }
+
+ return value == _plistNull
+ }
+
+ public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Bool.self)
+ guard let value = try self.decoder.unbox(entry, as: Bool.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int.Type, forKey key: Key) throws -> Int? {
+ public func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int.self)
+ guard let value = try self.decoder.unbox(entry, as: Int.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int8.Type, forKey key: Key) throws -> Int8? {
+ public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int8.self)
+ guard let value = try self.decoder.unbox(entry, as: Int8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int16.Type, forKey key: Key) throws -> Int16? {
+ public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int16.self)
+ guard let value = try self.decoder.unbox(entry, as: Int16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int32.Type, forKey key: Key) throws -> Int32? {
+ public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int32.self)
+ guard let value = try self.decoder.unbox(entry, as: Int32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Int64.Type, forKey key: Key) throws -> Int64? {
+ public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Int64.self)
+ guard let value = try self.decoder.unbox(entry, as: Int64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt.Type, forKey key: Key) throws -> UInt? {
+ public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt8.Type, forKey key: Key) throws -> UInt8? {
+ public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt8.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt16.Type, forKey key: Key) throws -> UInt16? {
+ public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt16.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt32.Type, forKey key: Key) throws -> UInt32? {
+ public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt32.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: UInt64.Type, forKey key: Key) throws -> UInt64? {
+ public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: UInt64.self)
+ guard let value = try self.decoder.unbox(entry, as: UInt64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Float.Type, forKey key: Key) throws -> Float? {
+ public func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Float.self)
+ guard let value = try self.decoder.unbox(entry, as: Float.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Double.Type, forKey key: Key) throws -> Double? {
+ public func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Double.self)
+ guard let value = try self.decoder.unbox(entry, as: Double.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: String.Type, forKey key: Key) throws -> String? {
+ public func decode(_ type: String.Type, forKey key: Key) throws -> String {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: String.self)
+ guard let value = try self.decoder.unbox(entry, as: String.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent(_ type: Data.Type, forKey key: Key) throws -> Data? {
+ public func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
+ guard let entry = self.container[key.stringValue] else {
+ throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
+ }
+
return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: Data.self)
+ guard let value = try self.decoder.unbox(entry, as: T.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
+ }
+
+ return value
}
}
- func decodeIfPresent<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T? {
- return try self.decoder.with(pushedKey: key) {
- return try self.decoder.unbox(self.container[key.stringValue], as: T.self)
- }
- }
-
- func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
+ public func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
return try self.decoder.with(pushedKey: key) {
guard let value = self.container[key.stringValue] else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<NestedKey>.self,
@@ -916,7 +1044,7 @@
}
}
- func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
+ public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
return try self.decoder.with(pushedKey: key) {
guard let value = self.container[key.stringValue] else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
@@ -932,23 +1060,18 @@
}
}
- func _superDecoder(forKey key: CodingKey) throws -> Decoder {
- return try self.decoder.with(pushedKey: key) {
- guard let value = self.container[key.stringValue] else {
- throw DecodingError.valueNotFound(Decoder.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Cannot get superDecoder() -- no value found for key \"\(key.stringValue)\""))
- }
-
+ private func _superDecoder(forKey key: CodingKey) throws -> Decoder {
+ return self.decoder.with(pushedKey: key) {
+ let value: Any = self.container[key.stringValue] ?? NSNull()
return _PlistDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options)
}
}
- func superDecoder() throws -> Decoder {
+ public func superDecoder() throws -> Decoder {
return try _superDecoder(forKey: _PlistSuperKey.super)
}
- func superDecoder(forKey key: Key) throws -> Decoder {
+ public func superDecoder(forKey key: Key) throws -> Decoder {
return try _superDecoder(forKey: key)
}
}
@@ -957,21 +1080,21 @@
// MARK: Properties
/// A reference to the decoder we're reading from.
- let decoder: _PlistDecoder
+ private let decoder: _PlistDecoder
/// A reference to the container we're reading from.
- let container: [Any]
+ private let container: [Any]
/// The path of coding keys taken to get to this point in decoding.
- var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey?]
/// The index of the element we're about to decode.
- var currentIndex: Int
+ private var currentIndex: Int
// MARK: - Initialization
/// Initializes `self` by referencing the given decoder and container.
- init(referencing decoder: _PlistDecoder, wrapping container: [Any]) {
+ fileprivate init(referencing decoder: _PlistDecoder, wrapping container: [Any]) {
self.decoder = decoder
self.container = container
self.codingPath = decoder.codingPath
@@ -980,175 +1103,253 @@
// MARK: - UnkeyedDecodingContainer Methods
- var count: Int? {
+ public var count: Int? {
return self.container.count
}
- var isAtEnd: Bool {
+ public var isAtEnd: Bool {
return self.currentIndex >= self.count!
}
- mutating func decodeIfPresent(_ type: Bool.Type) throws -> Bool? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decodeNil() throws -> Bool {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
+
+ if self.container[self.currentIndex] is NSNull {
+ self.currentIndex += 1
+ return true
+ } else {
+ return false
+ }
+ }
+
+ public mutating func decode(_ type: Bool.Type) throws -> Bool {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int.Type) throws -> Int? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int.Type) throws -> Int {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int8.Type) throws -> Int8? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int8.Type) throws -> Int8 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int16.Type) throws -> Int16? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int16.Type) throws -> Int16 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int32.Type) throws -> Int32? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int32.Type) throws -> Int32 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Int64.Type) throws -> Int64? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Int64.Type) throws -> Int64 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt.Type) throws -> UInt? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt.Type) throws -> UInt {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt8.Type) throws -> UInt8? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt8.Type) throws -> UInt8 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt16.Type) throws -> UInt16? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt16.Type) throws -> UInt16 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt32.Type) throws -> UInt32? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt32.Type) throws -> UInt32 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: UInt64.Type) throws -> UInt64? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: UInt64.Type) throws -> UInt64 {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Float.Type) throws -> Float? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Float.Type) throws -> Float {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Double.Type) throws -> Double? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: Double.Type) throws -> Double {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: String.Type) throws -> String? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode(_ type: String.Type) throws -> String {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent(_ type: Data.Type) throws -> Data? {
- guard !self.isAtEnd else { return nil }
+ public mutating func decode<T : Decodable>(_ type: T.Type) throws -> T {
+ guard !self.isAtEnd else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ }
return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Data.self)
+ guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: T.self) else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Expected \(type) but found null instead."))
+ }
+
self.currentIndex += 1
return decoded
}
}
- mutating func decodeIfPresent<T : Decodable>(_ type: T.Type) throws -> T? {
- guard !self.isAtEnd else { return nil }
-
- return try self.decoder.with(pushedKey: nil) {
- let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: T.self)
- self.currentIndex += 1
- return decoded
- }
- }
-
- mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
+ public mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
return try self.decoder.with(pushedKey: nil) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<NestedKey>.self,
@@ -1173,7 +1374,7 @@
}
}
- mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
+ public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
return try self.decoder.with(pushedKey: nil) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
@@ -1197,7 +1398,7 @@
}
}
- mutating func superDecoder() throws -> Decoder {
+ public mutating func superDecoder() throws -> Decoder {
return try self.decoder.with(pushedKey: nil) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(Decoder.self, DecodingError.Context(codingPath: self.codingPath,
@@ -1205,12 +1406,6 @@
}
let value = self.container[self.currentIndex]
- guard !(value is NSNull) else {
- throw DecodingError.valueNotFound(Decoder.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Cannot get superDecoder() -- found null value instead."))
- }
-
self.currentIndex += 1
return _PlistDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options)
}
@@ -1220,7 +1415,13 @@
extension _PlistDecoder : SingleValueDecodingContainer {
// MARK: SingleValueDecodingContainer Methods
- func decodeNil() -> Bool {
+ private func expectNonNull<T>(_ type: T.Type) throws {
+ guard !self.decodeNil() else {
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected \(type) but found null value instead."))
+ }
+ }
+
+ public func decodeNil() -> Bool {
guard let string = self.storage.topContainer as? String else {
return false
}
@@ -1228,155 +1429,79 @@
return string == _plistNull
}
- // These all unwrap the result, since we couldn't have gotten a single value container if the topContainer was null.
- func decode(_ type: Bool.Type) throws -> Bool {
- guard let value = try self.unbox(self.storage.topContainer, as: Bool.self) else {
- throw DecodingError.valueNotFound(Bool.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Bool but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Bool.Type) throws -> Bool {
+ try expectNonNull(Bool.self)
+ return try self.unbox(self.storage.topContainer, as: Bool.self)!
}
- func decode(_ type: Int.Type) throws -> Int {
- guard let value = try self.unbox(self.storage.topContainer, as: Int.self) else {
- throw DecodingError.valueNotFound(Int.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int.Type) throws -> Int {
+ try expectNonNull(Int.self)
+ return try self.unbox(self.storage.topContainer, as: Int.self)!
}
- func decode(_ type: Int8.Type) throws -> Int8 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int8.self) else {
- throw DecodingError.valueNotFound(Int8.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int8 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int8.Type) throws -> Int8 {
+ try expectNonNull(Int8.self)
+ return try self.unbox(self.storage.topContainer, as: Int8.self)!
}
- func decode(_ type: Int16.Type) throws -> Int16 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int16.self) else {
- throw DecodingError.valueNotFound(Int16.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int16 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int16.Type) throws -> Int16 {
+ try expectNonNull(Int16.self)
+ return try self.unbox(self.storage.topContainer, as: Int16.self)!
}
- func decode(_ type: Int32.Type) throws -> Int32 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int32.self) else {
- throw DecodingError.valueNotFound(Int32.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int32 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int32.Type) throws -> Int32 {
+ try expectNonNull(Int32.self)
+ return try self.unbox(self.storage.topContainer, as: Int32.self)!
}
- func decode(_ type: Int64.Type) throws -> Int64 {
- guard let value = try self.unbox(self.storage.topContainer, as: Int64.self) else {
- throw DecodingError.valueNotFound(Int64.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Int64 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Int64.Type) throws -> Int64 {
+ try expectNonNull(Int64.self)
+ return try self.unbox(self.storage.topContainer, as: Int64.self)!
}
- func decode(_ type: UInt.Type) throws -> UInt {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt.self) else {
- throw DecodingError.valueNotFound(UInt.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt.Type) throws -> UInt {
+ try expectNonNull(UInt.self)
+ return try self.unbox(self.storage.topContainer, as: UInt.self)!
}
- func decode(_ type: UInt8.Type) throws -> UInt8 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt8.self) else {
- throw DecodingError.valueNotFound(UInt8.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt8 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt8.Type) throws -> UInt8 {
+ try expectNonNull(UInt8.self)
+ return try self.unbox(self.storage.topContainer, as: UInt8.self)!
}
- func decode(_ type: UInt16.Type) throws -> UInt16 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt16.self) else {
- throw DecodingError.valueNotFound(UInt16.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt16 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt16.Type) throws -> UInt16 {
+ try expectNonNull(UInt16.self)
+ return try self.unbox(self.storage.topContainer, as: UInt16.self)!
}
- func decode(_ type: UInt32.Type) throws -> UInt32 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt32.self) else {
- throw DecodingError.valueNotFound(UInt32.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt32 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt32.Type) throws -> UInt32 {
+ try expectNonNull(UInt32.self)
+ return try self.unbox(self.storage.topContainer, as: UInt32.self)!
}
- func decode(_ type: UInt64.Type) throws -> UInt64 {
- guard let value = try self.unbox(self.storage.topContainer, as: UInt64.self) else {
- throw DecodingError.valueNotFound(UInt64.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected UInt64 but found null value instead."))
- }
-
- return value
+ public func decode(_ type: UInt64.Type) throws -> UInt64 {
+ try expectNonNull(UInt64.self)
+ return try self.unbox(self.storage.topContainer, as: UInt64.self)!
}
- func decode(_ type: Float.Type) throws -> Float {
- guard let value = try self.unbox(self.storage.topContainer, as: Float.self) else {
- throw DecodingError.valueNotFound(Float.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Float but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Float.Type) throws -> Float {
+ try expectNonNull(Float.self)
+ return try self.unbox(self.storage.topContainer, as: Float.self)!
}
- func decode(_ type: Double.Type) throws -> Double {
- guard let value = try self.unbox(self.storage.topContainer, as: Double.self) else {
- throw DecodingError.valueNotFound(Double.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected Double but found null value instead."))
- }
-
- return value
+ public func decode(_ type: Double.Type) throws -> Double {
+ try expectNonNull(Double.self)
+ return try self.unbox(self.storage.topContainer, as: Double.self)!
}
- func decode(_ type: String.Type) throws -> String {
- guard let value = try self.unbox(self.storage.topContainer, as: String.self) else {
- throw DecodingError.valueNotFound(String.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected String but found null value instead."))
- }
-
- return value
+ public func decode(_ type: String.Type) throws -> String {
+ try expectNonNull(String.self)
+ return try self.unbox(self.storage.topContainer, as: String.self)!
}
- func decode<T : Decodable>(_ type: T.Type) throws -> T {
- guard let value = try self.unbox(self.storage.topContainer, as: T.self) else {
- throw DecodingError.valueNotFound(T.self,
- DecodingError.Context(codingPath: self.codingPath,
- debugDescription: "Expected \(T.self) but found null value instead."))
- }
-
- return value
+ public func decode<T : Decodable>(_ type: T.Type) throws -> T {
+ try expectNonNull(T.self)
+ return try self.unbox(self.storage.topContainer, as: T.self)!
}
}
@@ -1384,8 +1509,7 @@
extension _PlistDecoder {
/// Returns the given value unboxed from a container.
- fileprivate func unbox(_ value: Any?, as type: Bool.Type) throws -> Bool? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? {
if let string = value as? String, string == _plistNull { return nil }
if let number = value as? NSNumber {
@@ -1406,8 +1530,7 @@
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
- fileprivate func unbox(_ value: Any?, as type: Int.Type) throws -> Int? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1422,8 +1545,7 @@
return int
}
- fileprivate func unbox(_ value: Any?, as type: Int8.Type) throws -> Int8? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1438,8 +1560,7 @@
return int8
}
- fileprivate func unbox(_ value: Any?, as type: Int16.Type) throws -> Int16? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1454,8 +1575,7 @@
return int16
}
- fileprivate func unbox(_ value: Any?, as type: Int32.Type) throws -> Int32? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1470,8 +1590,7 @@
return int32
}
- fileprivate func unbox(_ value: Any?, as type: Int64.Type) throws -> Int64? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1486,8 +1605,7 @@
return int64
}
- fileprivate func unbox(_ value: Any?, as type: UInt.Type) throws -> UInt? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1502,8 +1620,7 @@
return uint
}
- fileprivate func unbox(_ value: Any?, as type: UInt8.Type) throws -> UInt8? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1518,8 +1635,7 @@
return uint8
}
- fileprivate func unbox(_ value: Any?, as type: UInt16.Type) throws -> UInt16? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1534,8 +1650,7 @@
return uint16
}
- fileprivate func unbox(_ value: Any?, as type: UInt32.Type) throws -> UInt32? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1550,8 +1665,7 @@
return uint32
}
- fileprivate func unbox(_ value: Any?, as type: UInt64.Type) throws -> UInt64? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1566,8 +1680,7 @@
return uint64
}
- fileprivate func unbox(_ value: Any?, as type: Float.Type) throws -> Float? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1582,8 +1695,7 @@
return float
}
- func unbox(_ value: Any?, as type: Double.Type) throws -> Double? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? {
if let string = value as? String, string == _plistNull { return nil }
guard let number = value as? NSNumber else {
@@ -1598,9 +1710,7 @@
return double
}
- func unbox(_ value: Any?, as type: String.Type) throws -> String? {
- guard let value = value else { return nil }
-
+ fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? {
guard let string = value as? String else {
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
@@ -1608,8 +1718,7 @@
return string == _plistNull ? nil : string
}
- func unbox(_ value: Any?, as type: Date.Type) throws -> Date? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Date.Type) throws -> Date? {
if let string = value as? String, string == _plistNull { return nil }
guard let date = value as? Date else {
@@ -1619,8 +1728,7 @@
return date
}
- func unbox(_ value: Any?, as type: Data.Type) throws -> Data? {
- guard let value = value else { return nil }
+ fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? {
if let string = value as? String, string == _plistNull { return nil }
guard let data = value as? Data else {
@@ -1630,15 +1738,14 @@
return data
}
- func unbox<T : Decodable>(_ value: Any?, as type: T.Type) throws -> T? {
- guard let value = value else { return nil }
- if let string = value as? String, string == _plistNull { return nil }
-
+ fileprivate func unbox<T : Decodable>(_ value: Any, as type: T.Type) throws -> T? {
let decoded: T
if T.self == Date.self {
- decoded = (try self.unbox(value, as: Date.self) as! T)
+ guard let date = try self.unbox(value, as: Date.self) else { return nil }
+ decoded = date as! T
} else if T.self == Data.self {
- decoded = (try self.unbox(value, as: Data.self) as! T)
+ guard let data = try self.unbox(value, as: Data.self) else { return nil }
+ decoded = data as! T
} else {
self.storage.push(container: value)
decoded = try T(from: self)
diff --git a/stdlib/public/core/Codable.swift b/stdlib/public/core/Codable.swift
index 8f5b5a0..1cd4209 100644
--- a/stdlib/public/core/Codable.swift
+++ b/stdlib/public/core/Codable.swift
@@ -149,6 +149,12 @@
/// A `nil` value indicates an unkeyed container.
var codingPath: [CodingKey?] { get }
+ /// Encodes a null value for the given key.
+ ///
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if a null value is invalid in the current context for this format.
+ mutating func encodeNil(forKey key: Key) throws
+
/// Encodes the given value for the given key.
///
/// - parameter value: The value to encode.
@@ -421,6 +427,14 @@
return _box.codingPath
}
+ /// Encodes a null value for the given key.
+ ///
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if a null value is invalid in the current context for this format.
+ public mutating func encodeNil(forKey key: Key) throws {
+ try _box.encodeNil(forKey: key)
+ }
+
/// Encodes the given value for the given key.
///
/// - parameter value: The value to encode.
@@ -567,6 +581,141 @@
try _box.encodeWeak(object, forKey: key)
}
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Bool?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Int?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Int8?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Int16?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Int32?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Int64?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: UInt?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Float?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: Double?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent(_ value: String?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
+ /// Encodes the given value for the given key if it is not `nil`.
+ ///
+ /// - parameter value: The value to encode.
+ /// - parameter key: The key to associate the value with.
+ /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format.
+ public mutating func encodeIfPresent<T : Encodable>(_ value: T?, forKey key: Key) throws {
+ try _box.encodeIfPresent(value, forKey: key)
+ }
+
/// Stores a keyed encoding container for the given key and returns it.
///
/// - parameter keyType: The key type to use for the container.
@@ -627,6 +776,13 @@
/// - returns: Whether the `Decoder` has an entry for the given key.
func contains(_ key: Key) -> Bool
+ /// Decodes a null value for the given key.
+ ///
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: Whether the encountered value was null.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ func decodeNil(forKey key: Key) throws -> Bool
+
/// Decodes a value of the given type for the given key.
///
/// - parameter type: The type of value to decode.
@@ -1001,6 +1157,195 @@
return _box.contains(key)
}
+ /// Decodes a null value for the given key.
+ ///
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: Whether the encountered value was null.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ public func decodeNil(forKey key: Key) throws -> Bool {
+ return try _box.decodeNil(forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
+ return try _box.decode(Bool.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
+ return try _box.decode(Int.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
+ return try _box.decode(Int8.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
+ return try _box.decode(Int16.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
+ return try _box.decode(Int32.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
+ return try _box.decode(Int64.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
+ return try _box.decode(UInt.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
+ return try _box.decode(UInt8.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
+ return try _box.decode(UInt16.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
+ return try _box.decode(UInt32.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
+ return try _box.decode(UInt64.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
+ return try _box.decode(Float.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
+ return try _box.decode(Double.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode(_ type: String.Type, forKey key: Key) throws -> String {
+ return try _box.decode(String.self, forKey: key)
+ }
+
+ /// Decodes a value of the given type for the given key.
+ ///
+ /// - parameter type: The type of value to decode.
+ /// - parameter key: The key that the decoded value is associated with.
+ /// - returns: A value of the requested type, if present for the given key and convertible to the requested type.
+ /// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
+ /// - throws: `DecodingError.keyNotFound` if `self` does not have an entry for the given key.
+ /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for the given key.
+ public func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
+ return try _box.decode(T.self, forKey: key)
+ }
+
/// Decodes a value of the given type for the given key, if present.
///
/// This method returns `nil` if the container does not have a value associated with `key`, or if the value is null. The difference between these states can be distinguished with a `contains(_:)` call.
@@ -1235,6 +1580,11 @@
/// A `nil` value indicates an unkeyed container.
var codingPath: [CodingKey?] { get }
+ /// Encodes a null value.
+ ///
+ /// - throws: `EncodingError.invalidValue` if a null value is invalid in the current context for this format.
+ mutating func encodeNil() throws
+
/// Encodes the given value.
///
/// - parameter value: The value to encode.
@@ -1458,6 +1808,12 @@
/// Returns whether there are no more elements left to be decoded in the container.
var isAtEnd: Bool { get }
+ /// Decodes a null value.
+ ///
+ /// - returns: Whether the encountered value was null.
+ /// - throws: `DecodingError.valueNotFound` if there are no more values to decode.
+ mutating func decodeNil() throws -> Bool
+
/// Decodes a value of the given type.
///
/// - parameter type: The type of value to decode.
@@ -2240,6 +2596,12 @@
@_inlineable
@_versioned
+ internal func encodeNil(forKey key: Key) throws {
+ fatalError("_KeyedEncodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
internal func encode(_ value: Bool, forKey key: Key) throws {
fatalError("_KeyedEncodingContainerBase cannot be used directly.")
}
@@ -2471,6 +2833,12 @@
@_inlineable
@_versioned
+ override internal func encodeNil(forKey key: Key) throws {
+ try concrete.encodeNil(forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
override internal func encode(_ value: Bool, forKey key: Key) throws {
try concrete.encode(value, forKey: key)
}
@@ -2703,6 +3071,102 @@
@_inlineable
@_versioned
+ internal func decodeNil(forKey key: Key) throws -> Bool {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode(_ type: String.Type, forKey key: Key) throws -> String {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
+ internal func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
+ fatalError("_KeyedDecodingContainerBase cannot be used directly.")
+ }
+
+ @_inlineable
+ @_versioned
internal func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
fatalError("_KeyedDecodingContainerBase cannot be used directly.")
}
@@ -2850,6 +3314,102 @@
@_inlineable
@_versioned
+ override internal func decodeNil(forKey key: Key) throws -> Bool {
+ return try concrete.decodeNil(forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
+ return try concrete.decode(Bool.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
+ return try concrete.decode(Int.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
+ return try concrete.decode(Int8.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
+ return try concrete.decode(Int16.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
+ return try concrete.decode(Int32.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
+ return try concrete.decode(Int64.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
+ return try concrete.decode(UInt.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
+ return try concrete.decode(UInt8.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
+ return try concrete.decode(UInt16.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
+ return try concrete.decode(UInt32.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
+ return try concrete.decode(UInt64.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
+ return try concrete.decode(Float.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
+ return try concrete.decode(Double.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode(_ type: String.Type, forKey key: Key) throws -> String {
+ return try concrete.decode(String.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
+ override internal func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
+ return try concrete.decode(T.self, forKey: key)
+ }
+
+ @_inlineable
+ @_versioned
override internal func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
return try concrete.decodeIfPresent(Bool.self, forKey: key)
}
@@ -3618,14 +4178,14 @@
// Convenience Default Implementations
//===----------------------------------------------------------------------===//
-// Default implementation for encodeWeak(_:forKey:) in terms of encode(_:forKey:)
+// Default implementation of encodeWeak(_:forKey:) in terms of encode(_:forKey:)
public extension KeyedEncodingContainerProtocol {
public mutating func encodeWeak<T : AnyObject & Encodable>(_ object: T, forKey key: Key) throws {
try encode(object, forKey: key)
}
}
-// Default implementation for encodeIfPresent(_:forKey:) in terms of encode(_:forKey:)
+// Default implementation of encodeIfPresent(_:forKey:) in terms of encode(_:forKey:)
public extension KeyedEncodingContainerProtocol {
public mutating func encodeIfPresent(_ value: Bool?, forKey key: Key) throws {
guard let value = value else { return }
@@ -3703,371 +4263,255 @@
}
}
-// Default implementations for decode(_:forKey:) in terms of decodeIfPresent(_:forKey:)
+// Default implementation of decodeIfPresent(_:forKey:) in terms of decode(_:forKey:) and decodeNil(forKey:)
public extension KeyedDecodingContainerProtocol {
- @_semantics("optimize.sil.specialize.generic.never")
- @_semantics("optimize.sil.specialize.generic.partial.never")
- @inline(never)
- internal func _errorInDecoding<T: Decodable>(_ type: T.Type, forKey key: Key) -> DecodingError {
- if contains(key) {
- var path = codingPath
- path.append(key)
- return DecodingError.valueNotFound(type, DecodingError.Context(codingPath: path, debugDescription: "Found null value when expecting non-optional type \(type) for coding key \"\(key)\""))
- } else {
- var path = codingPath
- path.append(key)
- return DecodingError.keyNotFound(key, DecodingError.Context(codingPath: path, debugDescription: "Key not found when expecting non-optional type \(type) for coding key \"\(key)\""))
- }
+ public func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Bool.self, forKey: key)
}
- public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
- if let value = try decodeIfPresent(Bool.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Int.Type, forKey key: Key) throws -> Int? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Int.self, forKey: key)
}
- public func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
- if let value = try decodeIfPresent(Int.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Int8.Type, forKey key: Key) throws -> Int8? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Int8.self, forKey: key)
}
- public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
- if let value = try decodeIfPresent(Int8.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Int16.Type, forKey key: Key) throws -> Int16? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Int16.self, forKey: key)
}
- public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
- if let value = try decodeIfPresent(Int16.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Int32.Type, forKey key: Key) throws -> Int32? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Int32.self, forKey: key)
}
- public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
- if let value = try decodeIfPresent(Int32.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Int64.Type, forKey key: Key) throws -> Int64? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Int64.self, forKey: key)
}
- public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
- if let value = try decodeIfPresent(Int64.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: UInt.Type, forKey key: Key) throws -> UInt? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(UInt.self, forKey: key)
}
- public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
- if let value = try decodeIfPresent(UInt.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: UInt8.Type, forKey key: Key) throws -> UInt8? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(UInt8.self, forKey: key)
}
- public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
- if let value = try decodeIfPresent(UInt8.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: UInt16.Type, forKey key: Key) throws -> UInt16? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(UInt16.self, forKey: key)
}
- public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
- if let value = try decodeIfPresent(UInt16.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: UInt32.Type, forKey key: Key) throws -> UInt32? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(UInt32.self, forKey: key)
}
- public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
- if let value = try decodeIfPresent(UInt32.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: UInt64.Type, forKey key: Key) throws -> UInt64? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(UInt64.self, forKey: key)
}
- public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
- if let value = try decodeIfPresent(UInt64.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Float.Type, forKey key: Key) throws -> Float? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Float.self, forKey: key)
}
- public func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
- if let value = try decodeIfPresent(Float.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: Double.Type, forKey key: Key) throws -> Double? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(Double.self, forKey: key)
}
- public func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
- if let value = try decodeIfPresent(Double.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent(_ type: String.Type, forKey key: Key) throws -> String? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(String.self, forKey: key)
}
- public func decode(_ type: String.Type, forKey key: Key) throws -> String {
- if let value = try decodeIfPresent(String.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
- }
-
- public func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
- if let value = try decodeIfPresent(T.self, forKey: key) {
- return value
- } else {
- throw _errorInDecoding(type, forKey: key)
- }
+ public func decodeIfPresent<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T? {
+ guard try self.contains(key) && !self.decodeNil(forKey: key) else { return nil }
+ return try self.decode(T.self, forKey: key)
}
}
// Default implementation of encodeWeak(_:) in terms of encode(_:), and encode(contentsOf:) in terms of encode(_:) loop.
public extension UnkeyedEncodingContainer {
public mutating func encodeWeak<T : AnyObject & Encodable>(_ object: T) throws {
- try encode(object)
+ try self.encode(object)
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Bool {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Int {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Int8 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Int16 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Int32 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Int64 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == UInt {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == UInt8 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == UInt16 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == UInt32 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == UInt64 {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Float {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == Double {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element == String {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
public mutating func encode<T : Sequence>(contentsOf sequence: T) throws where T.Iterator.Element : Encodable {
for element in sequence {
- try encode(element)
+ try self.encode(element)
}
}
}
-// Default implementations for decode(_:) in terms of decodeIfPresent(_:)
+// Default implementation of decodeIfPresent(_:) in terms of decode(_:) and decodeNil()
public extension UnkeyedDecodingContainer {
- @_semantics("optimize.sil.specialize.generic.never")
- @_semantics("optimize.sil.specialize.generic.partial.never")
- @inline(never)
- internal func _errorInDecoding<T: Decodable>(_ type: T.Type) -> DecodingError {
- if !isAtEnd {
- return DecodingError.valueNotFound(type, DecodingError.Context(codingPath: codingPath, debugDescription: "Found null value when expecting non-optional type \(type)"))
- } else {
- return DecodingError.valueNotFound(type, DecodingError.Context(codingPath: codingPath, debugDescription: "No remaining elements when expecting non-optional type \(type)"))
- }
+ mutating func decodeIfPresent(_ type: Bool.Type) throws -> Bool? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Bool.self)
}
- mutating func decode(_ type: Bool.Type) throws -> Bool {
- if let value = try decodeIfPresent(Bool.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Int.Type) throws -> Int? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Int.self)
}
- mutating func decode(_ type: Int.Type) throws -> Int {
- if let value = try decodeIfPresent(Int.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Int8.Type) throws -> Int8? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Int8.self)
}
- mutating func decode(_ type: Int8.Type) throws -> Int8 {
- if let value = try decodeIfPresent(Int8.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Int16.Type) throws -> Int16? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Int16.self)
}
- mutating func decode(_ type: Int16.Type) throws -> Int16 {
- if let value = try decodeIfPresent(Int16.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Int32.Type) throws -> Int32? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Int32.self)
}
- mutating func decode(_ type: Int32.Type) throws -> Int32 {
- if let value = try decodeIfPresent(Int32.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Int64.Type) throws -> Int64? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Int64.self)
}
- mutating func decode(_ type: Int64.Type) throws -> Int64 {
- if let value = try decodeIfPresent(Int64.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: UInt.Type) throws -> UInt? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(UInt.self)
}
- mutating func decode(_ type: UInt.Type) throws -> UInt {
- if let value = try decodeIfPresent(UInt.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: UInt8.Type) throws -> UInt8? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(UInt8.self)
}
- mutating func decode(_ type: UInt8.Type) throws -> UInt8 {
- if let value = try decodeIfPresent(UInt8.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: UInt16.Type) throws -> UInt16? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(UInt16.self)
}
- mutating func decode(_ type: UInt16.Type) throws -> UInt16 {
- if let value = try decodeIfPresent(UInt16.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: UInt32.Type) throws -> UInt32? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(UInt32.self)
}
- mutating func decode(_ type: UInt32.Type) throws -> UInt32 {
- if let value = try decodeIfPresent(UInt32.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: UInt64.Type) throws -> UInt64? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(UInt64.self)
}
- mutating func decode(_ type: UInt64.Type) throws -> UInt64 {
- if let value = try decodeIfPresent(UInt64.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Float.Type) throws -> Float? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Float.self)
}
- mutating func decode(_ type: Float.Type) throws -> Float {
- if let value = try decodeIfPresent(Float.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: Double.Type) throws -> Double? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(Double.self)
}
- mutating func decode(_ type: Double.Type) throws -> Double {
- if let value = try decodeIfPresent(Double.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent(_ type: String.Type) throws -> String? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(String.self)
}
- mutating func decode(_ type: String.Type) throws -> String {
- if let value = try decodeIfPresent(String.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
- }
-
- mutating func decode<T : Decodable>(_ type: T.Type) throws -> T {
- if let value = try decodeIfPresent(T.self) {
- return value
- } else {
- throw _errorInDecoding(type)
- }
+ mutating func decodeIfPresent<T : Decodable>(_ type: T.Type) throws -> T? {
+ guard try !self.isAtEnd && !self.decodeNil() else { return nil }
+ return try self.decode(T.self)
}
}
diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp
index f144698..7c89d92 100644
--- a/stdlib/public/runtime/Exclusivity.cpp
+++ b/stdlib/public/runtime/Exclusivity.cpp
@@ -226,24 +226,6 @@
}
};
-/// A set of independent access sets. This is not designed to put
-/// the access sets on different cache lines, so it's fine for
-/// thread-local sets and probably not fine for concurrent sets.
-class AccessSets {
- enum { NumAccessSets = 8 };
- AccessSet Sets[NumAccessSets];
-
-public:
- constexpr AccessSets() = default;
- AccessSets(const AccessSets &) = delete;
- AccessSets &operator=(const AccessSets &) = delete;
-
- AccessSet &get(void *pointer) {
- size_t index = std::hash<void*>()(pointer) % NumAccessSets;
- return Sets[index];
- }
-};
-
} // end anonymous namespace
// Each of these cases should define a function with this prototype:
@@ -253,10 +235,10 @@
// Use direct language support for thread-locals.
static_assert(LLVM_ENABLE_THREADS, "LLVM_THREAD_LOCAL will use a global?");
-static LLVM_THREAD_LOCAL AccessSets ExclusivityAccessSets;
+static LLVM_THREAD_LOCAL AccessSet ExclusivityAccessSet;
-static AccessSets &getAllSets() {
- return ExclusivityAccessSets;
+static AccessSet &getAccessSet() {
+ return ExclusivityAccessSet;
}
#elif SWIFT_EXCLUSIVITY_USE_PTHREAD_SPECIFIC
@@ -265,7 +247,7 @@
static pthread_key_t createAccessSetPthreadKey() {
pthread_key_t key;
int result = pthread_key_create(&key, [](void *pointer) {
- delete static_cast<AccessSets*>(pointer);
+ delete static_cast<AccessSet*>(pointer);
});
if (result != 0) {
@@ -275,15 +257,15 @@
return key;
}
-static AccessSets &getAllSets() {
+static AccessSet &getAccessSet() {
static pthread_key_t key = createAccessSetPthreadKey();
- AccessSets *sets = static_cast<AccessSets*>(pthread_getspecific(key));
- if (!sets) {
- sets = new AccessSets();
- pthread_setspecific(key, sets);
+ AccessSet *set = static_cast<AccessSet*>(pthread_getspecific(key));
+ if (!set) {
+ set = new AccessSet();
+ pthread_setspecific(key, set);
}
- return *sets;
+ return *set;
}
/** An access set accessed via pthread_get_specific. *************************/
@@ -291,11 +273,6 @@
#error No implementation chosen for exclusivity!
#endif
-/// Return the right access set for the given pointer.
-static AccessSet &getAccessSet(void *pointer) {
- return getAllSets().get(pointer);
-}
-
/// Begin tracking a dynamic access.
///
/// This may cause a runtime failure if an incompatible access is
@@ -315,7 +292,7 @@
if (!pc) pc = get_return_address();
- getAccessSet(pointer).insert(access, pc, pointer, flags);
+ getAccessSet().insert(access, pc, pointer, flags);
}
/// End tracking a dynamic access.
@@ -329,5 +306,5 @@
return;
}
- getAccessSet(pointer).remove(access);
+ getAccessSet().remove(access);
}
diff --git a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt
index 6ea47fa..590c5e9 100644
--- a/test/ClangImporter/Inputs/SwiftPrivateAttr.txt
+++ b/test/ClangImporter/Inputs/SwiftPrivateAttr.txt
@@ -107,7 +107,7 @@
static var __PrivA: NSOptions { get }
static var B: NSOptions { get }
}
-class __PrivCFType : _CFObject {
+class __PrivCFType {
}
@available(swift, obsoleted: 3, renamed: "__PrivCFType")
typealias __PrivCFTypeRef = __PrivCFType
diff --git a/test/ClangImporter/Inputs/custom-modules/Protocols.h b/test/ClangImporter/Inputs/custom-modules/Protocols.h
index 43ad828..552adbd 100644
--- a/test/ClangImporter/Inputs/custom-modules/Protocols.h
+++ b/test/ClangImporter/Inputs/custom-modules/Protocols.h
@@ -9,3 +9,12 @@
Class <FooProto, AnotherProto> _Nonnull processComboType(Class <FooProto, AnotherProto> _Nonnull);
Class <AnotherProto, FooProto> _Nonnull processComboType2(Class <AnotherProto, FooProto> _Nonnull);
+
+@protocol SubProto <FooProto>
+@end
+
+@interface ProtocolTestingBase
+@end
+
+@interface SubProtoImpl: ProtocolTestingBase <SubProto>
+@end
diff --git a/test/ClangImporter/Inputs/frameworks/Simple.framework/Headers/Simple.h b/test/ClangImporter/Inputs/frameworks/Simple.framework/Headers/Simple.h
new file mode 100644
index 0000000..8e399ab
--- /dev/null
+++ b/test/ClangImporter/Inputs/frameworks/Simple.framework/Headers/Simple.h
@@ -0,0 +1,6 @@
+@interface SimpleInterface
+@end
+
+@protocol SimpleProtocol
+- (void)foo:(SimpleInterface *)foo;
+@end
diff --git a/test/ClangImporter/Inputs/frameworks/Simple.framework/Modules/module.modulemap b/test/ClangImporter/Inputs/frameworks/Simple.framework/Modules/module.modulemap
new file mode 100644
index 0000000..0a72a6d
--- /dev/null
+++ b/test/ClangImporter/Inputs/frameworks/Simple.framework/Modules/module.modulemap
@@ -0,0 +1,7 @@
+framework module Simple {
+ umbrella header "Simple.h"
+ export *
+ module * {
+ export *
+ }
+}
diff --git a/test/ClangImporter/Inputs/frameworks/Simple.framework/Simple b/test/ClangImporter/Inputs/frameworks/Simple.framework/Simple
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/ClangImporter/Inputs/frameworks/Simple.framework/Simple
diff --git a/test/ClangImporter/Inputs/other.swift b/test/ClangImporter/Inputs/other.swift
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/ClangImporter/Inputs/other.swift
diff --git a/test/ClangImporter/Inputs/pch-bridging-header-with-non-modular-import.h b/test/ClangImporter/Inputs/pch-bridging-header-with-non-modular-import.h
new file mode 100644
index 0000000..228a1cf
--- /dev/null
+++ b/test/ClangImporter/Inputs/pch-bridging-header-with-non-modular-import.h
@@ -0,0 +1,4 @@
+// This is probably intended as a modular import, but it's compiled in an
+// environment in which it can also be (and is) interpreted as a non-modular
+// import.
+#import <Simple/Simple.h>
diff --git a/test/ClangImporter/pch-bridging-header-vs-modular-interface-defn.swift b/test/ClangImporter/pch-bridging-header-vs-modular-interface-defn.swift
new file mode 100644
index 0000000..01e96a5
--- /dev/null
+++ b/test/ClangImporter/pch-bridging-header-vs-modular-interface-defn.swift
@@ -0,0 +1,87 @@
+//
+// Scenario for this test (this actually occurs in the wild):
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// 1. A header for module M, in include-path, that defines @interface Foo
+// and a @protocol Bar that references Foo in one of its methods.
+//
+// 2. A symlink in include-path that links into M's (modular) header dir,
+// which effectively makes a "second definition" of the same interface
+// and protocol pair, but in a non-modular context.
+//
+// 3. A bridging header that imports the (non-modular)
+// header-defining-Foo-and-Bar
+//
+// 4. A swift file that imports M and implements Bar (thus referencing Foo).
+//
+// 5. Another swift file that does nothing special, but makes for a multi-file
+// compilation (requiring a merge-module step).
+//
+//
+// What was previously going wrong (that we're testing for):
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// 1. Module M gets compiled into a PCM file with a local defn for M.Foo and
+// M.Bar referencing M.Foo.
+//
+// 2. The bridging header gets precompiled to a PCH with a non-modular
+// definition of Foo and Bar (because of the order we pass -Xcc includes
+// to the clang importer, they are preferred over frameworks).
+//
+// 3. Every time swift asks clang to import a defn -- modular or non-modular
+// -- clang reads _both_ definitions: first the one requested, then the
+// other one as a completion of its view of the set of defns for the
+// symbol. This wouldn't normally be a huge problem _except_ that in clang
+// rev 2ba19793, the rules for interfaces and protocols diverged:
+// interfaces became first-read-wins, protocols remained last-read-wins.
+//
+// 4. This means that when swift looks up (protocol) Bar, the non-modular
+// definition is found in the PCH, clang completes it with a modular defn,
+// and (since it's a protocol) last-read-wins: the modular M.Bar defn
+// sticks. Swift then does a load-all-members on M.Bar and gets the
+// (directly-referenced) M.Foo defn, but since Foo is an interface, M.Foo
+// is the first-read and it sticks (ignoring the non-modular Foo read
+// immediately-after from the PCH). So Swift emits an XRef to M.Foo into
+// the partial .swiftmodule.
+//
+// 5. Later, the merge-modules step executes and reloads the .swiftmodule
+// file, reading the XRef to M.Foo. Unfortunately when it's run with a
+// textual bridging header, the textual, non-modular defn of Foo is fed
+// directly into the compiler by the preprocessor, so it sticks before any
+// lookups get started. This makes the modular XRef lookup of M.Foo fail.
+//
+//
+// Why disabling bridging PCH fixes this
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// The first-read defn of Foo is fed into clang early, which sticks (as in
+// the merge-modules step). This makes the serialized XRef have the form
+// __ObjC.Foo, which succeeds when performed the second time in merge-modules.
+//
+//
+// How to fix it:
+// ~~~~~~~~~~~~~~
+//
+// One might hope that this can be fixed by having the merge-modules step take a
+// PCH as well as other steps in the compilation. That unfortuantely only
+// inverts the problem, which resurfaces in the definition-order of Bar itself:
+// an XRef to __ObjC.Bar gets serialized, and then _it_ can't be found during
+// merge-modules, because the *last-read* defn of Bar -- the modular one, M.Bar
+// -- wins during lookup.
+//
+// So while we _do_ propose to have the merge-modules step use the PCH, we also
+// put a patch into clang to apply the first-read-wins logic to protocols as
+// well as interfaces.
+//
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/Headers/Simple
+// RUN: ln -s %S/Inputs/frameworks/Simple.framework/Headers/Simple.h %t/Headers/Simple/Simple.h
+// RUN: %target-build-swift -emit-module -module-name test -Xfrontend -disable-deserialization-recovery -v -F %S/Inputs/frameworks -Xcc "-I%t/Headers" -module-cache-path %t/clang-module-cache -import-objc-header %S/Inputs/pch-bridging-header-with-non-modular-import.h %S/Inputs/other.swift %s
+// REQUIRES: objc_interop
+
+import Simple
+class Foo: SimpleProtocol {
+ func foo(_ bar: SimpleInterface) {
+ }
+}
diff --git a/test/ClangImporter/protocol-conformance-in-extension.swift b/test/ClangImporter/protocol-conformance-in-extension.swift
new file mode 100644
index 0000000..69a4c83
--- /dev/null
+++ b/test/ClangImporter/protocol-conformance-in-extension.swift
@@ -0,0 +1,21 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t/a~partial.swiftmodule -I %S/Inputs/custom-modules -module-name TEST -primary-file %s
+// RUN: %target-swift-frontend -emit-module -o %t/test.swiftmodule -I %S/Inputs/custom-modules -module-name TEST %t/a~partial.swiftmodule
+
+// REQUIRES: objc_interop
+
+import TestProtocols
+
+// The protocol in the extension has to refine something that the base class
+// conforms to to trigger the error in rdar://problem/32346184.
+protocol SomeSwiftProto: Equatable {}
+extension ProtocolTestingBase: Equatable {
+ public static func ==(left: ProtocolTestingBase, right: ProtocolTestingBase) -> Bool {
+ return left === right
+ }
+}
+
+// The extension going through the typealias also makes a difference.
+typealias SpecialObject = SubProtoImpl
+extension SpecialObject: SomeSwiftProto {
+}
diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift
index 8a5dc06..f023418 100644
--- a/test/Generics/associated_type_typo.swift
+++ b/test/Generics/associated_type_typo.swift
@@ -14,7 +14,7 @@
protocol P3 { }
protocol P4 { }
-// expected-error@+1{{'assoc' is not a member type of 'T'}}
+// expected-error@+1{{'T' does not have a member type named 'assoc'; did you mean 'Assoc'?}}
func typoAssoc1<T : P1>(x: T.assoc, _: T) { }
// expected-error@+2{{'T' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{53-58=Assoc}}
@@ -22,7 +22,7 @@
func typoAssoc2<T : P1, U : P1>(_: T, _: U) where T.assoc == U.assoc {}
// CHECK-GENERIC-LABEL: .typoAssoc2
-// CHECK-GENERIC: Generic signature: <T, U where T : P1, U : P1, T.Assoc == U.Assoc>
+// CHECK-GENERIC: Generic signature: <T, U where T : P1, U : P1>
// expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{42-47=Assoc}}
// expected-error@+2{{'U.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{19-24=Assoc}}
@@ -30,9 +30,8 @@
where U.AssocP2.assoc : P3, T.AssocP2.assoc : P4,
T.AssocP2 == U.AssocP2 {}
-// expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}
-// expected-error@+2{{'T' does not have a member type named 'Assocp2'; did you mean 'AssocP2'?}}{{39-46=AssocP2}}
-// expected-error@+1{{'assoc' is not a member type of 'T.AssocP2'}}
+// expected-error@+2{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}
+// expected-error@+1{{'T' does not have a member type named 'Assocp2'; did you mean 'AssocP2'?}}{{39-46=AssocP2}}
func typoAssoc4<T : P2>(_: T) where T.Assocp2.assoc : P3 {}
@@ -40,7 +39,6 @@
// CHECK-GENERIC-NEXT: Requirements:
// CHECK-GENERIC-NEXT: τ_0_0 : P2 [τ_0_0: Explicit @ {{.*}}:21]
// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2 : P1 [τ_0_0: Explicit @ {{.*}}:21 -> Protocol requirement (via Self.AssocP2 in P2)
-// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [τ_0_0[.P2].AssocP2[.P1].Assoc: Explicit @ {{.*}}:53]
// CHECK-GENERIC-NEXT: Potential archetypes
// <rdar://problem/19620340>
@@ -75,3 +73,17 @@
where Element_<C> == Element
, Element_<C.Slice> == Element
}
+
+class C {
+ typealias SomeElement = Int
+}
+
+func typoSuperclass1<T : C>(_: T) where T.someElement: P3 { }
+// expected-error@-1{{'T' does not have a member type named 'someElement'; did you mean 'SomeElement'?}}{{43-54=SomeElement}}
+
+class D {
+ typealias AElement = Int // expected-note{{did you mean 'AElement'?}}
+ typealias BElement = Int // expected-note{{did you mean 'BElement'?}}
+}
+
+func typoSuperclass2<T : D>(_: T, _: T.Element) { } // expected-error{{'Element' is not a member type of 'T'}}
diff --git a/test/IDE/complete_member_decls_from_parent_decl_context.swift b/test/IDE/complete_member_decls_from_parent_decl_context.swift
index 7d93383..bda9d39 100644
--- a/test/IDE/complete_member_decls_from_parent_decl_context.swift
+++ b/test/IDE/complete_member_decls_from_parent_decl_context.swift
@@ -234,11 +234,11 @@
func testInstanceFunc() {
struct NestedInnerA {
mutating
- func aTestInstaceFunc() {
+ func aTestInstanceFunc() {
#^NESTED_NOMINAL_DECL_A_1^#
// NESTED_NOMINAL_DECL_A_1: Begin completions
// NESTED_NOMINAL_DECL_A_1-DAG: Decl[LocalVar]/Local: self[#NestedInnerA#]{{; name=.+$}}
-// NESTED_NOMINAL_DECL_A_1-DAG: Decl[InstanceMethod]/CurrNominal: aTestInstaceFunc()[#Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_A_1-DAG: Decl[InstanceMethod]/CurrNominal: aTestInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_1-DAG: Decl[InstanceVar]/CurrNominal: aInstanceVar[#Int#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_1-DAG: Decl[InstanceMethod]/CurrNominal: aInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_1-DAG: Decl[Struct]/CurrNominal: NestedInnerAStruct[#NestedInnerA.NestedInnerAStruct#]{{; name=.+$}}
@@ -259,7 +259,7 @@
#^NESTED_NOMINAL_DECL_A_2^#
// NESTED_NOMINAL_DECL_A_2: Begin completions
// NESTED_NOMINAL_DECL_A_2-DAG: Decl[LocalVar]/Local: self[#NestedInnerA.Type#]{{; name=.+$}}
-// NESTED_NOMINAL_DECL_A_2-DAG: Decl[InstanceMethod]/CurrNominal: aTestInstaceFunc({#self: &NestedInnerA#})[#() -> Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_A_2-DAG: Decl[InstanceMethod]/CurrNominal: aTestInstanceFunc({#self: &NestedInnerA#})[#() -> Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_2-DAG: Decl[StaticMethod]/CurrNominal: aTestStaticFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_2-DAG: Decl[InstanceMethod]/CurrNominal: aInstanceFunc({#self: &NestedInnerA#})[#() -> Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_2-DAG: Decl[StaticVar]/CurrNominal: aStaticVar[#Int#]{{; name=.+$}}
@@ -325,7 +325,7 @@
NestedInnerA()#^NESTED_NOMINAL_DECL_A_5^#
// NESTED_NOMINAL_DECL_A_5: Begin completions, 4 items
-// NESTED_NOMINAL_DECL_A_5-NEXT: Decl[InstanceMethod]/CurrNominal: .aTestInstaceFunc()[#Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_A_5-NEXT: Decl[InstanceMethod]/CurrNominal: .aTestInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_5-NEXT: Decl[InstanceVar]/CurrNominal: .aInstanceVar[#Int#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_5-NEXT: Decl[InstanceMethod]/CurrNominal: .aInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_A_5-NEXT: Decl[Subscript]/CurrNominal: [{#Int#}][#Double#]{{; name=.+$}}
@@ -335,11 +335,11 @@
static func testStaticFunc() {
struct NestedInnerB {
mutating
- func bTestInstaceFunc() {
+ func bTestInstanceFunc() {
#^NESTED_NOMINAL_DECL_B_1^#
// NESTED_NOMINAL_DECL_B_1: Begin completions
// NESTED_NOMINAL_DECL_B_1-DAG: Decl[LocalVar]/Local: self[#NestedInnerB#]{{; name=.+$}}
-// NESTED_NOMINAL_DECL_B_1-DAG: Decl[InstanceMethod]/CurrNominal: bTestInstaceFunc()[#Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_B_1-DAG: Decl[InstanceMethod]/CurrNominal: bTestInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_1-DAG: Decl[InstanceVar]/CurrNominal: bInstanceVar[#Int#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_1-DAG: Decl[InstanceMethod]/CurrNominal: bInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_1-DAG: Decl[Struct]/CurrNominal: NestedInnerBStruct[#NestedInnerB.NestedInnerBStruct#]{{; name=.+$}}
@@ -363,7 +363,7 @@
#^NESTED_NOMINAL_DECL_B_2^#
// NESTED_NOMINAL_DECL_B_2: Begin completions
// NESTED_NOMINAL_DECL_B_2-DAG: Decl[LocalVar]/Local: self[#NestedInnerB.Type#]{{; name=.+$}}
-// NESTED_NOMINAL_DECL_B_2-DAG: Decl[InstanceMethod]/CurrNominal: bTestInstaceFunc({#self: &NestedInnerB#})[#() -> Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_B_2-DAG: Decl[InstanceMethod]/CurrNominal: bTestInstanceFunc({#self: &NestedInnerB#})[#() -> Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_2-DAG: Decl[StaticMethod]/CurrNominal: bTestStaticFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_2-DAG: Decl[InstanceMethod]/CurrNominal: bInstanceFunc({#self: &NestedInnerB#})[#() -> Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_2-DAG: Decl[StaticVar]/CurrNominal: bStaticVar[#Int#]{{; name=.+$}}
@@ -434,7 +434,7 @@
NestedInnerB()#^NESTED_NOMINAL_DECL_B_5^#
// NESTED_NOMINAL_DECL_B_5: Begin completions, 4 items
-// NESTED_NOMINAL_DECL_B_5-DAG: Decl[InstanceMethod]/CurrNominal: .bTestInstaceFunc()[#Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_B_5-DAG: Decl[InstanceMethod]/CurrNominal: .bTestInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_5-DAG: Decl[InstanceVar]/CurrNominal: .bInstanceVar[#Int#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_5-DAG: Decl[InstanceMethod]/CurrNominal: .bInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_B_5-DAG: Decl[Subscript]/CurrNominal: [{#Int#}][#Double#]{{; name=.+$}}
@@ -452,11 +452,11 @@
func testOuterC() {
struct NestedInnerC {
mutating
- func cTestInstaceFunc() {
+ func cTestInstanceFunc() {
#^NESTED_NOMINAL_DECL_C_1^#
// NESTED_NOMINAL_DECL_C_1: Begin completions
// NESTED_NOMINAL_DECL_C_1-DAG: Decl[LocalVar]/Local: self[#NestedInnerC#]{{; name=.+$}}
-// NESTED_NOMINAL_DECL_C_1-DAG: Decl[InstanceMethod]/CurrNominal: cTestInstaceFunc()[#Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_C_1-DAG: Decl[InstanceMethod]/CurrNominal: cTestInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_1-DAG: Decl[InstanceVar]/CurrNominal: cInstanceVar[#Int#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_1-DAG: Decl[InstanceMethod]/CurrNominal: cInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_1-DAG: Decl[Struct]/CurrNominal: NestedInnerCStruct[#NestedInnerC.NestedInnerCStruct#]{{; name=.+$}}
@@ -472,7 +472,7 @@
#^NESTED_NOMINAL_DECL_C_2^#
// NESTED_NOMINAL_DECL_C_2: Begin completions
// NESTED_NOMINAL_DECL_C_2-DAG: Decl[LocalVar]/Local: self[#NestedInnerC.Type#]{{; name=.+$}}
-// NESTED_NOMINAL_DECL_C_2-DAG: Decl[InstanceMethod]/CurrNominal: cTestInstaceFunc({#self: &NestedInnerC#})[#() -> Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_C_2-DAG: Decl[InstanceMethod]/CurrNominal: cTestInstanceFunc({#self: &NestedInnerC#})[#() -> Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_2-DAG: Decl[StaticMethod]/CurrNominal: cTestStaticFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_2-DAG: Decl[InstanceMethod]/CurrNominal: cInstanceFunc({#self: &NestedInnerC#})[#() -> Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_2-DAG: Decl[StaticVar]/CurrNominal: cStaticVar[#Int#]{{; name=.+$}}
@@ -525,7 +525,7 @@
NestedInnerC()#^NESTED_NOMINAL_DECL_C_5^#
// NESTED_NOMINAL_DECL_C_5: Begin completions, 4 items
-// NESTED_NOMINAL_DECL_C_5-NEXT: Decl[InstanceMethod]/CurrNominal: .cTestInstaceFunc()[#Void#]{{; name=.+$}}
+// NESTED_NOMINAL_DECL_C_5-NEXT: Decl[InstanceMethod]/CurrNominal: .cTestInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_5-NEXT: Decl[InstanceVar]/CurrNominal: .cInstanceVar[#Int#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_5-NEXT: Decl[InstanceMethod]/CurrNominal: .cInstanceFunc()[#Void#]{{; name=.+$}}
// NESTED_NOMINAL_DECL_C_5-NEXT: Decl[Subscript]/CurrNominal: [{#Int#}][#Double#]{{; name=.+$}}
diff --git a/test/IRGen/ordering_x86.sil b/test/IRGen/ordering_x86.sil
index ddae69d..c83e803 100644
--- a/test/IRGen/ordering_x86.sil
+++ b/test/IRGen/ordering_x86.sil
@@ -2,6 +2,7 @@
// RUN: %swift -target i386-apple-ios7.1 %s -module-name main -emit-ir -o - | %FileCheck %s
// RUN: %swift -target x86_64-apple-ios7.1 %s -module-name main -emit-ir -o - | %FileCheck %s
// RUN: %swift -target x86_64-unknown-linux-gnu -disable-objc-interop %s -module-name main -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target x86_64-apple-macosx10.9 -module-name main %s -emit-ir -o - | %FileCheck %s --check-prefix=X86_64
// REQUIRES: CODEGENERATOR=X86
@@ -34,3 +35,10 @@
// CHECK: define{{( protected)?}} swiftcc void @foo
// CHECK: define{{( protected)?}} swiftcc void @bar
// CHECK: define{{( protected)?}} swiftcc void @baz
+
+// Make sure that the target features are ordered. We care because function
+// merging does not identify two otherwise identical functions as the same if
+// the order of features differs.
+
+// X86_64: define{{( protected)?}} swiftcc void @baz{{.*}}#0
+// X86_64: #0 = {{.*}}"target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87"
diff --git a/test/Index/Store/Inputs/ClangModuleA.h b/test/Index/Store/Inputs/ClangModuleA.h
new file mode 100644
index 0000000..ea06ce2
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleA.h
@@ -0,0 +1 @@
+void funcA(void);
diff --git a/test/Index/Store/Inputs/ClangModuleB.h b/test/Index/Store/Inputs/ClangModuleB.h
new file mode 100644
index 0000000..ce316e2
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleB.h
@@ -0,0 +1,2 @@
+@import ClangModuleA;
+void funcB(void);
diff --git a/test/Index/Store/Inputs/ClangModuleCSub1.h b/test/Index/Store/Inputs/ClangModuleCSub1.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleCSub1.h
diff --git a/test/Index/Store/Inputs/ClangModuleCSub2.h b/test/Index/Store/Inputs/ClangModuleCSub2.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleCSub2.h
diff --git a/test/Index/Store/Inputs/SwiftModuleA.swift b/test/Index/Store/Inputs/SwiftModuleA.swift
new file mode 100644
index 0000000..59e7758
--- /dev/null
+++ b/test/Index/Store/Inputs/SwiftModuleA.swift
@@ -0,0 +1 @@
+public func funcSwiftA() {}
diff --git a/test/Index/Store/Inputs/SwiftModuleB.swift b/test/Index/Store/Inputs/SwiftModuleB.swift
new file mode 100644
index 0000000..b12db68
--- /dev/null
+++ b/test/Index/Store/Inputs/SwiftModuleB.swift
@@ -0,0 +1,2 @@
+import SwiftModuleA
+public func funcSwiftB() { funcSwiftA() }
diff --git a/test/Index/Store/Inputs/bridge-head.h b/test/Index/Store/Inputs/bridge-head.h
new file mode 100644
index 0000000..b25d652
--- /dev/null
+++ b/test/Index/Store/Inputs/bridge-head.h
@@ -0,0 +1 @@
+#include "bridge-include.h"
diff --git a/test/Index/Store/Inputs/bridge-include.h b/test/Index/Store/Inputs/bridge-include.h
new file mode 100644
index 0000000..55a0722
--- /dev/null
+++ b/test/Index/Store/Inputs/bridge-include.h
@@ -0,0 +1,2 @@
+int includedFunc(int a);
+int MY_CONST = 2;
\ No newline at end of file
diff --git a/test/Index/Store/Inputs/module.modulemap b/test/Index/Store/Inputs/module.modulemap
new file mode 100644
index 0000000..a25324f
--- /dev/null
+++ b/test/Index/Store/Inputs/module.modulemap
@@ -0,0 +1,20 @@
+module ClangModuleA {
+ header "ClangModuleA.h"
+ export *
+}
+module ClangModuleB {
+ header "ClangModuleB.h"
+ export *
+}
+
+module ClangModuleC {
+ module Sub1 {
+ header "ClangModuleCSub1.h"
+ export *
+ }
+
+ module Sub2 {
+ header "ClangModuleCSub2.h"
+ export *
+ }
+}
diff --git a/test/Index/Store/driver-index.swift b/test/Index/Store/driver-index.swift
new file mode 100644
index 0000000..b8007d0
--- /dev/null
+++ b/test/Index/Store/driver-index.swift
@@ -0,0 +1,2 @@
+// RUN: %swiftc_driver -driver-print-jobs -index-file -index-file-path %s %S/Inputs/SwiftModuleA.swift %s -o %t.output_for_index -index-store-path %t.index_store -module-name driver_index 2>&1 | %FileCheck %s
+// CHECK: {{.*}}swift -frontend -typecheck {{.*}}-primary-file {{.*}}driver-index.swift {{.*}}SwiftModuleA.swift {{.*}}driver-index.swift {{.*}}-o {{.*}}.output_for_index {{.*}}-index-store-path {{.*}}.index_store -index-system-modules
diff --git a/test/Index/Store/output-failure.swift b/test/Index/Store/output-failure.swift
new file mode 100644
index 0000000..24167e3
--- /dev/null
+++ b/test/Index/Store/output-failure.swift
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir %t/idx
+
+// Before indexing, do a dry-run to ensure any clang modules are cached. We
+// want to isolate the error that comes from swift's indexing support, not
+// any failures indexing a clang module.
+// RUN: %target-swift-frontend %s -typecheck
+
+// RUN: chmod -w %t/idx
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/dir.txt || chmod +w %t/idx
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx
+// RUN: %FileCheck %s -check-prefix=DIR_ERR < %t/dir.txt
+// DIR_ERR: error: creating index directory
+
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o
+// test -s %t/idx/*/units/oof.o*
+
+// RUN: chmod -w %t/idx/*/units
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/file.txt || chmod +w %t/idx/*/units
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx/*/units
+// RUN: %FileCheck %s -check-prefix=FILE_ERR < %t/file.txt
+// FILE_ERR: error: writing index unit file
+
+// RUN: rm -rf %t/idx/*/records/*
+// RUN: chmod -x %t/idx/*/records
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/record.txt || chmod +x %t/idx/*/records
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +x %t/idx/*/records
+// RUN: %FileCheck %s -check-prefix=RECORD_ERR < %t/record.txt
+// RECORD_ERR: error: writing index record file
+
+// RUN: rm -rf %t/idx/*/records/*
+// RUN: chmod -w %t/idx/*/records
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/record2.txt || chmod +w %t/idx/*/records
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx/*/records
+// RUN: %FileCheck %s -check-prefix=RECORD_ERR < %t/record2.txt
+
+func foo() {}
diff --git a/test/Index/Store/record-comments.swift b/test/Index/Store/record-comments.swift
new file mode 100644
index 0000000..5d356f1
--- /dev/null
+++ b/test/Index/Store/record-comments.swift
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t.o -typecheck %s
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: record-comments.swift
+// CHECK: ------------
+// CHECK: comment-tag/Swift | <no-name> | t:this_is_a_tag | <no-cgname> | Def -
+// CHECK: comment-tag/Swift | <no-name> | t:and_another | <no-cgname> | Def -
+// CHECK: ------------
+
+/// Hello
+/// - Tag: this_is_a_tag
+/// - Tag: and_another
+func foo() {}
+// CHECK: [[@LINE-3]]:5 | comment-tag/Swift | t:this_is_a_tag | Def | rel: 0
+// CHECK: [[@LINE-3]]:5 | comment-tag/Swift | t:and_another | Def | rel: 0
+// CHECK: [[@LINE-3]]:6 | function/Swift |
diff --git a/test/Index/Store/record-dependency.swift b/test/Index/Store/record-dependency.swift
new file mode 100644
index 0000000..6c3777b
--- /dev/null
+++ b/test/Index/Store/record-dependency.swift
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// CHECK: DEPEND START
+// CHECK: Record | user | {{.*}}record-dependency.swift | record-dependency.swift-
+// CHECK: DEPEND END
+
+// RUN: echo 'func bar() {}' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx2 -emit-module -module-name main -emit-module-path %t/main.swiftmodule %s %t/s2.swift -o %t/file.o -o %t/s2.o
+// RUN: c-index-test core -print-unit %t/idx2 | %FileCheck %s -check-prefix=TWO_RECORDS
+// TWO_RECORDS: file.o-
+// TWO_RECORDS: DEPEND START
+// TWO_RECORDS: Record | user | {{.*}}record-dependency.swift | record-dependency.swift-
+// TWO_RECORDS: DEPEND END
+// TWO_RECORDS: s2.o-
+// TWO_RECORDS: DEPEND START
+// TWO_RECORDS: Record | user | {{.*}}s2.swift | s2.swift-
+// TWO_RECORDS: DEPEND END
+
+// XFAIL: linux
+
+func foo() {}
diff --git a/test/Index/Store/record-empty.swift b/test/Index/Store/record-empty.swift
new file mode 100644
index 0000000..c7bdd9e
--- /dev/null
+++ b/test/Index/Store/record-empty.swift
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck -primary-file %s
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// CHECK-NOT: Record{{.*}}record-empty
+
+// XFAIL: linux
diff --git a/test/Index/Store/record-hashing.swift b/test/Index/Store/record-hashing.swift
new file mode 100644
index 0000000..665d4a3
--- /dev/null
+++ b/test/Index/Store/record-hashing.swift
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: echo "func foo() {}" > %t/theinput.swift
+
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: ls %t/idx/*/records/* | grep "theinput.swift" | count 1
+// RUN: cp -r %t/idx %t/idx-orig
+
+// RUN: touch %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// No change in record.
+
+// RUN: echo '// Comment.' >> %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// No change in record.
+
+// RUN: echo 'func goo() {}' >> %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: not diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// RUN: ls %t/idx/*/records/* | grep "theinput.swift" | count 2
+// Changed! Wrote a new record.
diff --git a/test/Index/Store/record-sourcefile.swift b/test/Index/Store/record-sourcefile.swift
new file mode 100644
index 0000000..129f7cc
--- /dev/null
+++ b/test/Index/Store/record-sourcefile.swift
@@ -0,0 +1,155 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx1 -o %t/file.o -typecheck %s
+// RUN: %target-swift-frontend -index-store-path %t/idx2 -o %t/file.o -typecheck -primary-file %s
+// RUN: c-index-test core -print-record %t/idx1 | %FileCheck %s
+// RUN: c-index-test core -print-record %t/idx2 | %FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: record-sourcefile.swift
+// CHECK: ------------
+// CHECK: struct/Swift | S1 | s:4file2S1V | <no-cgname> | Def,Ref,RelCont -
+// CHECK: instance-method/acc-get/Swift | getter:property | s:4file2S1V8propertySifg | <no-cgname> | Def,Ref,Call,Impl,RelChild,RelRec,RelCall,RelAcc,RelCont -
+// CHECK: instance-property/Swift | property | [[property_USR:s:4file2S1V8propertySiv]] | <no-cgname> | Def,Ref,Read,RelChild,RelCont -
+// CHECK: static-method/acc-get/Swift | getter:staticProperty | s:4file2S1V14staticPropertySifg | <no-cgname> | Def,Ref,Call,Impl,RelChild,RelRec,RelCall,RelAcc,RelCont -
+// CHECK: static-property/Swift | staticProperty | s:{{.*}} | <no-cgname> | Def,Ref,Read,RelChild,RelCont -
+// CHECK: instance-property/Swift | computedPropertyGetSet | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: struct/Swift | Int | s:Si | <no-cgname> | Ref -
+// CHECK: instance-method/acc-get/Swift | getter:computedPropertyGetSet | s:4file2S1V22computedPropertyGetSetSifg | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-set/Swift | setter:computedPropertyGetSet | s:4file2S1V22computedPropertyGetSetSifs | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-property/Swift | computedPropertyWillDid | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-willset/Swift | willSet:computedPropertyWillDid | s:4file2S1V23computedPropertyWillDidSifw | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-didset/Swift | didSet:computedPropertyWillDid | s:4file2S1V23computedPropertyWillDidSifW | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-property/Swift | computedPropertyAddressor | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-addr/Swift | <no-name> | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-mutaddr/Swift | <no-name> | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: static-method/Swift | staticMethod() | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-property/subscript/Swift | subscript(_:) | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-get/Swift | getter:subscript(_:) | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: protocol/Swift | P1 | s:{{.*}} | <no-cgname> | Def -
+// CHECK: type-alias/associated-type/Swift | AT | s:{{.*}} | <no-cgname> | Def,Ref,RelChild -
+// CHECK: type-alias/Swift | TA | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: class/Swift | C1 | s:{{.*}} | <no-cgname> | Def,Ref,RelBase,RelCont -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,Ref,Call,Dyn,RelChild,RelRec,RelCall,RelCont -
+// CHECK: class/Swift | C2 | s:{{.*}} | <no-cgname> | Def -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,Dyn,RelChild,RelOver -
+// CHECK: function/Swift | takeC1(x:) | s:{{.*}} | <no-cgname> | Def -
+// CHECK: instance-method(test)/Swift | testFoo() | s:{{.*}} | <no-cgname> | Def,Dyn,RelChild -
+// CHECK: ------------
+
+// CHECK: [[@LINE+1]]:8 | struct/Swift | [[S1_USR:s:.*]] | Def | rel: 0
+struct S1 {
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[property_USR]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ let property = 1
+// CHECK: [[@LINE+2]]:14 | static-property/Swift | [[staticProperty_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ static let staticProperty = 2
+
+// CHECK: [[@LINE+3]]:7 | instance-property/Swift | [[computedPropertyGetSet_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+// CHECK: [[@LINE+1]]:31 | struct/Swift | s:Si | Ref | rel: 0
+ var computedPropertyGetSet: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-get/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyGetSet_USR]]
+ get { return 1 }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-set/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyGetSet_USR]]
+ set { }
+ }
+
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[computedPropertyWillDid_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ var computedPropertyWillDid: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-willset/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyWillDid_USR]]
+ willSet { }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-didset/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyWillDid_USR]]
+ didSet { }
+ }
+
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[computedPropertyAddressor_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ var computedPropertyAddressor: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-addr/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyAddressor_USR]]
+ unsafeAddress { }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-mutaddr/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyAddressor_USR]]
+ unsafeMutableAddress { }
+ }
+
+// CHECK: [[@LINE+2]]:8 | instance-method/Swift | [[method_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ func method() {
+ _ = self
+// CHECK: [[@LINE+4]]:9 | instance-method/acc-get/Swift | s:{{.*}} | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[method_USR]]
+// CHECK-NEXT: RelRec | [[S1_USR]]
+// CHECK: [[@LINE+1]]:9 | instance-property/Swift | s:{{.*}} | Ref,Read,RelCont | rel: 1
+ _ = property
+ }
+
+// CHECK: [[@LINE+2]]:15 | static-method/Swift | [[staticMethod_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ static func staticMethod() {
+// CHECK: [[@LINE+5]]:9 | struct/Swift | s:{{.*}} | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+4]]:12 | static-method/acc-get/Swift | s:{{.*}} | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[staticMethod_USR]]
+// CHECK-NEXT: RelRec | [[S1_USR]]
+// CHECK: [[@LINE+1]]:12 | static-property/Swift | s:{{.*}} | Ref,Read,RelCont | rel: 1
+ _ = S1.staticProperty
+ }
+
+// CHECK: [[@LINE+4]]:3 | instance-property/subscript/Swift | [[S1_subscript_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+// CHECK: [[@LINE+2]]:28 | instance-method/acc-get/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[S1_subscript_USR]]
+ subscript(x: Int) -> Int { return 1 }
+}
+
+// CHECK: [[@LINE+1]]:10 | protocol/Swift | [[P1_USR:s:.*]] | Def | rel: 0
+protocol P1 {
+// CHECK: [[@LINE+2]]:18 | type-alias/associated-type/Swift | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[P1_USR]]
+ associatedtype AT
+// CHECK: [[@LINE+3]]:13 | type-alias/Swift | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[P1_USR]]
+// CHECK: [[@LINE+1]]:18 | type-alias/associated-type/Swift | s:{{.*}} | Ref | rel: 0
+ typealias TA = AT
+}
+
+// CHECK: [[@LINE+1]]:7 | class/Swift | [[C1_USR:s:.*]] | Def | rel: 0
+class C1 {
+// CHECK: [[@LINE+2]]:8 | instance-method/Swift | [[C1_foo_USR:s:.*]] | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[C1_USR]]
+ func method() {}
+}
+// CHECK: [[@LINE+3]]:7 | class/Swift | [[C2_USR:s:.*]] | Def | rel: 0
+// CHECK: [[@LINE+2]]:12 | class/Swift | [[C1_USR]] | Ref,RelBase | rel: 1
+// CHECK-NEXT: RelBase | [[C2_USR]]
+class C2 : C1 {
+// CHECK: [[@LINE+3]]:17 | instance-method/Swift | s:{{.*}} | Def,Dyn,RelChild,RelOver | rel: 2
+// CHECK-NEXT: RelOver | [[C1_foo_USR]]
+// CHECK-NEXT: RelChild | [[C2_USR]]
+ override func method() {}
+}
+
+// CHECK: [[@LINE+2]]:6 | function/Swift | [[takeC1_USR:s:.*]] | Def | rel: 0
+// CHECK: [[@LINE+1]]:16 | class/Swift | s:{{.*}} | Ref,RelCont | rel: 1
+func takeC1(x: C1) {
+// CHECK: [[@LINE+3]]:5 | instance-method/Swift | s:{{.*}} | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[takeC1_USR]]
+// CHECK-NEXT: RelRec | [[C1_USR]]
+ x.method()
+}
+
+func test1() {}
+class XCTestCase {}
+class MyTestCase: XCTestCase {
+// CHECK: [[@LINE+2]]:8 | instance-method(test)/Swift | s:{{.*}} | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | s:4file10MyTestCaseC
+ func testFoo() { test1() }
+}
diff --git a/test/Index/Store/record-with-compile-error.swift b/test/Index/Store/record-with-compile-error.swift
new file mode 100644
index 0000000..0cb017d
--- /dev/null
+++ b/test/Index/Store/record-with-compile-error.swift
@@ -0,0 +1,12 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s -verify
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s
+
+// CHECK: function/Swift | test1() | [[TEST1_FUNC:.*]] | <no-cgname> | Def
+// CHECK: [[@LINE+1]]:6 | function/Swift | [[TEST1_FUNC]]
+func test1() {
+ unresolved() // expected-error {{use of unresolved identifier}}
+}
diff --git a/test/Index/Store/unit-from-compile.swift b/test/Index/Store/unit-from-compile.swift
new file mode 100644
index 0000000..2ddfb6e
--- /dev/null
+++ b/test/Index/Store/unit-from-compile.swift
@@ -0,0 +1,24 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend -c -index-store-path %t/idx %s -o %t/file1.o -module-name some_module_test
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// RUN: %target-swift-frontend -c -index-store-path %t/idx_opt %s -o %t/file1.o -module-name some_module_test -O
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=OPT
+
+// CHECK: file1.o
+// CHECK: provider: swift
+// CHECK: is-system: 0
+// CHECK: is-module: 0
+// CHECK: module-name: some_module_test
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}/unit-from-compile.swift
+// CHECK: out-file: {{.*}}/file1.o
+// CHECK: is-debug: 1
+
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}/Swift.swiftmodule |
+// CHECK: DEPEND END (1)
+
+// OPT: is-debug: 1
diff --git a/test/Index/Store/unit-multiple-sourcefiles.swift b/test/Index/Store/unit-multiple-sourcefiles.swift
new file mode 100644
index 0000000..a35350b
--- /dev/null
+++ b/test/Index/Store/unit-multiple-sourcefiles.swift
@@ -0,0 +1,33 @@
+// XFAIL: linux
+
+//===--- Building source files separately with a module merge at the end
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s1.swift %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %t/s1.swift %t/s2.swift -o %t/s1.o -c -module-name main -emit-module -emit-module-path %t/s1.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swift -primary-file %t/s2.swift -o %t/s2.o -c -module-name main -emit-module -emit-module-path %t/s2.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swiftmodule %t/s2.swiftmodule -emit-module -o %t/main.swiftmodule -module-name main
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+//===--- Building source files together (e.g. WMO)
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s1.swift %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swift %t/s2.swift -o %t/s1.o -o %t/s2.o -c -module-name main -emit-module -emit-module-path %t/main.swiftmodule
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+// CHECK-NOT: main.swiftmodule-{{[A-Z0-9]*}}
+
+// CHECK: s1.o-{{[A-Z0-9]*}}
+// CHECK: --------
+// CHECK: out-file: {{.*}}s1.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: s2.o-{{[A-Z0-9]*}}
+// CHECK: --------
+// CHECK: out-file: {{.*}}s2.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
diff --git a/test/Index/Store/unit-one-file-multi-file-invocation.swift b/test/Index/Store/unit-one-file-multi-file-invocation.swift
new file mode 100644
index 0000000..65d08c0
--- /dev/null
+++ b/test/Index/Store/unit-one-file-multi-file-invocation.swift
@@ -0,0 +1,23 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %swiftc_driver -index-file -index-file-path %s %s %S/Inputs/SwiftModuleA.swift -module-name unit_one_test -o %t.output_for_index -index-store-path %t/idx
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=UNIT
+
+// UNIT-NOT: SwiftShims
+
+// UNIT: [[SWIFT:Swift.swiftmodule-[A-Z0-9]*]]
+// UNIT: DEPEND START
+// UNIT: Record | system | Swift.Math.Floating | {{.*}}Swift.swiftmodule | Swift.swiftmodule_Math_Floating-{{.*}}
+// UNIT: Record | system | Swift.String | {{.*}}Swift.swiftmodule | Swift.swiftmodule_String-{{.*}}
+// UNIT: DEPEND END
+
+// UNIT: unit-one-file-multi-file-invocation{{.*}}.output_for_index
+// UNIT: DEPEND START
+// UNIT: Unit | system |{{.*}}/Swift.swiftmodule | [[SWIFT]]
+// UNIT: Record | user |{{.*}}/unit-one-file-multi-file-invocation.swift |
+// UNIT: DEPEND END (2)
+
+func test1() {
+ funcSwiftA()
+}
diff --git a/test/Index/Store/unit-one-sourcefile.swift b/test/Index/Store/unit-one-sourcefile.swift
new file mode 100644
index 0000000..d0acc59
--- /dev/null
+++ b/test/Index/Store/unit-one-sourcefile.swift
@@ -0,0 +1,29 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -o %t/file1.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s %t/s2.swift -o %t/file1.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -primary-file %t/s2.swift -o %t/file2.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE2
+
+// FILE1: file1.o-{{[A-Z0-9]*}}
+// FILE1: --------
+// FILE1: out-file: {{.*}}file1.o
+// FILE1: DEPEND START
+// FILE1: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE1: DEPEND END
+
+// FILE2: file2.o-{{[A-Z0-9]*}}
+// FILE2: --------
+// FILE2: out-file: {{.*}}file2.o
+// FILE2: DEPEND START
+// FILE2: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE2: DEPEND END
diff --git a/test/Index/Store/unit-pcm-dependency.swift b/test/Index/Store/unit-pcm-dependency.swift
new file mode 100644
index 0000000..c9721ba
--- /dev/null
+++ b/test/Index/Store/unit-pcm-dependency.swift
@@ -0,0 +1,79 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s -o %t/s1.o -I %S/Inputs -typecheck -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// If the module cache already exists, the pcm gets indexed.
+// RUN: rm -rf %t/idx
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s -o %t/s1.o -I %S/Inputs -typecheck -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// FIXME: index the bridging header!
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: echo 'import ClangModuleA' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s %t/s2.swift -o %t/s1.o -o %t/s2.o -I %S/Inputs -c -emit-module -module-name main -emit-module-path %t/main.swiftmodule -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx > %t/both.txt
+// RUN: %FileCheck %s -check-prefix=FILE1 < %t/both.txt
+// RUN: %FileCheck %s -check-prefix=FILE2 < %t/both.txt
+
+
+// XFAIL: linux
+
+import ClangModuleB
+import ClangModuleC.Sub1
+import ClangModuleC.Sub2
+
+func test() {
+ funcA()
+ funcB()
+}
+
+// FILE1: ClangModuleA-
+// FILE1: --------
+// FILE1: is-system: 0
+// FILE1: has-main: 0
+// FILE1: DEPEND START
+// FILE1: Record | user | {{.*}}ClangModuleA.h | ClangModuleA.h-
+// FILE1: DEPEND END
+
+// FILE1: ClangModuleB-
+// FILE1: --------
+// FILE1: is-system: 0
+// FILE1: has-main: 0
+// FILE1: DEPEND START
+// FILE1: Unit | user | ClangModuleA | {{.*}}ClangModuleA-{{.*}}.pcm | ClangModuleA-{{.*}}.pcm-
+// FILE1: Record | user | {{.*}}ClangModuleB.h | ClangModuleB.h-
+// FILE1: DEPEND END
+
+// FILE1: s1.o-
+// FILE1: --------
+// FILE1: has-main: 1
+// FILE1: DEPEND START
+// FILE1-NOT: ClangModuleA.h
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Unit | system | Swift | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Unit | user | ClangModuleB | {{.*}}ClangModuleB-{{[A-Z0-9]*}}.pcm | ClangModuleB-{{[A-Z0-9]*}}.pcm-
+// FILE1: Unit | user | ClangModuleC | {{.*}}ClangModuleC-{{[A-Z0-9]*}}.pcm | ClangModuleC-{{[A-Z0-9]*}}.pcm-
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Record | user | {{.*}}unit-pcm-dependency.swift | unit-pcm-dependency.swift-
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: DEPEND END (4)
+
+// FILE2-NOT: main.swiftmodule-
+
+// FILE2: s2.o-
+// FILE2: --------
+// FILE2: has-main: 1
+// FILE2: out-file: {{.*}}s2.o
+// FILE2: DEPEND START
+// FILE2-NOT: ClangModuleB.h
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: Unit | system | Swift | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: Unit | user | ClangModuleA | {{.*}}ClangModuleA-{{[A-Z0-9]*}}.pcm | ClangModuleA-{{[A-Z0-9]*}}.pcm-
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: DEPEND END
diff --git a/test/Index/Store/unit-swiftmodule-dependency.swift b/test/Index/Store/unit-swiftmodule-dependency.swift
new file mode 100644
index 0000000..df54f92
--- /dev/null
+++ b/test/Index/Store/unit-swiftmodule-dependency.swift
@@ -0,0 +1,57 @@
+// RUN: rm -rf %t && mkdir %t
+
+// RUN: %target-swift-frontend -index-store-path %t/idx %S/Inputs/SwiftModuleA.swift -emit-module -o %t/SwiftModuleA.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %S/Inputs/SwiftModuleB.swift -emit-module -o %t/SwiftModuleB.swiftmodule -I %t
+
+// RUN: echo 'import SwiftModuleA' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s %t/s2.swift -c -o %t/s1.o -o %t/s2.o -I %t -emit-module -module-name main -emit-module-path %t/main.swiftmodule
+
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+// XFAIL: linux
+
+import SwiftModuleA
+import SwiftModuleB
+
+func test() {
+ funcSwiftA()
+ funcSwiftB()
+}
+
+// CHECK: [[MODA:SwiftModuleA.swiftmodule-[A-Z0-9]*]]
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/SwiftModuleA.swiftmodule
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: [[MODB:SwiftModuleB.swiftmodule-[A-Z0-9]*]]
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/SwiftModuleB.swiftmodule
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK-NOT: main.swiftmodule-
+
+// CHECK: s1.o-
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/s1.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleB | {{.*}}/SwiftModuleB.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: s2.o-
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/s2.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
diff --git a/test/Index/Store/unit-with-bridging-header.swift b/test/Index/Store/unit-with-bridging-header.swift
new file mode 100644
index 0000000..f335802
--- /dev/null
+++ b/test/Index/Store/unit-with-bridging-header.swift
@@ -0,0 +1,49 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-pch -index-store-path %t/idx -o %t/bridge-head.pch %S/Inputs/bridge-head.h
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %t/bridge-head.pch -primary-file %s -o %t/s1.o -index-store-path %t/idx
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s --check-prefix=PCH-RECORD
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s --check-prefix=PCH-UNIT
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/bridge-head.h -primary-file %s -o %t/s1.o -index-store-path %t/idx2
+// RUN: c-index-test core -print-unit %t/idx2 | %FileCheck --check-prefix=TEXTUAL-UNIT %s
+
+// PCH-RECORD: bridge-include.h
+// PCH-RECORD: ------------
+// PCH-RECORD: function/C | includedFunc | {{.*}} | <no-cgname> | Decl -
+// PCH-RECORD: variable/C | MY_CONST | {{.*}} | <no-cgname> | Def -
+// PCH-RECORD: ------------
+// PCH-RECORD: 1:5 | function/C | {{.*}} | Decl | rel: 0
+// PCH-RECORD: 2:5 | variable/C | {{.*}} | Def | rel: 0
+
+// PCH-UNIT: bridge-head.pch-
+// PCH-UNIT: --------
+// PCH-UNIT: has-main: 0
+// PCH-UNIT: DEPEND START
+// PCH-UNIT: Record | user | {{.*}}bridge-include.h | bridge-include.h-
+// PCH-UNIT: File | user | {{.*}}bridge-head.h |
+// PCH-UNIT: File | user | {{.*}}module.modulemap |
+// PCH-UNIT: DEPEND END (3)
+// PCH-UNIT: INCLUDE START
+// PCH-UNIT: {{.*}}bridge-head.h:1 | {{.*}}bridge-include.h
+// PCH-UNIT: INCLUDE END (1)
+
+// PCH-UNIT: s1.o-
+// PCH-UNIT: --------
+// PCH-UNIT: has-main: 1
+// PCH-UNIT: DEPEND START
+// PCH-UNIT: Unit | system | {{.*}}Swift.swiftmodule |
+// PCH-UNIT: Unit | user | {{.*}}bridge-head.pch | bridge-head.pch-
+// PCH-UNIT: Record | user | {{.*}}unit-with-bridging-header.swift | unit-with-bridging-header.swift-
+// PCH-UNIT: DEPEND END (3)
+
+// TEXTUAL-UNIT: s1.o-
+// TEXTUAL-UNIT: --------
+// TEXTUAL-UNIT: has-main: 1
+// TEXTUAL-UNIT: DEPEND START
+// TEXTUAL-UNIT: Unit | system | {{.*}}Swift.swiftmodule |
+// TEXTUAL-UNIT: Record | user | {{.*}}unit-with-bridging-header.swift | unit-with-bridging-header.swift-
+// TEXTUAL-UNIT: DEPEND END (2)
+
+func test() {}
diff --git a/test/Parse/invalid.swift b/test/Parse/invalid.swift
index bf21c14..9ff219f 100644
--- a/test/Parse/invalid.swift
+++ b/test/Parse/invalid.swift
@@ -82,18 +82,18 @@
// expected-error @-1 {{parameter may not have multiple 'inout', 'var', or 'let' specifiers}} {{17-21=}}
func SR979e(inout x: inout String) {} // expected-error {{parameter may not have multiple 'inout', 'var', or 'let' specifiers}} {{13-18=}}
func SR979f(var inout x : Int) { // expected-error {{parameter may not have multiple 'inout', 'var', or 'let' specifiers}} {{17-23=}}
-// expected-error @-1 {{parameters may not have the 'var' specifier}} {{13-16=}}{{3-3=var x = x\n }}
- x += 10
+// expected-error @-1 {{'var' as a parameter attribute is not allowed}}
+ x += 10 // expected-error {{left side of mutating operator isn't mutable: 'x' is a 'let' constant}}
}
func SR979g(inout i: inout Int) {} // expected-error {{parameter may not have multiple 'inout', 'var', or 'let' specifiers}} {{13-18=}}
func SR979h(let inout x : Int) {} // expected-error {{parameter may not have multiple 'inout', 'var', or 'let' specifiers}} {{17-23=}}
// expected-error @-1 {{'let' as a parameter attribute is not allowed}}
class VarTester {
- init(var a: Int, var b: Int) {} // expected-error {{parameters may not have the 'var' specifier}} {{8-11=}} {{33-33= var a = a }}
- // expected-error @-1 {{parameters may not have the 'var' specifier}} {{20-24=}} {{33-33= var b = b }}
- func x(var b: Int) { //expected-error {{parameters may not have the 'var' specifier}} {{12-15=}} {{9-9=var b = b\n }}
- b += 10
- }
+ init(var a: Int, var b: Int) {} // expected-error {{'var' as a parameter attribute is not allowed}}
+ // expected-error @-1 {{'var' as a parameter attribute is not allowed}}
+ func x(var b: Int) { //expected-error {{'var' as a parameter attribute is not allowed}}
+ b += 10 // expected-error {{left side of mutating operator isn't mutable: 'b' is a 'let' constant}}
+ }
}
func repeat() {}
diff --git a/test/SILOptimizer/capture_promotion_ownership.sil b/test/SILOptimizer/capture_promotion_ownership.sil
index b970e1d..601a0e4 100644
--- a/test/SILOptimizer/capture_promotion_ownership.sil
+++ b/test/SILOptimizer/capture_promotion_ownership.sil
@@ -335,7 +335,7 @@
}
// This test makes sure that we properly handle non load uses of
-// struct_element_addr that always have load users with the load occuring before
+// struct_element_addr that always have load users with the load occurring before
// and after the element in the use list.
sil @mutate_int : $@convention(thin) (@inout Int) -> ()
diff --git a/test/SILOptimizer/eager_specialize.sil b/test/SILOptimizer/eager_specialize.sil
index 0dfc62a..d9d66a4 100644
--- a/test/SILOptimizer/eager_specialize.sil
+++ b/test/SILOptimizer/eager_specialize.sil
@@ -394,7 +394,7 @@
// CHECK: %11 = builtin "cmp_eq_Word"(%9 : $Builtin.Word, %10 : $Builtin.Word) : $Builtin.Int1
// CHECK: cond_br %11, bb4, bb2
-// None of the constraint checks was successfull, perform a generic copy.
+// None of the constraint checks was successful, perform a generic copy.
// CHECK: bb2:
// CHECK: copy_addr %2 to [initialization] %0 : $*S
// CHECK: destroy_addr %1 : $*S
@@ -470,7 +470,7 @@
// CHECK: %4 = builtin "ispod"<S>(%3 : $@thick S.Type) : $Builtin.Int1
// CHECK: cond_br %4, bb3, bb1
-// None of the constraint checks was successfull, perform a generic copy.
+// None of the constraint checks was successful, perform a generic copy.
// CHECK: bb1:
// CHECK: copy_addr %2 to [initialization] %0 : $*S
// CHECK: destroy_addr %1 : $*S
@@ -620,7 +620,7 @@
// CHECK: %6 = builtin "cmp_eq_Word"(%4 : $Builtin.Word, %5 : $Builtin.Word) : $Builtin.Int1
// CHECK: cond_br %6, bb3, bb1
-// Type dispatch was not successfull.
+// Type dispatch was not successful.
// CHECK: bb1:
// CHECK: destroy_addr %1 : $*S
// CHECK: destroy_addr %0 : $*T
diff --git a/test/SILOptimizer/specialize.sil b/test/SILOptimizer/specialize.sil
index 7b3a2a6..77db10d 100644
--- a/test/SILOptimizer/specialize.sil
+++ b/test/SILOptimizer/specialize.sil
@@ -7,7 +7,7 @@
// CHECK-LABEL: sil @exp1 : $@convention(thin) () -> () {
// CHECK-NOT: apply
-// Call of specialized intializer: <Int32>
+// Call of specialized initializer: <Int32>
// CHECK: [[CTOR:%[0-9]+]] = function_ref @_T08XXX_inits5Int32V_Tg5
// CHECK: apply [[CTOR]]
// CHECK: [[ACCEPTS_INT:%[0-9]+]] = function_ref @acceptsInt
diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift
index be0e092..c7825f4 100644
--- a/test/Sema/immutability.swift
+++ b/test/Sema/immutability.swift
@@ -348,11 +348,11 @@
func invalid_inout(inout var x : Int) { // expected-error {{parameter may not have multiple 'inout', 'var', or 'let' specifiers}} {{26-30=}}
// expected-error @-1 {{'inout' before a parameter name is not allowed, place it before the parameter type instead}}{{20-25=}}{{34-34=inout }}
}
-func invalid_var(var x: Int) { // expected-error {{parameters may not have the 'var' specifier}}{{18-21=}} {{1-1= var x = x\n}}
+func invalid_var(var x: Int) { // expected-error {{'var' as a parameter attribute is not allowed}}
}
func takesClosure(_: (Int) -> Int) {
- takesClosure { (var d) in d } // expected-error {{parameters may not have the 'var' specifier}}
+ takesClosure { (var d) in d } // expected-error {{'var' as a parameter attribute is not allowed}}
}
func updateInt(_ x : inout Int) {}
diff --git a/test/decl/class/override.swift b/test/decl/class/override.swift
index 2396c86..852d672 100644
--- a/test/decl/class/override.swift
+++ b/test/decl/class/override.swift
@@ -169,8 +169,8 @@
func manyA(_: AnyObject, _: AnyObject) {}
func manyB(_ a: AnyObject, b: AnyObject) {}
- func manyC(var a: AnyObject, // expected-error {{parameters may not have the 'var' specifier}} {{14-17=}}
- var b: AnyObject) {} // expected-error {{parameters may not have the 'var' specifier}} {{14-18=}}
+ func manyC(var a: AnyObject, // expected-error {{'var' as a parameter attribute is not allowed}}
+ var b: AnyObject) {} // expected-error {{'var' as a parameter attribute is not allowed}}
func result() -> AnyObject? { return nil }
func both(_ x: AnyObject) -> AnyObject? { return x }
diff --git a/test/decl/var/usage.swift b/test/decl/var/usage.swift
index 904290b..b6236f8 100644
--- a/test/decl/var/usage.swift
+++ b/test/decl/var/usage.swift
@@ -12,10 +12,10 @@
return y
}
-func mutableParameter(_ a : Int, h : Int, var i : Int, j: Int, g: Int) -> Int { // expected-error {{parameters may not have the 'var' specifier}}
- i += 1
+func mutableParameter(_ a : Int, h : Int, var i : Int, j: Int, g: Int) -> Int { // expected-error {{'var' as a parameter attribute is not allowed}}
+ i += 1 // expected-error {{left side of mutating operator isn't mutable: 'i' is a 'let' constant}}
var j = j
- swap(&i, &j)
+ swap(&i, &j) // expected-error {{cannot pass immutable value as inout argument: 'i' is a 'let' constant}}
return i+g
}
diff --git a/test/stdlib/TestData.swift b/test/stdlib/TestData.swift
index 55297fa..4d46703 100644
--- a/test/stdlib/TestData.swift
+++ b/test/stdlib/TestData.swift
@@ -1034,19 +1034,19 @@
func test_splittingHttp() {
func split(_ data: Data, on delimiter: String) -> [Data] {
- let dataDelimeter = delimiter.data(using: .utf8)!
+ let dataDelimiter = delimiter.data(using: .utf8)!
var found = [Data]()
let start = data.startIndex
- let end = data.endIndex.advanced(by: -dataDelimeter.count)
+ let end = data.endIndex.advanced(by: -dataDelimiter.count)
guard end >= start else { return [data] }
var index = start
var previousIndex = index
while index < end {
- let slice = data[index..<index.advanced(by: dataDelimeter.count)]
+ let slice = data[index..<index.advanced(by: dataDelimiter.count)]
- if slice == dataDelimeter {
+ if slice == dataDelimiter {
found.append(data[previousIndex..<index])
- previousIndex = index + dataDelimeter.count
+ previousIndex = index + dataDelimiter.count
}
index = index.advanced(by: 1)
diff --git a/test/stdlib/TestJSONEncoder.swift b/test/stdlib/TestJSONEncoder.swift
index 5a8a4a8..4882858 100644
--- a/test/stdlib/TestJSONEncoder.swift
+++ b/test/stdlib/TestJSONEncoder.swift
@@ -92,6 +92,17 @@
_testRoundTrip(of: employee)
}
+ func testEncodingTopLevelNullableType() {
+ // EnhancedBool is a type which encodes either as a Bool or as nil.
+ _testEncodeFailure(of: EnhancedBool.true)
+ _testEncodeFailure(of: EnhancedBool.false)
+ _testEncodeFailure(of: EnhancedBool.fileNotFound)
+
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.true), expectedJSON: "{\"value\":true}".data(using: .utf8)!)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.false), expectedJSON: "{\"value\":false}".data(using: .utf8)!)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.fileNotFound), expectedJSON: "{\"value\":null}".data(using: .utf8)!)
+ }
+
// MARK: - Output Formatting Tests
func testEncodingOutputFormattingDefault() {
let expectedJSON = "{\"name\":\"Johnny Appleseed\",\"email\":\"appleseed@apple.com\"}".data(using: .utf8)!
@@ -661,61 +672,30 @@
}
}
-// MARK: - Helper Types
-
-/// Wraps a type T so that it can be encoded at the top level of a payload.
-fileprivate struct TopLevelWrapper<T> : Codable, Equatable where T : Codable, T : Equatable {
- let value: T
-
- init(_ value: T) {
- self.value = value
- }
-
- static func ==(_ lhs: TopLevelWrapper<T>, _ rhs: TopLevelWrapper<T>) -> Bool {
- return lhs.value == rhs.value
- }
-}
-
-fileprivate struct FloatNaNPlaceholder : Codable, Equatable {
- init() {}
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.singleValueContainer()
- try container.encode(Float.nan)
- }
+/// An enum type which decodes from Bool?.
+fileprivate enum EnhancedBool : Codable {
+ case `true`
+ case `false`
+ case fileNotFound
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
- let float = try container.decode(Float.self)
- if !float.isNaN {
- throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Couldn't decode NaN."))
+ if container.decodeNil() {
+ self = .fileNotFound
+ } else {
+ let value = try container.decode(Bool.self)
+ self = value ? .true : .false
}
}
- static func ==(_ lhs: FloatNaNPlaceholder, _ rhs: FloatNaNPlaceholder) -> Bool {
- return true
- }
-}
-
-fileprivate struct DoubleNaNPlaceholder : Codable, Equatable {
- init() {}
-
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
- try container.encode(Double.nan)
- }
-
- init(from decoder: Decoder) throws {
- let container = try decoder.singleValueContainer()
- let double = try container.decode(Double.self)
- if !double.isNaN {
- throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Couldn't decode NaN."))
+ switch self {
+ case .true: try container.encode(true)
+ case .false: try container.encode(false)
+ case .fileNotFound: try container.encodeNil()
}
}
-
- static func ==(_ lhs: DoubleNaNPlaceholder, _ rhs: DoubleNaNPlaceholder) -> Bool {
- return true
- }
}
/// A type which encodes as an array directly through a single value container.
@@ -864,6 +844,63 @@
}
}
+// MARK: - Helper Types
+
+/// Wraps a type T so that it can be encoded at the top level of a payload.
+fileprivate struct TopLevelWrapper<T> : Codable, Equatable where T : Codable, T : Equatable {
+ let value: T
+
+ init(_ value: T) {
+ self.value = value
+ }
+
+ static func ==(_ lhs: TopLevelWrapper<T>, _ rhs: TopLevelWrapper<T>) -> Bool {
+ return lhs.value == rhs.value
+ }
+}
+
+fileprivate struct FloatNaNPlaceholder : Codable, Equatable {
+ init() {}
+
+ func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ try container.encode(Float.nan)
+ }
+
+ init(from decoder: Decoder) throws {
+ let container = try decoder.singleValueContainer()
+ let float = try container.decode(Float.self)
+ if !float.isNaN {
+ throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Couldn't decode NaN."))
+ }
+ }
+
+ static func ==(_ lhs: FloatNaNPlaceholder, _ rhs: FloatNaNPlaceholder) -> Bool {
+ return true
+ }
+}
+
+fileprivate struct DoubleNaNPlaceholder : Codable, Equatable {
+ init() {}
+
+ func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ try container.encode(Double.nan)
+ }
+
+ init(from decoder: Decoder) throws {
+ let container = try decoder.singleValueContainer()
+ let double = try container.decode(Double.self)
+ if !double.isNaN {
+ throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Couldn't decode NaN."))
+ }
+ }
+
+ static func ==(_ lhs: DoubleNaNPlaceholder, _ rhs: DoubleNaNPlaceholder) -> Bool {
+ return true
+ }
+}
+
// MARK: - Run Tests
#if !FOUNDATION_XCTEST
@@ -879,6 +916,7 @@
JSONEncoderTests.test("testEncodingTopLevelStructuredSingleClass") { TestJSONEncoder().testEncodingTopLevelStructuredSingleClass() }
JSONEncoderTests.test("testEncodingTopLevelDeepStructuredType") { TestJSONEncoder().testEncodingTopLevelDeepStructuredType()}
JSONEncoderTests.test("testEncodingClassWhichSharesEncoderWithSuper") { TestJSONEncoder().testEncodingClassWhichSharesEncoderWithSuper() }
+JSONEncoderTests.test("testEncodingTopLevelNullableType") { TestJSONEncoder().testEncodingTopLevelNullableType() }
JSONEncoderTests.test("testEncodingOutputFormattingDefault") { TestJSONEncoder().testEncodingOutputFormattingDefault() }
JSONEncoderTests.test("testEncodingOutputFormattingPrettyPrinted") { TestJSONEncoder().testEncodingOutputFormattingPrettyPrinted() }
JSONEncoderTests.test("testEncodingOutputFormattingSortedKeys") { TestJSONEncoder().testEncodingOutputFormattingSortedKeys() }
diff --git a/test/stdlib/TestPlistEncoder.swift b/test/stdlib/TestPlistEncoder.swift
index 2ae6377..9f55f38 100644
--- a/test/stdlib/TestPlistEncoder.swift
+++ b/test/stdlib/TestPlistEncoder.swift
@@ -111,6 +111,24 @@
_testRoundTrip(of: employee, in: .xml)
}
+ func testEncodingTopLevelNullableType() {
+ // EnhancedBool is a type which encodes either as a Bool or as nil.
+ _testEncodeFailure(of: EnhancedBool.true, in: .binary)
+ _testEncodeFailure(of: EnhancedBool.true, in: .xml)
+ _testEncodeFailure(of: EnhancedBool.false, in: .binary)
+ _testEncodeFailure(of: EnhancedBool.false, in: .xml)
+ _testEncodeFailure(of: EnhancedBool.fileNotFound, in: .binary)
+ _testEncodeFailure(of: EnhancedBool.fileNotFound, in: .xml)
+
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.true), in: .binary)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.true), in: .xml)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.false), in: .binary)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.false), in: .xml)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.fileNotFound), in: .binary)
+ _testRoundTrip(of: TopLevelWrapper(EnhancedBool.fileNotFound), in: .xml)
+ }
+
+
// MARK: - Encoder Features
func testNestedContainerCodingPaths() {
let encoder = JSONEncoder()
@@ -438,6 +456,32 @@
}
}
+/// An enum type which decodes from Bool?.
+fileprivate enum EnhancedBool : Codable {
+ case `true`
+ case `false`
+ case fileNotFound
+
+ init(from decoder: Decoder) throws {
+ let container = try decoder.singleValueContainer()
+ if container.decodeNil() {
+ self = .fileNotFound
+ } else {
+ let value = try container.decode(Bool.self)
+ self = value ? .true : .false
+ }
+ }
+
+ func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ switch self {
+ case .true: try container.encode(true)
+ case .false: try container.encode(false)
+ case .fileNotFound: try container.encodeNil()
+ }
+ }
+}
+
/// A type which encodes as an array directly through a single value container.
struct Numbers : Codable, Equatable {
let values = [4, 8, 15, 16, 23, 42]
@@ -614,6 +658,7 @@
PropertyListEncoderTests.test("testEncodingTopLevelStructuredSingleClass") { TestPropertyListEncoder().testEncodingTopLevelStructuredSingleClass() }
PropertyListEncoderTests.test("testEncodingTopLevelDeepStructuredType") { TestPropertyListEncoder().testEncodingTopLevelDeepStructuredType() }
PropertyListEncoderTests.test("testEncodingClassWhichSharesEncoderWithSuper") { TestPropertyListEncoder().testEncodingClassWhichSharesEncoderWithSuper() }
+PropertyListEncoderTests.test("testEncodingTopLevelNullableType") { TestPropertyListEncoder().testEncodingTopLevelNullableType() }
PropertyListEncoderTests.test("testNestedContainerCodingPaths") { TestPropertyListEncoder().testNestedContainerCodingPaths() }
PropertyListEncoderTests.test("testSuperEncoderCodingPaths") { TestPropertyListEncoder().testSuperEncoderCodingPaths() }
runAllTests()
diff --git a/unittests/AST/SourceLocTests.cpp b/unittests/AST/SourceLocTests.cpp
index 617469e..1ce40ec 100644
--- a/unittests/AST/SourceLocTests.cpp
+++ b/unittests/AST/SourceLocTests.cpp
@@ -151,7 +151,8 @@
.addMemBufferCopy("if let x = Optional.some(1) { }");
SourceLoc start = C.Ctx.SourceMgr.getLocForBufferStart(bufferID);
- auto vardecl = new (C.Ctx) VarDecl(/*IsStatic*/false, /*IsLet*/true,
+ auto vardecl = new (C.Ctx) VarDecl(/*IsStatic*/false,
+ VarDecl::Specifier::Let,
/*IsCaptureList*/false,
start.getAdvancedLoc(7)
, C.Ctx.getIdentifier("x")
diff --git a/unittests/runtime/Metadata.cpp b/unittests/runtime/Metadata.cpp
index 9e3a8c5..869cbf3 100644
--- a/unittests/runtime/Metadata.cpp
+++ b/unittests/runtime/Metadata.cpp
@@ -874,7 +874,7 @@
// The existential's box reference should be copied.
EXPECT_EQ(buf1.buffer.PrivateData[0], buf2.buffer.PrivateData[0]);
- // Ownership of the box should have been transfered.
+ // Ownership of the box should have been transferred.
auto *reference = reinterpret_cast<HeapObject *>(buf2.buffer.PrivateData[0]);
EXPECT_TRUE(swift_isUniquelyReferencedOrPinned_nonNull_native(reference));
diff --git a/utils/symbolicate-linux-fatal b/utils/symbolicate-linux-fatal
index 86f77ad..565ace8 100755
--- a/utils/symbolicate-linux-fatal
+++ b/utils/symbolicate-linux-fatal
@@ -79,6 +79,45 @@
known_memmap = {}
+def check_base_address(dynlib_path, dynlib_baseaddr, memmap):
+ global known_memmap
+ if dynlib_path in memmap or dynlib_path in known_memmap:
+ if dynlib_path in memmap:
+ existing_baseaddr = memmap[dynlib_path]
+ else:
+ existing_baseaddr = known_memmap[dynlib_path]
+ if existing_baseaddr != dynlib_baseaddr:
+ error_msg = "Mismatched base address for: {0:s}, " \
+ "had: {1:x}, now got {2:x}"
+ error_msg = error_msg.format(
+ dynlib_path, existing_baseaddr, dynlib_baseaddr)
+ raise Exception(error_msg)
+
+
+def symbolicate_one(frame_addr, frame_idx, dynlib_fname):
+ global lldb_target
+ so_addr = lldb_target.ResolveLoadAddress(frame_addr - 1)
+ sym_ctx = so_addr.GetSymbolContext(lldb.eSymbolContextEverything)
+ frame_fragment = "{0: <4d} {1:20s} 0x{2:016x}".format(
+ frame_idx, dynlib_fname, frame_addr)
+ symbol = sym_ctx.GetSymbol()
+ if not symbol.IsValid():
+ raise Exception("symbol isn't valid")
+
+ symbol_base = symbol.GetStartAddress().GetLoadAddress(lldb_target)
+ symbol_fragment = "{0:s} + {1:d}".format(
+ symbol.GetName(), frame_addr - symbol_base)
+ line_entry = sym_ctx.GetLineEntry()
+ if line_entry.IsValid():
+ line_fragment = "at {0:s}:{1:d}".format(
+ line_entry.GetFileSpec().GetFilename(), line_entry.GetLine())
+ else:
+ line_fragment = ""
+
+ return "{0:s} {1:s} {2:s}".format(
+ frame_fragment, symbol_fragment, line_fragment)
+
+
def process_stack(binary, dyn_libs, stack):
global lldb_target
global known_memmap
@@ -96,26 +135,20 @@
else:
dynlib_path = None
- if "<unavailable>" in stack_tokens[3]:
+ try:
framePC = int(stack_tokens[2], 16)
symbol_offset = int(stack_tokens[-1], 10)
+ except:
+ full_stack.append({"line": line, "framePC": 0, "dynlib_fname": ""})
+ continue
+
+ if "<unavailable>" in stack_tokens[3]:
dynlib_baseaddr = framePC - symbol_offset
- if dynlib_path in memmap or dynlib_path in known_memmap:
- if dynlib_path in memmap:
- existing_baseaddr = memmap[dynlib_path]
- else:
- existing_baseaddr = known_memmap[dynlib_path]
- if existing_baseaddr != dynlib_baseaddr:
- error_msg = "Mismatched base address for: {0:s}, " \
- "had: {1:x}, now got {2:x}"
- error_msg = error_msg.format(
- dynlib_path, existing_baseaddr, dynlib_baseaddr)
- raise Exception(error_msg)
- else:
- known_memmap[dynlib_path] = dynlib_baseaddr
- memmap[dynlib_path] = dynlib_baseaddr
+ check_base_address(dynlib_path, dynlib_baseaddr, memmap)
+ known_memmap[dynlib_path] = dynlib_baseaddr
+ memmap[dynlib_path] = dynlib_baseaddr
else:
- framePC = int(stack_tokens[2], 16) + int(stack_tokens[-1], 10)
+ framePC = framePC + symbol_offset
full_stack.append(
{"line": line, "framePC": framePC, "dynlib_fname": dynlib_fname})
@@ -125,32 +158,13 @@
add_lldb_target_modules(lldb_target, memmap)
frame_idx = 0
for frame in full_stack:
- use_orig_line = True
frame_addr = frame["framePC"]
dynlib_fname = frame["dynlib_fname"]
- so_addr = lldb_target.ResolveLoadAddress(frame_addr - 1)
- sym_ctx = so_addr.GetSymbolContext(lldb.eSymbolContextEverything)
- frame_fragment = "{0: <4d} {1:20s} 0x{2:016x}".format(
- frame_idx, dynlib_fname, frame_addr)
- symbol = sym_ctx.GetSymbol()
- if symbol.IsValid():
- symbol_base = symbol.GetStartAddress().GetLoadAddress(lldb_target)
- symbol_fragment = "{0:s} + {1:d}".format(
- symbol.GetName(), frame_addr - symbol_base)
- use_orig_line = False
- else:
- symbol_fragment = "<unavailable>"
- line_entry = sym_ctx.GetLineEntry()
- if line_entry.IsValid():
- line_fragment = "at {0:s}:{1:d}".format(
- line_entry.GetFileSpec().GetFilename(), line_entry.GetLine())
- else:
- line_fragment = ""
- if use_orig_line:
+ try:
+ sym_line = symbolicate_one(frame_addr, frame_idx, dynlib_fname)
+ print(sym_line)
+ except:
print(frame["line"].rstrip())
- else:
- print("{0:s} {1:s} {2:s}".format(
- frame_fragment, symbol_fragment, line_fragment))
frame_idx = frame_idx + 1
diff --git a/validation-test/compiler_crashers_2/0074-rdar28544316.swift b/validation-test/compiler_crashers_2_fixed/0074-rdar28544316.swift
similarity index 93%
rename from validation-test/compiler_crashers_2/0074-rdar28544316.swift
rename to validation-test/compiler_crashers_2_fixed/0074-rdar28544316.swift
index f967f8d..5349cfc 100644
--- a/validation-test/compiler_crashers_2/0074-rdar28544316.swift
+++ b/validation-test/compiler_crashers_2_fixed/0074-rdar28544316.swift
@@ -1,4 +1,4 @@
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
// REQUIRES: asserts
class PropertyDataSource<O: PropertyHosting> {
diff --git a/validation-test/compiler_crashers_2_fixed/0111-rdar33067102.swift b/validation-test/compiler_crashers_2_fixed/0111-rdar33067102.swift
new file mode 100644
index 0000000..3d349e9
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0111-rdar33067102.swift
@@ -0,0 +1,5 @@
+// RUN: not %target-swift-frontend -swift-version 4 %s -typecheck
+
+func flatterMap(_ records: [(Int)]) -> [Int] {
+ records.flatMap { _ in return 1 } // expected-note {{}}
+}
diff --git a/validation-test/stdlib/Lazy.swift.gyb b/validation-test/stdlib/Lazy.swift.gyb
index 1c8f6bd..b91833b 100644
--- a/validation-test/stdlib/Lazy.swift.gyb
+++ b/validation-test/stdlib/Lazy.swift.gyb
@@ -12,7 +12,6 @@
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test
-// REQUIRES: radar_31897334
import StdlibUnittest
import StdlibCollectionUnittest
@@ -276,7 +275,10 @@
.forEach(in: [-1 ..< -1, -1..<0, -1..<1, 0..<1, 1..<1] as [Range<Int>]) {
r in
var c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
${operation}
}
@@ -296,7 +298,10 @@
]) {
(i, offset) in
let c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
_ = c.index(i, offsetBy: offset)
}
@@ -313,7 +318,10 @@
]) {
(i, offset, limit) in
let c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
_ = c.index(i, offsetBy: offset, limitedBy: limit)
}
@@ -340,7 +348,10 @@
]) {
(start, end) in
let c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
_ = c.distance(from: start, to: end)
}