Merge pull request #19392 from xedin/use-unique_ptr-for-worklist
[CSStep] Switch to use `std::unique_ptr` for work list
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index 71a8090..cf33184 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -141,7 +141,8 @@
global ::= protocol 'TL' // protocol requirements base descriptor
global ::= assoc-type-name 'Tl' // associated type descriptor
global ::= assoc-type-name 'TM' // default associated type witness accessor
-
+ global ::= type assoc-type-path protocol 'Tn' // associated conformance descriptor
+ global ::= type assoc-type-path protocol 'TN' // default associated conformance witness accessor
REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk helper function
REABSTRACT-THUNK-TYPE ::= 'r' // reabstraction thunk
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index ff0ee4a..370dcf8 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -3979,6 +3979,19 @@
/// Record the default witness for a requirement.
void setDefaultWitness(ValueDecl *requirement, Witness witness);
+ /// Returns the default associated conformance witness for an associated
+ /// type, or \c None if there is no default.
+ Optional<ProtocolConformanceRef> getDefaultAssociatedConformanceWitness(
+ CanType association,
+ ProtocolDecl *requirement) const;
+
+ /// Set the default associated conformance witness for the given
+ /// associated conformance.
+ void setDefaultAssociatedConformanceWitness(
+ CanType association,
+ ProtocolDecl *requirement,
+ ProtocolConformanceRef conformance);
+
/// Retrieve the name to use for this protocol when interoperating
/// with the Objective-C runtime.
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
diff --git a/include/swift/AST/DiagnosticsModuleDiffer.def b/include/swift/AST/DiagnosticsModuleDiffer.def
index c5b0a7d..9f216d1 100644
--- a/include/swift/AST/DiagnosticsModuleDiffer.def
+++ b/include/swift/AST/DiagnosticsModuleDiffer.def
@@ -52,6 +52,10 @@
ERROR(decl_new_attr,none,"%0 is now %1", (StringRef, StringRef))
+ERROR(decl_reorder,none,"%0 in a non-resilient type changes position from %1 to %2", (StringRef, unsigned, unsigned))
+
+ERROR(decl_added,none,"%0 is added to a non-resilient type", (StringRef))
+
#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index e8653c3..d85dd41 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -1696,6 +1696,11 @@
NOTE(witness_fix_access,none,
"mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to "
"satisfy the requirement", (DescriptiveDeclKind, AccessLevel))
+WARNING(assoc_type_default_conformance_failed,none,
+ "default type %0 for associated type %1 does not satisfy constraint "
+ "%2: %3", (Type, DeclName, Type, Type))
+NOTE(assoc_type_default_here,none,
+ "associated type %0 has default type %1 written here", (DeclName, Type))
ERROR(protocol_access,none,
"%select{protocol must be declared %select{"
diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h
index a600fdf..b2911aa 100644
--- a/include/swift/AST/LazyResolver.h
+++ b/include/swift/AST/LazyResolver.h
@@ -63,9 +63,6 @@
/// Resolve the generic environment of the given protocol.
virtual void resolveProtocolEnvironment(ProtocolDecl *proto) = 0;
- /// Bind an extension to its extended type.
- virtual void bindExtension(ExtensionDecl *ext) = 0;
-
/// Resolve the type of an extension.
///
/// This can be called to ensure that the members of an extension can be
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index cb1d6f3..ed283d6 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -211,6 +211,7 @@
NODE(MethodDescriptor)
NODE(ProtocolRequirementsBaseDescriptor)
NODE(AssociatedConformanceDescriptor)
+NODE(DefaultAssociatedConformanceAccessor)
NODE(AssociatedTypeDescriptor)
NODE(ThrowsAnnotation)
NODE(EmptyList)
diff --git a/include/swift/IDE/DigesterEnums.def b/include/swift/IDE/DigesterEnums.def
index 0092af8..f730523 100644
--- a/include/swift/IDE/DigesterEnums.def
+++ b/include/swift/IDE/DigesterEnums.def
@@ -100,6 +100,7 @@
KEY(mutating)
KEY(static)
KEY(deprecated)
+KEY(implicit)
KEY(typeAttributes)
KEY(declAttributes)
KEY(declKind)
@@ -109,6 +110,7 @@
KEY(conformingProtocols)
KEY(enumRawTypeName)
KEY(genericSig)
+KEY(fixedbinaryorder)
KNOWN_TYPE(Optional)
KNOWN_TYPE(ImplicitlyUnwrappedOptional)
diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h
index e5d486f..2e99868 100644
--- a/include/swift/IRGen/Linking.h
+++ b/include/swift/IRGen/Linking.h
@@ -213,6 +213,11 @@
/// is stored in the data.
AssociatedConformanceDescriptor,
+ /// A default accessor for an associated conformance of a protocol.
+ /// The pointer is a ProtocolDecl*; the index of the associated conformance
+ /// is stored in the data.
+ DefaultAssociatedConformanceAccessor,
+
/// A function which returns the default type metadata for the associated
/// type of a protocol. The secondary pointer is a ProtocolDecl*.
/// The index of the associated type declaration is stored in the data.
@@ -795,14 +800,13 @@
}
static LinkEntity
- forAssociatedConformanceDescriptor(ProtocolDecl *proto,
- CanType associatedType,
- ProtocolDecl *associatedProtocol) {
+ forAssociatedConformanceDescriptor(AssociatedConformance conformance) {
LinkEntity entity;
entity.setForProtocolAndAssociatedConformance(
Kind::AssociatedConformanceDescriptor,
- proto, associatedType,
- associatedProtocol);
+ conformance.getSourceProtocol(),
+ conformance.getAssociation(),
+ conformance.getAssociatedRequirement());
return entity;
}
@@ -835,6 +839,17 @@
return entity;
}
+ static LinkEntity
+ forDefaultAssociatedConformanceAccessor(AssociatedConformance conformance) {
+ LinkEntity entity;
+ entity.setForProtocolAndAssociatedConformance(
+ Kind::DefaultAssociatedConformanceAccessor,
+ conformance.getSourceProtocol(),
+ conformance.getAssociation(),
+ conformance.getAssociatedRequirement());
+ return entity;
+ }
+
static LinkEntity forReflectionBuiltinDescriptor(CanType type) {
LinkEntity entity;
entity.setForType(Kind::ReflectionBuiltinDescriptor, type);
@@ -925,7 +940,8 @@
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
}
- assert(getKind() == Kind::AssociatedConformanceDescriptor);
+ assert(getKind() == Kind::AssociatedConformanceDescriptor ||
+ getKind() == Kind::DefaultAssociatedConformanceAccessor);
return getAssociatedConformanceByIndex(
cast<ProtocolDecl>(getDecl()),
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h
index d71c0d6..35f172e 100644
--- a/include/swift/Parse/Lexer.h
+++ b/include/swift/Parse/Lexer.h
@@ -506,9 +506,10 @@
return diagnose(Loc, Diagnostic(DiagID, std::forward<ArgTypes>(Args)...));
}
- void formToken(tok Kind, const char *TokStart, bool IsMultilineString = false,
- unsigned CustomDelimiterLen = 0);
+ void formToken(tok Kind, const char *TokStart);
void formEscapedIdentifierToken(const char *TokStart);
+ void formStringLiteralToken(const char *TokStart, bool IsMultilineString,
+ unsigned CustomDelimiterLen);
/// Advance to the end of the line.
/// If EatNewLine is true, CurPtr will be at end of newline character.
diff --git a/include/swift/Parse/Token.h b/include/swift/Parse/Token.h
index 6cd0fc9..59e3e45 100644
--- a/include/swift/Parse/Token.h
+++ b/include/swift/Parse/Token.h
@@ -220,6 +220,21 @@
default: return false;
}
}
+
+ /// \brief True if the string literal token is multiline.
+ bool isMultilineString() const {
+ return MultilineString;
+ }
+ /// \brief Count of extending escaping '#'.
+ unsigned getCustomDelimiterLen() const {
+ return CustomDelimiterLen;
+ }
+ /// \brief Set characteristics of string literal token.
+ void setStringLiteral(bool IsMultilineString, unsigned CustomDelimiterLen) {
+ assert(Kind == tok::string_literal);
+ this->MultilineString = IsMultilineString;
+ this->CustomDelimiterLen = CustomDelimiterLen;
+ }
/// getLoc - Return a source location identifier for the specified
/// offset in the current file.
@@ -268,25 +283,16 @@
void setText(StringRef T) { Text = T; }
/// \brief Set the token to the specified kind and source range.
- void setToken(tok K, StringRef T, unsigned CommentLength = 0,
- bool IsMultilineString = false, unsigned CustomDelimiterLen = 0) {
+ void setToken(tok K, StringRef T, unsigned CommentLength = 0) {
Kind = K;
Text = T;
this->CommentLength = CommentLength;
EscapedIdentifier = false;
- this->MultilineString = IsMultilineString;
- this->CustomDelimiterLen = CustomDelimiterLen;
+ this->MultilineString = false;
+ this->CustomDelimiterLen = 0;
assert(this->CustomDelimiterLen == CustomDelimiterLen &&
"custom string delimiter length > 255");
}
-
- bool isMultilineString() const {
- return MultilineString;
- }
-
- unsigned getCustomDelimiterLen() const {
- return CustomDelimiterLen;
- }
};
} // end namespace swift
diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h
index 1942d5e..723bbb9 100644
--- a/include/swift/Serialization/Validation.h
+++ b/include/swift/Serialization/Validation.h
@@ -20,6 +20,7 @@
namespace swift {
+class ModuleFile;
enum class ResilienceStrategy : unsigned;
namespace serialization {
@@ -147,6 +148,24 @@
validateSerializedAST(StringRef data,
ExtendedValidationInfo *extendedInfo = nullptr);
+/// Emit diagnostics explaining a failure to load a serialized AST.
+///
+/// - \p Ctx is an AST context through which any diagnostics are surfaced.
+/// - \p diagLoc is the (possibly invalid) location used in the diagnostics.
+/// - \p loadInfo and \p extendedInfo describe the attempt to load an AST
+/// (\ref validateSerializedAST). Note that loadInfo.Status must not be
+/// Status::Valid.
+/// - \p moduleBufferID and \p moduleDocBufferID are the buffer identifiers
+/// of the module input and doc input buffers respectively (\ref
+/// SerializedModuleLoader::loadAST, \ref ModuleFile::load).
+/// - \p loadedModuleFile is an invalid loaded module.
+/// - \p ModuleName is the name used to refer to the module in diagnostics.
+void diagnoseSerializedASTLoadFailure(
+ ASTContext &Ctx, SourceLoc diagLoc, const ValidationInfo &loadInfo,
+ const ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID,
+ StringRef moduleDocBufferID, ModuleFile *loadedModuleFile,
+ Identifier ModuleName);
+
} // end namespace serialization
} // end namespace swift
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index ea0de37..b0cea9a 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -285,6 +285,11 @@
llvm::DenseMap<std::pair<const ProtocolDecl *, AssociatedTypeDecl *>, Type>
DefaultTypeWitnesses;
+ /// Default associated conformance witnesses for protocols.
+ llvm::DenseMap<std::tuple<const ProtocolDecl *, CanType, ProtocolDecl *>,
+ ProtocolConformanceRef>
+ DefaultAssociatedConformanceWitnesses;
+
/// \brief Structure that captures data that is segregated into different
/// arenas.
struct Arena {
@@ -1709,6 +1714,32 @@
(void)pair;
}
+Optional<ProtocolConformanceRef>
+ProtocolDecl::getDefaultAssociatedConformanceWitness(
+ CanType association,
+ ProtocolDecl *requirement) const {
+ auto &ctx = getASTContext();
+ auto found =
+ ctx.getImpl().DefaultAssociatedConformanceWitnesses.find(
+ std::make_tuple(this, association, requirement));
+ if (found == ctx.getImpl().DefaultAssociatedConformanceWitnesses.end())
+ return None;
+
+ return found->second;
+}
+
+void ProtocolDecl::setDefaultAssociatedConformanceWitness(
+ CanType association,
+ ProtocolDecl *requirement,
+ ProtocolConformanceRef conformance) {
+ auto &ctx = getASTContext();
+ auto pair = ctx.getImpl().DefaultAssociatedConformanceWitnesses.insert(
+ std::make_pair(std::make_tuple(this, association, requirement),
+ conformance));
+ assert(pair.second && "Already have a default associated conformance");
+ (void)pair;
+}
+
bool ASTContext::canImportModule(std::pair<Identifier, SourceLoc> ModulePath) {
// If this module has already been successfully imported, it is importable.
if (getLoadedModule(ModulePath) != nullptr)
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index 925e667..55bbda3 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -92,7 +92,11 @@
const_cast<ProtocolDecl *>(proto)->createGenericParamsIfMissing();
}
- return getGenericParamsOfContext()->getParams().front()
+ auto *genericParams = getGenericParamsOfContext();
+ if (genericParams == nullptr)
+ return nullptr;
+
+ return genericParams->getParams().front()
->getDeclaredInterfaceType()
->castTo<GenericTypeParamType>();
}
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index 1ef30d5..699a8b7 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -564,6 +564,9 @@
ASTContext &ctx = proto->getASTContext();
TinyPtrVector<NominalTypeDecl *> result;
+ if (!ext->getGenericParams())
+ return result;
+
for (const auto &req : ext->getGenericParams()->getTrailingRequirements()) {
// We only care about type constraints.
if (req.getKind() != RequirementReprKind::TypeConstraint)
@@ -709,6 +712,7 @@
};
if (Loc.isValid() &&
+ DC->getParentSourceFile() &&
DC->getParentSourceFile()->Kind != SourceFileKind::REPL &&
Ctx.LangOpts.EnableASTScopeLookup) {
// Find the source file in which we are performing the lookup.
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index a41f978..9048834 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -1841,6 +1841,15 @@
protoTy, assocTypePath, requirementTy);
}
+ case 'N': {
+ NodePointer requirementTy = popProtocol();
+ auto assocTypePath = popAssocTypePath();
+ NodePointer protoTy = popNode(Node::Kind::Type);
+ return createWithChildren(
+ Node::Kind::DefaultAssociatedConformanceAccessor,
+ protoTy, assocTypePath, requirementTy);
+ }
+
case 'H':
case 'h': {
auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 50e451b..363d552 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -323,6 +323,7 @@
case Node::Kind::DeclContext:
case Node::Kind::DefaultArgumentInitializer:
case Node::Kind::DefaultAssociatedTypeMetadataAccessor:
+ case Node::Kind::DefaultAssociatedConformanceAccessor:
case Node::Kind::DependentAssociatedTypeRef:
case Node::Kind::DependentGenericSignature:
case Node::Kind::DependentGenericParamCount:
@@ -1564,6 +1565,14 @@
Printer << ": ";
print(Node->getChild(2));
return nullptr;
+ case Node::Kind::DefaultAssociatedConformanceAccessor:
+ Printer << "default associated conformance accessor for ";
+ print(Node->getChild(0));
+ Printer << ".";
+ print(Node->getChild(1));
+ Printer << ": ";
+ print(Node->getChild(2));
+ return nullptr;
case Node::Kind::AssociatedTypeDescriptor:
Printer << "associated type descriptor for ";
print(Node->getChild(0));
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index 2549d1a..e4f08ee 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -888,6 +888,10 @@
Out << "<associated-conformance-descriptor>";
}
+void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) {
+ Out << "<default-associated-conformance-descriptor>";
+}
+
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
Out << "Wt";
mangleChildNodes(node); // protocol conformance, identifier
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index f7ffe88..348b288 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -579,6 +579,11 @@
Buffer << "Tn";
}
+void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) {
+ mangleChildNodes(node);
+ Buffer << "TN";
+}
+
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
mangleChildNodes(node); // protocol conformance, identifier
Buffer << "Wt";
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index ec487ba..23048cd 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -517,7 +517,9 @@
}
FrontendStatsTracer tracer(Context->Stats, "perform-sema");
- Context->LoadedModules[MainModule->getName()] = getMainModule();
+
+ ModuleDecl *mainModule = getMainModule();
+ Context->LoadedModules[mainModule->getName()] = mainModule;
if (Invocation.getInputKind() == InputFileKind::SIL) {
assert(!InputSourceCodeBufferIDs.empty());
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index d48d029..0cc89af 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -3389,21 +3389,15 @@
llvm::Constant *IRGenModule::getAddrOfAssociatedConformanceDescriptor(
AssociatedConformance conformance) {
- auto entity = LinkEntity::forAssociatedConformanceDescriptor(
- conformance.getSourceProtocol(),
- conformance.getAssociation(),
- conformance.getAssociatedRequirement());
+ auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
ProtocolRequirementStructTy, DebugTypeInfo());
}
llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor(
- ProtocolDecl *proto,
- CanType subject,
- ProtocolDecl *requirement,
- llvm::Constant *definition) {
- auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
- requirement);
+ AssociatedConformance conformance,
+ llvm::Constant *definition) {
+ auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
return defineAlias(entity, definition);
}
@@ -3989,6 +3983,25 @@
}
llvm::Function *
+IRGenModule::getAddrOfDefaultAssociatedConformanceAccessor(
+ AssociatedConformance requirement) {
+ auto forDefinition = ForDefinition;
+
+ LinkEntity entity =
+ LinkEntity::forDefaultAssociatedConformanceAccessor(requirement);
+ llvm::Function *&entry = GlobalFuncs[entity];
+ if (entry) {
+ if (forDefinition) updateLinkageForDefinition(*this, entry, entity);
+ return entry;
+ }
+
+ auto signature = getAssociatedTypeWitnessTableAccessFunctionSignature();
+ LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
+ entry = createFunction(*this, link, signature);
+ return entry;
+}
+
+llvm::Function *
IRGenModule::getAddrOfContinuationPrototype(CanSILFunctionType fnType) {
LinkEntity entity = LinkEntity::forCoroutineContinuationPrototype(fnType);
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index f0198cf..a75abe0 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -647,7 +647,14 @@
if (entry.isAssociatedConformance()) {
auto flags = Flags(Flags::Kind::AssociatedConformanceAccessFunction);
- return { flags, nullptr };
+
+ // Look for a default witness.
+ llvm::Constant *defaultImpl =
+ findDefaultAssociatedConformanceWitness(
+ entry.getAssociatedConformancePath(),
+ entry.getAssociatedConformanceRequirement());
+
+ return { flags, defaultImpl };
}
assert(entry.isFunction());
@@ -712,10 +719,12 @@
if (entry.isAssociatedConformance()) {
// Define the associated conformance descriptor to point to the
// current position in the protocol descriptor.
+ AssociatedConformance conformance(
+ Proto,
+ entry.getAssociatedConformancePath(),
+ entry.getAssociatedConformanceRequirement());
IGM.defineAssociatedConformanceDescriptor(
- Proto,
- entry.getAssociatedConformancePath(),
- entry.getAssociatedConformanceRequirement(),
+ conformance,
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
}
@@ -800,6 +809,89 @@
IGF.Builder.CreateRet(returnValue);
return accessor;
}
+
+ llvm::Constant *findDefaultAssociatedConformanceWitness(
+ CanType association,
+ ProtocolDecl *requirement) {
+ if (!DefaultWitnesses) return nullptr;
+
+ for (auto &entry : DefaultWitnesses->getEntries()) {
+ if (!entry.isValid() ||
+ entry.getKind() != SILWitnessTable::AssociatedTypeProtocol ||
+ entry.getAssociatedTypeProtocolWitness().Protocol != requirement ||
+ entry.getAssociatedTypeProtocolWitness().Requirement != association)
+ continue;
+
+ auto witness = entry.getAssociatedTypeProtocolWitness().Witness;
+ return getDefaultAssociatedConformanceAccessFunction(
+ AssociatedConformance(Proto, association, requirement),
+ witness);
+ }
+
+ return nullptr;
+ }
+
+ llvm::Constant *getDefaultAssociatedConformanceAccessFunction(
+ AssociatedConformance requirement,
+ ProtocolConformanceRef conformance) {
+ auto accessor =
+ IGM.getAddrOfDefaultAssociatedConformanceAccessor(requirement);
+
+ IRGenFunction IGF(IGM, accessor);
+ if (IGM.DebugInfo)
+ IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
+
+ Explosion parameters = IGF.collectParameters();
+
+ llvm::Value *associatedTypeMetadata = parameters.claimNext();
+ llvm::Value *self = parameters.claimNext();
+ llvm::Value *wtable = parameters.claimNext();
+
+ bool hasArchetype =
+ !conformance.isConcrete() ||
+ conformance.getConcrete()->getType()->hasArchetype();
+ if (hasArchetype) {
+ // Bind local Self type data from the metadata argument.
+ CanType selfInContext =
+ Proto->mapTypeIntoContext(Proto->getProtocolSelfType())
+ ->getCanonicalType();
+ IGF.bindLocalTypeDataFromTypeMetadata(selfInContext, IsExact, self,
+ MetadataState::Abstract);
+ IGF.setUnscopedLocalTypeData(
+ selfInContext,
+ LocalTypeDataKind::forAbstractProtocolWitnessTable(Proto),
+ wtable);
+
+ // Bind the associated type metadata.
+ IGF.bindLocalTypeDataFromTypeMetadata(requirement.getAssociation(),
+ IsExact,
+ associatedTypeMetadata,
+ MetadataState::Abstract);
+ }
+
+ // For a concrete witness table, call it.
+ ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement();
+ if (conformance.isConcrete()) {
+ auto conformanceI = &IGM.getConformanceInfo(associatedProtocol,
+ conformance.getConcrete());
+ auto returnValue = conformanceI->getTable(IGF, &associatedTypeMetadata);
+ IGF.Builder.CreateRet(returnValue);
+ return accessor;
+ }
+
+ // For an abstract table, emit a reference to the witness table.
+ CanType associatedTypeInContext
+ = Proto->mapTypeIntoContext(requirement.getAssociation())
+ ->getCanonicalType();
+ auto returnValue =
+ emitArchetypeWitnessTableRef(
+ IGF,
+ cast<ArchetypeType>(associatedTypeInContext),
+ associatedProtocol);
+ IGF.Builder.CreateRet(returnValue);
+ return accessor;
+ }
+
void addAssociatedTypeNames() {
std::string AssociatedTypeNames;
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 0cf4f02..a04e8ae 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -1385,6 +1385,13 @@
void addAssociatedConformance(AssociatedConformance requirement) {
// FIXME: Add static witness tables for type conformances.
+ auto &entry = SILEntries.front();
+ (void)entry;
+ SILEntries = SILEntries.slice(1);
+
+ if (ResilientConformance)
+ return;
+
auto associate =
ConformanceInContext.getAssociatedType(
requirement.getAssociation())->getCanonicalType();
@@ -1394,9 +1401,8 @@
requirement.getAssociation(),
requirement.getAssociatedRequirement());
+
#ifndef NDEBUG
- auto &entry = SILEntries.front();
- (void)entry;
assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol
&& "sil witness table does not match protocol");
auto associatedWitness = entry.getAssociatedTypeProtocolWitness();
@@ -1411,8 +1417,6 @@
"offset doesn't match ProtocolInfo layout");
#endif
- SILEntries = SILEntries.slice(1);
-
llvm::Constant *wtableAccessFunction =
getAssociatedTypeWitnessTableAccessFunction(requirement,
associate,
@@ -1644,7 +1648,8 @@
getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement,
CanType associatedType,
ProtocolConformanceRef associatedConformance) {
- if (!associatedType->hasArchetype()) {
+ bool hasArchetype = associatedType->hasArchetype();
+ if (!hasArchetype && !ResilientConformance) {
assert(associatedConformance.isConcrete() &&
"no concrete conformance for non-dependent type");
return getOrCreateWitnessTableAccessFunction(IGM,
@@ -1682,13 +1687,6 @@
Address destTable(parameters.claimNext(), IGM.getPointerAlignment());
setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType,
Conformance.getProtocol());
- IGF.bindLocalTypeDataFromSelfWitnessTable(
- &Conformance,
- destTable.getAddress(),
- [&](CanType type) {
- return Conformance.getDeclContext()->mapTypeIntoContext(type)
- ->getCanonicalType();
- });
ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement();
@@ -1710,6 +1708,24 @@
}
}
+ // If there are no archetypes, return a reference to the table. There is
+ // no need for a cache.
+ if (!hasArchetype) {
+ auto wtable = MetadataResponse::forComplete(
+ conformanceI->getTable(IGF, &associatedTypeMetadata))
+ .getMetadata();
+ IGF.Builder.CreateRet(wtable);
+ return accessor;
+ }
+
+ IGF.bindLocalTypeDataFromSelfWitnessTable(
+ &Conformance,
+ destTable.getAddress(),
+ [&](CanType type) {
+ return Conformance.getDeclContext()->mapTypeIntoContext(type)
+ ->getCanonicalType();
+ });
+
// If the witness table is directly fulfillable from the type,
// we don't need a cache entry.
// TODO: maybe we should have a cache entry anyway if the fulfillment
@@ -1869,7 +1885,8 @@
unsigned count = 0;
for (auto &entry : SILWT->getEntries()) {
if (entry.getKind() != SILWitnessTable::Method &&
- entry.getKind() != SILWitnessTable::AssociatedType)
+ entry.getKind() != SILWitnessTable::AssociatedType &&
+ entry.getKind() != SILWitnessTable::AssociatedTypeProtocol)
continue;
count++;
@@ -1907,6 +1924,36 @@
continue;
}
+ // Associated conformance access function.
+ if (entry.getKind() == SILWitnessTable::AssociatedTypeProtocol) {
+ const auto &witness = entry.getAssociatedTypeProtocolWitness();
+
+ // Associated type descriptor.
+ AssociatedConformance requirement(SILWT->getConformance()->getProtocol(),
+ witness.Requirement,
+ witness.Protocol);
+ auto assocConformanceDescriptor =
+ IGM.getAddrOfLLVMVariableOrGOTEquivalent(
+ LinkEntity::forAssociatedConformanceDescriptor(requirement),
+ Alignment(4), IGM.ProtocolRequirementStructTy);
+ table.addRelativeAddress(assocConformanceDescriptor);
+
+ auto associate =
+ ConformanceInContext.getAssociatedType(
+ witness.Requirement)->getCanonicalType();
+
+ ProtocolConformanceRef associatedConformance =
+ ConformanceInContext.getAssociatedConformance(witness.Requirement,
+ witness.Protocol);
+
+ llvm::Constant *wtableAccessFunction =
+ getAssociatedTypeWitnessTableAccessFunction(requirement,
+ associate,
+ associatedConformance);
+ table.addRelativeAddress(wtableAccessFunction);
+ continue;
+ }
+
if (entry.getKind() != SILWitnessTable::Method)
continue;
diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h
index edd7713..37c5b95 100644
--- a/lib/IRGen/IRGenMangler.h
+++ b/lib/IRGen/IRGenMangler.h
@@ -197,6 +197,19 @@
return finalize();
}
+ std::string mangleDefaultAssociatedConformanceAccessor(
+ const ProtocolDecl *proto,
+ CanType subject,
+ const ProtocolDecl *requirement) {
+ beginMangling();
+ appendAnyGenericType(proto);
+ bool isFirstAssociatedTypeIdentifier = true;
+ appendAssociatedTypePath(subject, isFirstAssociatedTypeIdentifier);
+ appendProtocolName(requirement);
+ appendOperator("TN");
+ return finalize();
+ }
+
std::string mangleProtocolConformanceDescriptor(
const ProtocolConformance *Conformance) {
beginMangling();
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index fb33001..0c98b82 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -1237,10 +1237,8 @@
llvm::Constant *getAddrOfAssociatedConformanceDescriptor(
AssociatedConformance conformance);
llvm::GlobalValue *defineAssociatedConformanceDescriptor(
- ProtocolDecl *proto,
- CanType subject,
- ProtocolDecl *requirement,
- llvm::Constant *definition);
+ AssociatedConformance conformance,
+ llvm::Constant *definition);
llvm::Constant *getAddrOfProtocolDescriptor(ProtocolDecl *D,
ConstantInit definition = ConstantInit());
@@ -1293,6 +1291,8 @@
const AssociatedConformance &association);
llvm::Function *getAddrOfDefaultAssociatedTypeMetadataAccessFunction(
AssociatedType association);
+ llvm::Function *getAddrOfDefaultAssociatedConformanceAccessor(
+ AssociatedConformance requirement);
Address getAddrOfObjCISAMask();
diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp
index 6562b50..b24a247 100644
--- a/lib/IRGen/Linking.cpp
+++ b/lib/IRGen/Linking.cpp
@@ -187,6 +187,14 @@
assocConformance.second);
}
+ case Kind::DefaultAssociatedConformanceAccessor: {
+ auto assocConformance = getAssociatedConformance();
+ return mangler.mangleDefaultAssociatedConformanceAccessor(
+ cast<ProtocolDecl>(getDecl()),
+ assocConformance.first,
+ assocConformance.second);
+ }
+
case Kind::ProtocolConformanceDescriptor:
return mangler.mangleProtocolConformanceDescriptor(
cast<NormalProtocolConformance>(getProtocolConformance()));
@@ -498,6 +506,7 @@
case Kind::AssociatedTypeMetadataAccessFunction:
case Kind::DefaultAssociatedTypeMetadataAccessFunction:
case Kind::AssociatedTypeWitnessTableAccessFunction:
+ case Kind::DefaultAssociatedConformanceAccessor:
case Kind::GenericProtocolWitnessTableCache:
case Kind::GenericProtocolWitnessTableInstantiationFunction:
return SILLinkage::Private;
@@ -629,6 +638,7 @@
case Kind::TypeMetadataCompletionFunction:
case Kind::TypeMetadataPattern:
case Kind::DefaultAssociatedTypeMetadataAccessFunction:
+ case Kind::DefaultAssociatedConformanceAccessor:
return false;
case Kind::ValueWitness:
diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp
index 9192819..b614aa0 100644
--- a/lib/Parse/Lexer.cpp
+++ b/lib/Parse/Lexer.cpp
@@ -272,8 +272,7 @@
return Result;
}
-void Lexer::formToken(tok Kind, const char *TokStart,
- bool IsMultilineString, unsigned CustomDelimiterLen) {
+void Lexer::formToken(tok Kind, const char *TokStart) {
assert(CurPtr >= BufferStart &&
CurPtr <= BufferEnd && "Current pointer out of range!");
@@ -305,8 +304,7 @@
lexTrivia(TrailingTrivia, /* IsForTrailingTrivia */ true);
}
- NextToken.setToken(Kind, TokenText, CommentLength,
- IsMultilineString, CustomDelimiterLen);
+ NextToken.setToken(Kind, TokenText, CommentLength);
}
void Lexer::formEscapedIdentifierToken(const char *TokStart) {
@@ -326,6 +324,20 @@
NextToken.setEscapedIdentifier(true);
}
+static void validateMultilineIndents(const Token &Str, DiagnosticEngine *Diags);
+
+void Lexer::formStringLiteralToken(const char *TokStart,
+ bool IsMultilineString,
+ unsigned CustomDelimiterLen) {
+ formToken(tok::string_literal, TokStart);
+ if (NextToken.is(tok::eof))
+ return;
+ NextToken.setStringLiteral(IsMultilineString, CustomDelimiterLen);
+
+ if (IsMultilineString && Diags)
+ validateMultilineIndents(NextToken, Diags);
+}
+
Lexer::State Lexer::getStateForBeginningOfTokenLoc(SourceLoc Loc) const {
const char *Ptr = getBufferPtrForSourceLoc(Loc);
// Skip whitespace backwards until we hit a newline. This is needed to
@@ -1238,9 +1250,11 @@
/// advanceIfCustomDelimiter - Extracts/detects any custom delimiter on
/// opening a string literal, advances CurPtr if a delimiter is found and
-/// returns a non-zero delimiter length. CurPtr[-1] generally '#' when called.
+/// returns a non-zero delimiter length. CurPtr[-1] must be '#' when called.
static unsigned advanceIfCustomDelimiter(const char *&CurPtr,
DiagnosticEngine *Diags) {
+ assert(CurPtr[-1] == '#');
+
const char *TmpPtr = CurPtr;
unsigned CustomDelimiterLen = 1;
while (diagnoseZeroWidthMatchAndAdvance('#', TmpPtr, Diags))
@@ -1263,24 +1277,28 @@
if (!CustomDelimiterLen)
return true;
const char *TmpPtr = BytesPtr;
- while (CustomDelimiterLen--)
- if (!diagnoseZeroWidthMatchAndAdvance('#', TmpPtr, Diags))
- return false;
- BytesPtr = TmpPtr;
- if (*BytesPtr == '#' && Diags)
- Diags->diagnose(Lexer::getSourceLoc(BytesPtr), IsClosing ?
- diag::lex_invalid_closing_delimiter :
- diag::lex_invalid_escape_delimiter)
- .fixItRemoveChars(Lexer::getSourceLoc(BytesPtr),
- Lexer::getSourceLoc(BytesPtr + 1));
+ while (diagnoseZeroWidthMatchAndAdvance('#', TmpPtr, Diags)) {}
+
+ if (TmpPtr - BytesPtr < CustomDelimiterLen)
+ return false;
+
+ BytesPtr += CustomDelimiterLen;
+
+ if (Diags && TmpPtr > BytesPtr) {
+ Diag<> message = IsClosing ? diag::lex_invalid_closing_delimiter
+ : diag::lex_invalid_escape_delimiter;
+ Diags->diagnose(Lexer::getSourceLoc(BytesPtr), message)
+ .fixItRemoveChars(Lexer::getSourceLoc(BytesPtr),
+ Lexer::getSourceLoc(TmpPtr));
+ }
return true;
}
/// lexCharacter - Read a character and return its UTF32 code. If this is the
/// end of enclosing string/character sequence (i.e. the character is equal to
-/// 'StopQuote'), this returns ~0U and leaves 'CurPtr' pointing to the terminal
-/// quote. If this is a malformed character sequence, it emits a diagnostic
-/// (when EmitDiagnostics is true) and returns ~1U.
+/// 'StopQuote'), this returns ~0U and advances 'CurPtr' pointing to the end of
+/// terminal quote. If this is a malformed character sequence, it emits a
+/// diagnostic (when EmitDiagnostics is true) and returns ~1U.
///
/// character_escape ::= [\][\] | [\]t | [\]n | [\]r | [\]" | [\]' | [\]0
/// character_escape ::= unicode_character_escape
@@ -1291,6 +1309,7 @@
switch (*CurPtr++) {
default: {// Normal characters are part of the string.
+ // Normal characters are part of the string.
// If this is a "high" UTF-8 character, validate it.
if ((signed char)(CurPtr[-1]) >= 0) {
if (isPrintable(CurPtr[-1]) == 0)
@@ -1308,32 +1327,35 @@
}
case '"':
case '\'':
- // If we found a closing quote character, we're done.
if (CurPtr[-1] == StopQuote) {
- --CurPtr;
+ // Mutliline and custom escaping are only enabled for " quote.
+ if (LLVM_UNLIKELY(StopQuote != '"'))
+ return ~0U;
+ if (!IsMultilineString && !CustomDelimiterLen)
+ return ~0U;
+
+ DiagnosticEngine *D = EmitDiagnostics ? Diags : nullptr;
+ auto TmpPtr = CurPtr;
+ if (IsMultilineString && !advanceIfMultilineDelimiter(TmpPtr, D))
+ return '"';
+ if (CustomDelimiterLen &&
+ !delimiterMatches(CustomDelimiterLen, TmpPtr, D, /*IsClosing=*/true))
+ return '"';
+ CurPtr = TmpPtr;
return ~0U;
}
// Otherwise, this is just a character.
return CurPtr[-1];
-
+
case 0:
- if (CurPtr-1 != BufferEnd) {
- if (EmitDiagnostics)
- diagnose(CurPtr-1, diag::lex_nul_character);
- return CurPtr[-1];
- }
- // Move the pointer back to EOF.
- --CurPtr;
+ assert(CurPtr - 1 != BufferEnd && "Caller must handle EOF");
if (EmitDiagnostics)
- diagnose(CurPtr-1, diag::lex_unterminated_string);
- return ~1U;
+ diagnose(CurPtr-1, diag::lex_nul_character);
+ return CurPtr[-1];
case '\n': // String literals cannot have \n or \r in them.
case '\r':
- if (IsMultilineString) // ... unless they are multiline
- return CurPtr[-1];
- if (EmitDiagnostics)
- diagnose(CurPtr-1, diag::lex_unterminated_string);
- return ~1U;
+ assert(IsMultilineString && "Caller must handle newlines in non-multiline");
+ return CurPtr[-1];
case '\\': // Escapes.
if (!delimiterMatches(CustomDelimiterLen, CurPtr,
EmitDiagnostics ? Diags : nullptr))
@@ -1402,7 +1424,6 @@
/// outstanding delimiters as it scans the string.
static const char *skipToEndOfInterpolatedExpression(const char *CurPtr,
const char *EndPtr,
- DiagnosticEngine *Diags,
bool IsMultilineString) {
SmallVector<char, 4> OpenDelimiters;
SmallVector<bool, 4> AllowNewline;
@@ -1432,81 +1453,71 @@
continue;
// Will be diagnosed as an unterminated string literal.
return CurPtr-1;
+ case 0:
+ if (CurPtr-1 != EndPtr)
+ continue; // CC token or random NUL character.
+ // Will be diagnosed as an unterminated string literal.
+ return CurPtr-1;
case '#':
if (inStringLiteral() ||
- !(CustomDelimiterLen = advanceIfCustomDelimiter(CurPtr, Diags)))
+ !(CustomDelimiterLen = advanceIfCustomDelimiter(CurPtr, nullptr)))
continue;
+ assert(CurPtr[-1] == '"' &&
+ "advanceIfCustomDelimiter() must stop at after the quote");
LLVM_FALLTHROUGH;
case '"':
case '\'': {
- if (!AllowNewline.back() && inStringLiteral()) {
- if (OpenDelimiters.back() == CurPtr[-1] &&
- delimiterMatches(CustomDelimiter.back(), CurPtr, Diags, true)) {
- // Closing single line string literal.
- OpenDelimiters.pop_back();
- AllowNewline.pop_back();
- CustomDelimiter.pop_back();
- }
- // Otherwise, it's just a quote in string literal. e.g. "foo's".
- continue;
- }
-
- bool isMultilineQuote = advanceIfMultilineDelimiter(CurPtr, Diags);
-
if (!inStringLiteral()) {
- // Open string literal
+ // Open string literal.
OpenDelimiters.push_back(CurPtr[-1]);
- AllowNewline.push_back(isMultilineQuote);
+ AllowNewline.push_back(advanceIfMultilineDelimiter(CurPtr, nullptr));
CustomDelimiter.push_back(CustomDelimiterLen);
continue;
}
- // We are in multiline string literal.
- assert(AllowNewline.back() && "other cases must be handled above");
- if (isMultilineQuote &&
- delimiterMatches(CustomDelimiter.back(), CurPtr, Diags, true)) {
- // Close multiline string literal.
- OpenDelimiters.pop_back();
- AllowNewline.pop_back();
- CustomDelimiter.pop_back();
- }
+ // In string literal.
- // Otherwise, it's just a normal character in multiline string.
+ // Skip if it's an another kind of quote in string literal. e.g. "foo's".
+ if (OpenDelimiters.back() != CurPtr[-1])
+ continue;
+
+ // Multi-line string can only be closed by '"""'.
+ if (AllowNewline.back() && !advanceIfMultilineDelimiter(CurPtr, nullptr))
+ continue;
+
+ // Check whether we have equivalent number of '#'s.
+ if (!delimiterMatches(CustomDelimiter.back(), CurPtr, nullptr, true))
+ continue;
+
+ // Close string literal.
+ OpenDelimiters.pop_back();
+ AllowNewline.pop_back();
+ CustomDelimiter.pop_back();
continue;
}
case '\\':
+ // We ignore invalid escape sequence here. They should be diagnosed in
+ // the real lexer functions.
if (inStringLiteral() &&
- delimiterMatches(CustomDelimiter.back(), CurPtr, Diags)) {
- char escapedChar = *CurPtr++;
- switch (escapedChar) {
+ delimiterMatches(CustomDelimiter.back(), CurPtr, nullptr)) {
+ switch (*CurPtr++) {
case '(':
// Entering a recursive interpolated expression
OpenDelimiters.push_back('(');
continue;
- case '\n': case '\r':
- if (AllowNewline.back())
- continue;
- LLVM_FALLTHROUGH;
- case 0:
- // Don't jump over newline/EOF due to preceding backslash!
- return CurPtr-1;
+ case '\n': case '\r': case 0:
+ // Don't jump over newline/EOF due to preceding backslash.
+ // Let the outer switch to handle it.
+ --CurPtr;
+ continue;
default:
continue;
}
}
continue;
- case 0:
- // If we hit EOF, we fail.
- if (CurPtr-1 == EndPtr) {
- if (Diags)
- Diags->diagnose(Lexer::getSourceLoc(CurPtr-1),
- diag::lex_unterminated_string);
- return CurPtr-1;
- }
- continue;
-
+
// Paren nesting deeper to support "foo = \((a+b)-(c*d)) bar".
case '(':
if (!inStringLiteral()) {
@@ -1730,111 +1741,117 @@
commonIndentation);
}
+/// Emit diagnostics for single-quote string and suggest replacement
+/// with double-quoted equivalent.
+static void diagnoseSingleQuoteStringLiteral(const char *TokStart,
+ const char *TokEnd,
+ DiagnosticEngine *D) {
+ assert(*TokStart == '\'' && TokEnd[-1] == '\'');
+ if (!D)
+ return;
+
+ SmallString<32> replacement;
+ replacement.push_back('"');
+ const char *Ptr = TokStart + 1;
+ const char *OutputPtr = Ptr;
+
+ while (*Ptr++ != '\'' && Ptr < TokEnd) {
+ if (Ptr[-1] == '\\') {
+ if (*Ptr == '\'') {
+ replacement.append(OutputPtr, Ptr - 1);
+ OutputPtr = Ptr + 1;
+ // Un-escape single quotes.
+ replacement.push_back('\'');
+ } else if (*Ptr == '(') {
+ // Preserve the contents of interpolation.
+ Ptr = skipToEndOfInterpolatedExpression(Ptr + 1, replacement.end(),
+ /*IsMultiline=*/false);
+ assert(*Ptr == ')');
+ }
+ // Skip over escaped characters.
+ ++Ptr;
+ } else if (Ptr[-1] == '"') {
+ replacement.append(OutputPtr, Ptr - 1);
+ OutputPtr = Ptr;
+ // Escape double quotes.
+ replacement.append("\\\"");
+ }
+ }
+ assert(Ptr == TokEnd && Ptr[-1] == '\'');
+ replacement.append(OutputPtr, Ptr - 1);
+ replacement.push_back('"');
+
+ D->diagnose(Lexer::getSourceLoc(TokStart), diag::lex_single_quote_string)
+ .fixItReplaceChars(Lexer::getSourceLoc(TokStart),
+ Lexer::getSourceLoc(TokEnd), replacement);
+}
+
/// lexStringLiteral:
/// string_literal ::= ["]([^"\\\n\r]|character_escape)*["]
/// string_literal ::= ["]["]["].*["]["]["] - approximately
/// string_literal ::= (#+)("")?".*"(\2\1) - "raw" strings
void Lexer::lexStringLiteral(unsigned CustomDelimiterLen) {
- const char *TokStart = CurPtr-1;
- assert((*TokStart == '"' || *TokStart == '\'') && "Unexpected start");
+ const char QuoteChar = CurPtr[-1];
+ const char *TokStart = CurPtr - 1 - CustomDelimiterLen;
+
// NOTE: We only allow single-quote string literals so we can emit useful
// diagnostics about changing them to double quotes.
+ assert((QuoteChar == '"' || QuoteChar == '\'') && "Unexpected start");
- bool wasErroneous = false, IsMultilineString = false;
-
- // Is this the start of a multiline string literal?
- if ((IsMultilineString = advanceIfMultilineDelimiter(CurPtr, Diags))) {
- if (*CurPtr != '\n' && *CurPtr != '\r')
- diagnose(CurPtr, diag::lex_illegal_multiline_string_start)
+ bool IsMultilineString = advanceIfMultilineDelimiter(CurPtr, Diags);
+ if (IsMultilineString && *CurPtr != '\n' && *CurPtr != '\r')
+ diagnose(CurPtr, diag::lex_illegal_multiline_string_start)
.fixItInsert(Lexer::getSourceLoc(CurPtr), "\n");
- }
+ bool wasErroneous = false;
while (true) {
+ // Handle string interpolation.
const char *TmpPtr = CurPtr + 1;
- if (*CurPtr == '\\' && delimiterMatches(CustomDelimiterLen, TmpPtr, nullptr)
- && *TmpPtr == '(') {
+ if (*CurPtr == '\\' &&
+ delimiterMatches(CustomDelimiterLen, TmpPtr, nullptr) &&
+ *TmpPtr++ == '(') {
// Consume tokens until we hit the corresponding ')'.
- CurPtr = TmpPtr + 1;
- const char *EndPtr =
- skipToEndOfInterpolatedExpression(CurPtr, BufferEnd,
- Diags, IsMultilineString);
-
- if (*EndPtr == ')') {
+ CurPtr = skipToEndOfInterpolatedExpression(TmpPtr, BufferEnd,
+ IsMultilineString);
+ if (*CurPtr == ')') {
// Successfully scanned the body of the expression literal.
- CurPtr = EndPtr+1;
- } else {
- CurPtr = EndPtr;
- wasErroneous = true;
+ ++CurPtr;
+ continue;
}
- continue;
+
+ // Being diagnosed below.
+ assert((*CurPtr == '\r' || *CurPtr == '\n' || CurPtr == BufferEnd) &&
+ "Returned at unexpected position");
}
// String literals cannot have \n or \r in them (unless multiline).
if (((*CurPtr == '\r' || *CurPtr == '\n') && !IsMultilineString)
|| CurPtr == BufferEnd) {
- TokStart -= CustomDelimiterLen;
diagnose(TokStart, diag::lex_unterminated_string);
return formToken(tok::unknown, TokStart);
}
- unsigned CharValue = lexCharacter(CurPtr, *TokStart, true,
+ unsigned CharValue = lexCharacter(CurPtr, QuoteChar, true,
IsMultilineString, CustomDelimiterLen);
+ // This is the end of string, we are done.
+ if (CharValue == ~0U)
+ break;
+
+ // Remember we had already-diagnosed invalid characters.
wasErroneous |= CharValue == ~1U;
-
- // If this is the end of string, we are done. If it is a normal character
- // or an already-diagnosed error, just munch it.
- if (CharValue == ~0U) {
- ++CurPtr;
-
- if (*TokStart == '\'') {
- // Complain about single-quote string and suggest replacement with
- // double-quoted equivalent.
- StringRef orig(TokStart, CurPtr - TokStart);
- llvm::SmallString<32> replacement;
- replacement += '"';
- std::string str = orig.slice(1, orig.size() - 1).str();
- std::string quot = "\"";
- size_t pos = 0;
- while (pos != str.length()) {
- if (str.at(pos) == '\\') {
- if (str.at(pos + 1) == '\'') {
- // Un-escape escaped single quotes.
- str.replace(pos, 2, "'");
- ++pos;
- } else {
- // Skip over escaped characters.
- pos += 2;
- }
- } else if (str.at(pos) == '"') {
- str.replace(pos, 1, "\\\"");
- // Advance past the newly added ["\""].
- pos += 2;
- } else {
- ++pos;
- }
- }
- replacement += StringRef(str);
- replacement += '"';
- diagnose(TokStart, diag::lex_single_quote_string)
- .fixItReplaceChars(getSourceLoc(TokStart), getSourceLoc(CurPtr),
- replacement);
- }
-
- // Is this the end of multiline/custom-delimited string literal?
- if ((!IsMultilineString || advanceIfMultilineDelimiter(CurPtr, Diags)) &&
- delimiterMatches(CustomDelimiterLen, CurPtr, Diags, true)) {
- TokStart -= CustomDelimiterLen;
- if (wasErroneous)
- return formToken(tok::unknown, TokStart);
-
- formToken(tok::string_literal, TokStart,
- IsMultilineString, CustomDelimiterLen);
- if (IsMultilineString && Diags)
- validateMultilineIndents(NextToken, Diags);
- return;
- }
- }
}
+
+ if (QuoteChar == '\'') {
+ assert(!IsMultilineString && CustomDelimiterLen == 0 &&
+ "Single quoted string cannot have custom delimitor, nor multiline");
+ diagnoseSingleQuoteStringLiteral(TokStart, CurPtr, Diags);
+ }
+
+ if (wasErroneous)
+ return formToken(tok::unknown, TokStart);
+
+ return formStringLiteralToken(TokStart, IsMultilineString,
+ CustomDelimiterLen);
}
@@ -2232,9 +2249,8 @@
IsFirstSegment = false;
// Find the closing ')'.
- const char *End = skipToEndOfInterpolatedExpression(BytesPtr,
- Str.getText().end(),
- Diags, MultilineString);
+ const char *End = skipToEndOfInterpolatedExpression(
+ BytesPtr, Str.getText().end(), MultilineString);
assert(*End == ')' && "invalid string literal interpolations should"
" not be returned as string literals");
++End;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index e0fd920..95521e0 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -240,8 +240,8 @@
StringRef Text = SM.extractText({ Loc, Len });
Token NewTok;
- NewTok.setToken(tok::string_literal, Text,
- IsMultiline, CustomDelimiterLen);
+ NewTok.setToken(tok::string_literal, Text);
+ NewTok.setStringLiteral(IsMultiline, CustomDelimiterLen);
Toks.push_back(NewTok);
} else {
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index e655e14..75d0bc7 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -181,7 +181,8 @@
ProtocolConformance *
parseProtocolConformanceHelper(ProtocolDecl *&proto,
GenericEnvironment *GenericEnv,
- bool localScope);
+ bool localScope,
+ ProtocolDecl *defaultForProto);
public:
SILParser(Parser &P)
: P(P), SILMod(static_cast<SILParserTUState *>(P.SIL)->M),
@@ -391,15 +392,18 @@
bool isStartOfSILInstruction();
bool parseSubstitutions(SmallVectorImpl<ParsedSubstitution> &parsed,
- GenericEnvironment *GenericEnv=nullptr);
+ GenericEnvironment *GenericEnv=nullptr,
+ ProtocolDecl *defaultForProto = nullptr);
ProtocolConformance *parseProtocolConformance(ProtocolDecl *&proto,
GenericEnvironment *&genericEnv,
- bool localScope);
- ProtocolConformance *parseProtocolConformance() {
+ bool localScope,
+ ProtocolDecl *defaultForProto);
+ ProtocolConformance *parseProtocolConformance(
+ ProtocolDecl *defaultForProto) {
ProtocolDecl *dummy;
GenericEnvironment *env;
- return parseProtocolConformance(dummy, env, true);
+ return parseProtocolConformance(dummy, env, true, defaultForProto);
}
Optional<llvm::coverage::Counter>
@@ -1012,6 +1016,8 @@
if (!DC)
DC = &P.SF;
+ else if (!GenericEnv)
+ GenericEnv = DC->getGenericEnvironmentOfContext();
return swift::performTypeLocChecking(P.Context, T,
/*isSILMode=*/true, IsSILType,
@@ -1510,10 +1516,46 @@
return false;
}
+/// Bind any unqualified 'Self' references to the given protocol's 'Self'
+/// generic parameter.
+///
+/// FIXME: This is a hack to work around the lack of a DeclContext for
+/// witness tables.
+static void bindProtocolSelfInTypeRepr(TypeLoc &TL, ProtocolDecl *proto) {
+ if (auto typeRepr = TL.getTypeRepr()) {
+ // AST walker to update 'Self' references.
+ class BindProtocolSelf : public ASTWalker {
+ ProtocolDecl *proto;
+ GenericTypeParamDecl *selfParam;
+ Identifier selfId;
+
+ public:
+ BindProtocolSelf(ProtocolDecl *proto)
+ : proto(proto),
+ selfParam(proto->getProtocolSelfType()->getDecl()),
+ selfId(proto->getASTContext().Id_Self) {
+ }
+
+ virtual bool walkToTypeReprPre(TypeRepr *T) override {
+ if (auto ident = dyn_cast<IdentTypeRepr>(T)) {
+ auto firstComponent = ident->getComponentRange().front();
+ if (firstComponent->getIdentifier() == selfId)
+ firstComponent->setValue(selfParam, proto);
+ }
+
+ return true;
+ }
+ };
+
+ typeRepr->walk(BindProtocolSelf(proto));
+ }
+}
+
/// Parse the substitution list for an apply instruction or
/// specialized protocol conformance.
bool SILParser::parseSubstitutions(SmallVectorImpl<ParsedSubstitution> &parsed,
- GenericEnvironment *GenericEnv) {
+ GenericEnvironment *GenericEnv,
+ ProtocolDecl *defaultForProto) {
// Check for an opening '<' bracket.
if (!P.Tok.isContextualPunctuator("<"))
return false;
@@ -1529,7 +1571,10 @@
if (TyR.isNull())
return true;
TypeLoc Ty = TyR.get();
- if (performTypeLocChecking(Ty, /*IsSILType=*/ false, GenericEnv))
+ if (defaultForProto)
+ bindProtocolSelfInTypeRepr(Ty, defaultForProto);
+ if (performTypeLocChecking(Ty, /*IsSILType=*/ false, GenericEnv,
+ defaultForProto))
return true;
parsed.push_back({Loc, Ty.getType()});
} while (P.consumeIf(tok::comma));
@@ -5725,7 +5770,8 @@
ProtocolConformance *SILParser::parseProtocolConformance(
ProtocolDecl *&proto,
GenericEnvironment *&genericEnv,
- bool localScope) {
+ bool localScope,
+ ProtocolDecl *defaultForProto) {
// Parse generic params for the protocol conformance. We need to make sure
// they have the right scope.
Optional<Scope> GenericsScope;
@@ -5741,7 +5787,8 @@
}
ProtocolConformance *retVal =
- parseProtocolConformanceHelper(proto, genericEnv, localScope);
+ parseProtocolConformanceHelper(proto, genericEnv, localScope,
+ defaultForProto);
if (localScope) {
GenericsScope.reset();
@@ -5752,13 +5799,19 @@
ProtocolConformance *SILParser::parseProtocolConformanceHelper(
ProtocolDecl *&proto,
GenericEnvironment *witnessEnv,
- bool localScope) {
+ bool localScope,
+ ProtocolDecl *defaultForProto) {
// Parse AST type.
ParserResult<TypeRepr> TyR = P.parseType();
if (TyR.isNull())
return nullptr;
TypeLoc Ty = TyR.get();
- if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv))
+ if (defaultForProto) {
+ bindProtocolSelfInTypeRepr(Ty, defaultForProto);
+ }
+
+ if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv,
+ defaultForProto))
return nullptr;
auto ConformingTy = Ty.getType();
@@ -5770,7 +5823,7 @@
// Parse substitutions for specialized conformance.
SmallVector<ParsedSubstitution, 4> parsedSubs;
- if (parseSubstitutions(parsedSubs, witnessEnv))
+ if (parseSubstitutions(parsedSubs, witnessEnv, defaultForProto))
return nullptr;
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
@@ -5778,7 +5831,8 @@
ProtocolDecl *dummy;
GenericEnvironment *specializedEnv;
auto genericConform =
- parseProtocolConformance(dummy, specializedEnv, localScope);
+ parseProtocolConformance(dummy, specializedEnv, localScope,
+ defaultForProto);
if (!genericConform)
return nullptr;
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
@@ -5799,7 +5853,7 @@
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
return nullptr;
- auto baseConform = parseProtocolConformance();
+ auto baseConform = parseProtocolConformance(defaultForProto);
if (!baseConform)
return nullptr;
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
@@ -5812,41 +5866,6 @@
return retVal;
}
-/// Bind any unqualified 'Self' references to the given protocol's 'Self'
-/// generic parameter.
-///
-/// FIXME: This is a hack to work around the lack of a DeclContext for
-/// witness tables.
-static void bindProtocolSelfInTypeRepr(TypeLoc &TL, ProtocolDecl *proto) {
- if (auto typeRepr = TL.getTypeRepr()) {
- // AST walker to update 'Self' references.
- class BindProtocolSelf : public ASTWalker {
- ProtocolDecl *proto;
- GenericTypeParamDecl *selfParam;
- Identifier selfId;
-
- public:
- BindProtocolSelf(ProtocolDecl *proto)
- : proto(proto),
- selfParam(proto->getProtocolSelfType()->getDecl()),
- selfId(proto->getASTContext().Id_Self) {
- }
-
- virtual bool walkToTypeReprPre(TypeRepr *T) override {
- if (auto ident = dyn_cast<IdentTypeRepr>(T)) {
- auto firstComponent = ident->getComponentRange().front();
- if (firstComponent->getIdentifier() == selfId)
- firstComponent->setValue(selfParam, proto);
- }
-
- return true;
- }
- };
-
- typeRepr->walk(BindProtocolSelf(proto));
- }
-}
-
/// Parser a single SIL vtable entry and add it to either \p witnessEntries
/// or \c conditionalConformances.
static bool parseSILVTableEntry(
@@ -5859,6 +5878,7 @@
std::vector<SILWitnessTable::Entry> &witnessEntries,
std::vector<SILWitnessTable::ConditionalConformance>
&conditionalConformances) {
+ ProtocolDecl *defaultForProto = isDefaultWitnessTable ? proto : nullptr;
Identifier EntryKeyword;
SourceLoc KeywordLoc;
if (P.parseIdentifier(EntryKeyword, KeywordLoc,
@@ -5878,7 +5898,8 @@
return true;
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;
- ProtocolConformance *conform = witnessState.parseProtocolConformance();
+ ProtocolConformance *conform =
+ witnessState.parseProtocolConformance(defaultForProto);
if (!conform) // Ignore this witness entry for now.
return false;
@@ -5925,7 +5946,7 @@
ProtocolConformanceRef conformance(proto);
if (P.Tok.getText() != "dependent") {
- auto concrete = witnessState.parseProtocolConformance();
+ auto concrete = witnessState.parseProtocolConformance(defaultForProto);
if (!concrete) // Ignore this witness entry for now.
return false;
conformance = ProtocolConformanceRef(concrete);
@@ -6045,7 +6066,8 @@
GenericEnvironment *witnessEnv;
auto conf = WitnessState.parseProtocolConformance(proto,
witnessEnv,
- false/*localScope*/);
+ false/*localScope*/,
+ nullptr);
WitnessState.ContextGenericEnv = witnessEnv;
NormalProtocolConformance *theConformance = conf ?
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index 1350026..4182f48 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -769,7 +769,19 @@
}
void addAssociatedConformance(const AssociatedConformance &req) {
- addMissingDefault();
+ auto witness =
+ Proto->getDefaultAssociatedConformanceWitness(
+ req.getAssociation(),
+ req.getAssociatedRequirement());
+ if (!witness)
+ return addMissingDefault();
+
+ auto entry =
+ SILWitnessTable::AssociatedTypeProtocolWitness{
+ req.getAssociation(),
+ req.getAssociatedRequirement(),
+ *witness};
+ DefaultWitnesses.push_back(entry);
}
};
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index bf1f963..194f65b 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -4689,7 +4689,25 @@
(void)decl->isDynamic();
}
-bool swift::isPassThroughTypealias(TypeAliasDecl *typealias) {
+/// Determine whether this is a "pass-through" typealias, which has the
+/// same type parameters as the nominal type it references and specializes
+/// the underlying nominal type with exactly those type parameters.
+/// For example, the following typealias \c GX is a pass-through typealias:
+///
+/// \code
+/// struct X<T, U> { }
+/// typealias GX<A, B> = X<A, B>
+/// \endcode
+///
+/// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has
+/// different type parameters and \c GX3 doesn't pass its type parameters
+/// directly through.
+///
+/// \code
+/// typealias GX2<A> = X<A, A>
+/// typealias GX3<A, B> = X<B, A>
+/// \endcode
+static bool isPassThroughTypealias(TypeAliasDecl *typealias) {
// Pass-through only makes sense when the typealias refers to a nominal
// type.
Type underlyingType = typealias->getUnderlyingTypeLoc().getType();
@@ -4877,31 +4895,78 @@
if (ext->hasValidationStarted())
return;
- bindExtension(ext);
-
DeclValidationRAII IBV(ext);
- // If the extension is already known to be invalid, we're done.
- if (ext->isInvalid())
- return;
+ auto dc = ext->getDeclContext();
- // FIXME: We need to check whether anything is specialized, because
- // the innermost extended type might itself be a non-generic type
- // within a generic type.
+ // If we didn't parse a type, fill in an error type and bail out.
+ if (!ext->getExtendedTypeLoc().getTypeRepr()) {
+ ext->setInvalid();
+ ext->getExtendedTypeLoc().setInvalidType(Context);
+ return;
+ }
+
+ // Validate the extended type.
+ TypeResolutionOptions options(TypeResolverContext::ExtensionBinding);
+ options |= TypeResolutionFlags::AllowUnboundGenerics;
+ if (validateType(ext->getExtendedTypeLoc(),
+ TypeResolution::forContextual(dc), options)) {
+ ext->setInvalid();
+ ext->getExtendedTypeLoc().setInvalidType(Context);
+ return;
+ }
+
+ // Dig out the extended type.
auto extendedType = ext->getExtendedType();
- if (extendedType.isNull() || extendedType->hasError())
+ // Hack to allow extending a generic typealias.
+ if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
+ if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
+ auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal();
+ if (extendedNominal) {
+ extendedType = extendedNominal->getDeclaredType();
+ if (!isPassThroughTypealias(aliasDecl))
+ ext->getExtendedTypeLoc().setType(extendedType);
+ }
+ }
+ }
+
+ // Cannot extend a metatype.
+ if (extendedType->is<AnyMetatypeType>()) {
+ diagnose(ext->getLoc(), diag::extension_metatype, extendedType)
+ .highlight(ext->getExtendedTypeLoc().getSourceRange());
+ ext->setInvalid();
+ ext->getExtendedTypeLoc().setInvalidType(Context);
+ return;
+ }
+
+ // Cannot extend a bound generic type.
+ if (extendedType->isSpecialized()) {
+ diagnose(ext->getLoc(), diag::extension_specialization,
+ extendedType->getAnyNominal()->getName())
+ .highlight(ext->getExtendedTypeLoc().getSourceRange());
+ ext->setInvalid();
+ ext->getExtendedTypeLoc().setInvalidType(Context);
+ return;
+ }
+
+ auto *nominal = extendedType->getAnyNominal();
+
+ // Cannot extend function types, tuple types, etc.
+ if (nominal == nullptr) {
+ diagnose(ext->getLoc(), diag::non_nominal_extension, extendedType)
+ .highlight(ext->getExtendedTypeLoc().getSourceRange());
+ ext->setInvalid();
+ ext->getExtendedTypeLoc().setInvalidType(Context);
+ return;
+ }
+
+ // Extensions nested inside other declarations are invalid and we
+ // do not bind them.
+ if (!isa<SourceFile>(dc))
return;
// Validate the nominal type declaration being extended.
- NominalTypeDecl *nominal = extendedType->getAnyNominal();
- if (!nominal) {
- auto unbound = cast<UnboundGenericType>(extendedType.getPointer());
- auto typealias = cast<TypeAliasDecl>(unbound->getDecl());
- validateDecl(typealias);
-
- nominal = typealias->getUnderlyingTypeLoc().getType()->getAnyNominal();
- }
validateDecl(nominal);
if (nominal->getGenericParamsOfContext()) {
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 9cc6860..4b1f7a5 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -5252,6 +5252,30 @@
void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
DefaultWitnessChecker checker(*this, proto);
+ // Find the default for the given associated type.
+ auto findAssociatedTypeDefault =
+ [&](AssociatedTypeDecl *assocType,
+ AssociatedTypeDecl **defaultedAssocTypeOut = nullptr) -> Type {
+ auto defaultedAssocType =
+ AssociatedTypeInference::findDefaultedAssociatedType(*this, assocType);
+ if (!defaultedAssocType)
+ return nullptr;;
+
+ Type defaultType = defaultedAssocType->getDefaultDefinitionLoc().getType();
+ if (!defaultType)
+ return nullptr;
+
+ // Map out of its protocol context...
+ defaultType = defaultType->mapTypeOutOfContext();
+ if (defaultType->hasError())
+ return nullptr;
+
+ if (defaultedAssocTypeOut)
+ *defaultedAssocTypeOut = defaultedAssocType;
+
+ return defaultType;
+ };
+
for (auto *requirement : proto->getMembers()) {
if (requirement->isInvalid())
continue;
@@ -5262,19 +5286,8 @@
if (auto assocType = dyn_cast<AssociatedTypeDecl>(valueDecl)) {
if (assocType->getOverriddenDecls().empty()) {
- if (auto defaultedAssocType =
- AssociatedTypeInference::findDefaultedAssociatedType(
- *this, assocType)) {
- Type defaultType =
- defaultedAssocType->getDefaultDefinitionLoc().getType();
-
- // Map out of its protocol context...
- defaultType = defaultType->mapTypeOutOfContext();
-
- if (!defaultType->hasError()) {
- proto->setDefaultTypeWitness(assocType, defaultType);
- }
- }
+ if (Type defaultType = findAssociatedTypeDefault(assocType))
+ proto->setDefaultTypeWitness(assocType, defaultType);
}
continue;
@@ -5288,6 +5301,77 @@
checker.resolveWitnessViaLookup(valueDecl);
}
+
+ // Find defaults for any associated conformances rooted on defaulted
+ // associated types.
+ for (const auto &req : proto->getRequirementSignature()) {
+ if (req.getKind() != RequirementKind::Conformance)
+ continue;
+ if (req.getFirstType()->isEqual(proto->getProtocolSelfType()))
+ continue;
+
+ // Find the innermost dependent member type (e.g., Self.AssocType), so
+ // we can look at the associated type.
+ auto depMemTy = req.getFirstType()->getAs<DependentMemberType>();
+ if (!depMemTy)
+ continue;
+
+ while (auto innerDepMemTy =
+ depMemTy->getBase()->getAs<DependentMemberType>())
+ depMemTy = innerDepMemTy;
+
+ if (!depMemTy->getBase()->isEqual(proto->getProtocolSelfType()))
+ continue;
+
+ auto assocType = depMemTy->getAssocType();
+ if (!assocType)
+ continue;
+
+ // Find the associated type nearest our own protocol, which might have
+ // a default not available in the associated type referenced by the
+ // (canonicalized) requirement.
+ if (assocType->getProtocol() != proto) {
+ SmallVector<ValueDecl *, 2> found;
+ proto->getModuleContext()->lookupQualified(
+ proto, assocType->getFullName(),
+ NL_QualifiedDefault|NL_ProtocolMembers|NL_OnlyTypes,
+ found);
+ if (found.size() == 1 && isa<AssociatedTypeDecl>(found[0]))
+ assocType = cast<AssociatedTypeDecl>(found[0]);
+ }
+
+ // Dig out the default associated type definition.
+ AssociatedTypeDecl *defaultedAssocType = nullptr;
+ Type defaultAssocType = findAssociatedTypeDefault(assocType,
+ &defaultedAssocType);
+ if (!defaultAssocType)
+ continue;
+
+ Type defaultAssocTypeInContext =
+ proto->mapTypeIntoContext(defaultAssocType);
+ auto requirementProto =
+ req.getSecondType()->castTo<ProtocolType>()->getDecl();
+ auto conformance = conformsToProtocol(defaultAssocTypeInContext,
+ requirementProto, proto,
+ ConformanceCheckFlags::Used);
+ if (!conformance) {
+ // Diagnose the lack of a conformance. This is potentially an ABI
+ // incompatibility.
+ diagnose(proto, diag::assoc_type_default_conformance_failed,
+ defaultAssocType, assocType->getFullName(), req.getFirstType(),
+ req.getSecondType());
+ diagnose(defaultedAssocType, diag::assoc_type_default_here,
+ assocType->getFullName(), defaultAssocType)
+ .highlight(
+ defaultedAssocType->getDefaultDefinitionLoc().getSourceRange());
+
+ continue;
+ }
+
+ // Record the default associated conformance.
+ proto->setDefaultAssociatedConformanceWitness(
+ req.getFirstType()->getCanonicalType(), requirementProto, *conformance);
+ }
}
void TypeChecker::recordKnownWitness(NormalProtocolConformance *conformance,
diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp
index 8f441ac..615cb50 100644
--- a/lib/Sema/TypeCheckProtocolInference.cpp
+++ b/lib/Sema/TypeCheckProtocolInference.cpp
@@ -183,15 +183,19 @@
if (extension == conformanceExtension)
return true;
- tc.bindExtension(extension);
+ auto *extendedNominal = extension->getExtendedNominal();
+
+ // Invalid case.
+ if (extendedNominal == nullptr)
+ return true;
// Assume unconstrained concrete extensions we found witnesses in are
// always viable.
- if (!extension->getExtendedType()->isAnyExistentialType()) {
- // TODO: When constrained extensions are a thing, we'll need an "is
- // as specialized as" kind of check here.
+ if (!isa<ProtocolDecl>(extendedNominal))
return !extension->isConstrainedExtension();
- }
+
+ // Build a generic signature.
+ tc.validateExtension(extension);
// The extension may not have a generic signature set up yet, as a
// recursion breaker, in which case we can't yet confidently reject its
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index 07fe209..90ab00d 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -346,80 +346,6 @@
nominal->addExtension(ext);
}
-static void bindExtensionDecl(ExtensionDecl *ED, TypeChecker &TC) {
- if (ED->getExtendedType())
- return;
-
- // If we didn't parse a type, fill in an error type and bail out.
- if (!ED->getExtendedTypeLoc().getTypeRepr()) {
- ED->setInvalid();
- ED->getExtendedTypeLoc().setInvalidType(TC.Context);
- return;
- }
-
- auto dc = ED->getDeclContext();
-
- // Validate the representation.
- // FIXME: Perform some kind of "shallow" validation here?
- TypeResolutionOptions options(TypeResolverContext::ExtensionBinding);
- options |= TypeResolutionFlags::AllowUnboundGenerics;
- if (TC.validateType(ED->getExtendedTypeLoc(),
- TypeResolution::forContextual(dc), options)) {
- ED->setInvalid();
- ED->getExtendedTypeLoc().setInvalidType(TC.Context);
- return;
- }
-
- // Dig out the extended type.
- auto extendedType = ED->getExtendedType();
-
- // Hack to allow extending a generic typealias.
- if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
- if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
- auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal();
- if (extendedNominal) {
- extendedType = extendedNominal->getDeclaredType();
- if (!isPassThroughTypealias(aliasDecl))
- ED->getExtendedTypeLoc().setType(extendedType);
- }
- }
- }
-
- // Handle easy cases.
-
- // Cannot extend a metatype.
- if (extendedType->is<AnyMetatypeType>()) {
- TC.diagnose(ED->getLoc(), diag::extension_metatype, extendedType)
- .highlight(ED->getExtendedTypeLoc().getSourceRange());
- ED->setInvalid();
- ED->getExtendedTypeLoc().setInvalidType(TC.Context);
- return;
- }
-
- // Cannot extend a bound generic type.
- if (extendedType->isSpecialized()) {
- TC.diagnose(ED->getLoc(), diag::extension_specialization,
- extendedType->getAnyNominal()->getName())
- .highlight(ED->getExtendedTypeLoc().getSourceRange());
- ED->setInvalid();
- ED->getExtendedTypeLoc().setInvalidType(TC.Context);
- return;
- }
-
- // Dig out the nominal type being extended.
- NominalTypeDecl *extendedNominal = extendedType->getAnyNominal();
- if (!extendedNominal) {
- TC.diagnose(ED->getLoc(), diag::non_nominal_extension, extendedType)
- .highlight(ED->getExtendedTypeLoc().getSourceRange());
- ED->setInvalid();
- ED->getExtendedTypeLoc().setInvalidType(TC.Context);
- return;
- }
- assert(extendedNominal && "Should have the nominal type being extended");
-
- bindExtensionToNominal(ED, extendedNominal);
-}
-
static void bindExtensions(SourceFile &SF, TypeChecker &TC) {
// Utility function to try and resolve the extended type without diagnosing.
// If we succeed, we go ahead and bind the extension. Otherwise, return false.
@@ -467,14 +393,8 @@
}
} while(changed);
- // Phase 3 - anything that remains on the worklist cannot be resolved, which
- // means its invalid. Diagnose.
- for (auto *ext : worklist)
- bindExtensionDecl(ext, TC);
-}
-
-void TypeChecker::bindExtension(ExtensionDecl *ext) {
- ::bindExtensionDecl(ext, *this);
+ // Any remaining extensions are invalid. They will be diagnosed later by
+ // typeCheckDecl().
}
static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC) {
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index 6dc3db3..6d13959 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -1106,8 +1106,6 @@
validateDecl(proto);
}
- virtual void bindExtension(ExtensionDecl *ext) override;
-
virtual void resolveExtension(ExtensionDecl *ext) override {
validateExtension(ext);
}
@@ -2173,26 +2171,6 @@
DeclContext *DC,
TypeChecker &TC);
-/// Determine whether this is a "pass-through" typealias, which has the
-/// same type parameters as the nominal type it references and specializes
-/// the underlying nominal type with exactly those type parameters.
-/// For example, the following typealias \c GX is a pass-through typealias:
-///
-/// \code
-/// struct X<T, U> { }
-/// typealias GX<A, B> = X<A, B>
-/// \endcode
-///
-/// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has
-/// different type parameters and \c GX3 doesn't pass its type parameters
-/// directly through.
-///
-/// \code
-/// typealias GX2<A> = X<A, A>
-/// typealias GX3<A, B> = X<B, A>
-/// \endcode
-bool isPassThroughTypealias(TypeAliasDecl *typealias);
-
/// Whether an overriding declaration requires the 'override' keyword.
enum class OverrideRequiresKeyword {
/// The keyword is never required.
diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp
index 09b95d2..a97621d 100644
--- a/lib/Serialization/SerializedModuleLoader.cpp
+++ b/lib/Serialization/SerializedModuleLoader.cpp
@@ -326,9 +326,19 @@
if (auto orphanedBuffer = loadedModuleFile->takeBufferForDiagnostics())
OrphanedMemoryBuffers.push_back(std::move(orphanedBuffer));
- if (!diagLoc)
- return nullptr;
+ if (diagLoc)
+ serialization::diagnoseSerializedASTLoadFailure(
+ Ctx, *diagLoc, loadInfo, extendedInfo, moduleBufferID,
+ moduleDocBufferID, loadedModuleFile.get(), M.getName());
+ return nullptr;
+}
+void swift::serialization::diagnoseSerializedASTLoadFailure(
+ ASTContext &Ctx, SourceLoc diagLoc,
+ const serialization::ValidationInfo &loadInfo,
+ const serialization::ExtendedValidationInfo &extendedInfo,
+ StringRef moduleBufferID, StringRef moduleDocBufferID,
+ ModuleFile *loadedModuleFile, Identifier ModuleName) {
auto diagnoseDifferentLanguageVersion = [&](StringRef shortVersion) -> bool {
if (shortVersion.empty())
return false;
@@ -339,10 +349,9 @@
if (versionString.str() == shortVersion)
return false;
- Ctx.Diags.diagnose(*diagLoc,
- diag::serialization_module_language_version_mismatch,
- loadInfo.shortVersion, versionString.str(),
- moduleBufferID);
+ Ctx.Diags.diagnose(
+ diagLoc, diag::serialization_module_language_version_mismatch,
+ loadInfo.shortVersion, versionString.str(), moduleBufferID);
return true;
};
@@ -353,23 +362,23 @@
case serialization::Status::FormatTooNew:
if (diagnoseDifferentLanguageVersion(loadInfo.shortVersion))
break;
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_module_too_new,
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_module_too_new,
moduleBufferID);
break;
case serialization::Status::FormatTooOld:
if (diagnoseDifferentLanguageVersion(loadInfo.shortVersion))
break;
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_module_too_old,
- M.getName(), moduleBufferID);
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_module_too_old, ModuleName,
+ moduleBufferID);
break;
case serialization::Status::Malformed:
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_malformed_module,
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_malformed_module,
moduleBufferID);
break;
case serialization::Status::MalformedDocumentation:
assert(!moduleDocBufferID.empty());
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_malformed_module,
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_malformed_module,
moduleDocBufferID);
break;
@@ -379,19 +388,19 @@
// not now.
llvm::StringSet<> duplicates;
llvm::SmallVector<ModuleFile::Dependency, 4> missing;
- std::copy_if(loadedModuleFile->getDependencies().begin(),
- loadedModuleFile->getDependencies().end(),
- std::back_inserter(missing),
- [&duplicates](const ModuleFile::Dependency &dependency)->bool {
- if (dependency.isLoaded() || dependency.isHeader())
- return false;
- return duplicates.insert(dependency.RawPath).second;
- });
+ std::copy_if(
+ loadedModuleFile->getDependencies().begin(),
+ loadedModuleFile->getDependencies().end(), std::back_inserter(missing),
+ [&duplicates](const ModuleFile::Dependency &dependency) -> bool {
+ if (dependency.isLoaded() || dependency.isHeader())
+ return false;
+ return duplicates.insert(dependency.RawPath).second;
+ });
// FIXME: only show module part of RawAccessPath
assert(!missing.empty() && "unknown missing dependency?");
if (missing.size() == 1) {
- Ctx.Diags.diagnose(*diagLoc,diag::serialization_missing_single_dependency,
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_missing_single_dependency,
missing.front().getPrettyPrintedPath());
} else {
llvm::SmallString<64> missingNames;
@@ -403,7 +412,7 @@
[&] { missingNames += "', '"; });
missingNames += '\'';
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_missing_dependencies,
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_missing_dependencies,
missingNames);
}
@@ -419,24 +428,25 @@
auto circularDependencyIter =
llvm::find_if(loadedModuleFile->getDependencies(),
[](const ModuleFile::Dependency &next) {
- return !next.Import.second->hasResolvedImports();
- });
- assert(circularDependencyIter != loadedModuleFile->getDependencies().end()
- && "circular dependency reported, but no module with unresolved "
- "imports found");
+ return !next.Import.second->hasResolvedImports();
+ });
+ assert(circularDependencyIter !=
+ loadedModuleFile->getDependencies().end() &&
+ "circular dependency reported, but no module with unresolved "
+ "imports found");
// FIXME: We should include the path of the circularity as well, but that's
// hard because we're discovering this /while/ resolving imports, which
// means the problematic modules haven't been recorded yet.
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_circular_dependency,
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_circular_dependency,
circularDependencyIter->getPrettyPrintedPath(),
- M.getName());
+ ModuleName);
break;
}
case serialization::Status::MissingShadowedModule: {
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_missing_shadowed_module,
- M.getName());
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_missing_shadowed_module,
+ ModuleName);
if (Ctx.SearchPathOpts.SDKPath.empty() &&
llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) {
Ctx.Diags.diagnose(SourceLoc(), diag::sema_no_import_no_sdk);
@@ -448,7 +458,7 @@
case serialization::Status::FailedToLoadBridgingHeader:
// We already emitted a diagnostic about the bridging header. Just emit
// a generic message here.
- Ctx.Diags.diagnose(*diagLoc, diag::serialization_load_failed, M.getName());
+ Ctx.Diags.diagnose(diagLoc, diag::serialization_load_failed, ModuleName);
break;
case serialization::Status::NameMismatch: {
@@ -457,8 +467,7 @@
auto diagKind = diag::serialization_name_mismatch;
if (Ctx.LangOpts.DebuggerSupport)
diagKind = diag::serialization_name_mismatch_repl;
- Ctx.Diags.diagnose(*diagLoc, diagKind,
- loadInfo.name, M.getName());
+ Ctx.Diags.diagnose(diagLoc, diagKind, loadInfo.name, ModuleName);
break;
}
@@ -468,8 +477,8 @@
auto diagKind = diag::serialization_target_incompatible;
if (Ctx.LangOpts.DebuggerSupport)
diagKind = diag::serialization_target_incompatible_repl;
- Ctx.Diags.diagnose(*diagLoc, diagKind,
- M.getName(), loadInfo.targetTriple, moduleBufferID);
+ Ctx.Diags.diagnose(diagLoc, diagKind, ModuleName, loadInfo.targetTriple,
+ moduleBufferID);
break;
}
@@ -486,14 +495,12 @@
auto diagKind = diag::serialization_target_too_new;
if (Ctx.LangOpts.DebuggerSupport)
diagKind = diag::serialization_target_too_new_repl;
- Ctx.Diags.diagnose(*diagLoc, diagKind,
- compilationOSInfo.first, compilationOSInfo.second,
- M.getName(), moduleOSInfo.second, moduleBufferID);
+ Ctx.Diags.diagnose(diagLoc, diagKind, compilationOSInfo.first,
+ compilationOSInfo.second, ModuleName,
+ moduleOSInfo.second, moduleBufferID);
break;
}
}
-
- return nullptr;
}
bool
diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp
index 68e0d42..384cd05 100644
--- a/lib/TBDGen/TBDGen.cpp
+++ b/lib/TBDGen/TBDGen.cpp
@@ -100,11 +100,8 @@
}
void TBDGenVisitor::addAssociatedConformanceDescriptor(
- ProtocolDecl *proto,
- CanType subject,
- ProtocolDecl *requirement) {
- auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
- requirement);
+ AssociatedConformance conformance) {
+ auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
addSymbol(entity);
}
@@ -426,10 +423,11 @@
if (req.getFirstType()->isEqual(PD->getProtocolSelfType()))
continue;
- addAssociatedConformanceDescriptor(
- PD,
- req.getFirstType()->getCanonicalType(),
- req.getSecondType()->castTo<ProtocolType>()->getDecl());
+ AssociatedConformance conformance(
+ PD,
+ req.getFirstType()->getCanonicalType(),
+ req.getSecondType()->castTo<ProtocolType>()->getDecl());
+ addAssociatedConformanceDescriptor(conformance);
}
for (auto *member : PD->getMembers()) {
@@ -442,7 +440,8 @@
}
}
- // Always produce associated type descriptors.
+ // Always produce associated type descriptors, because they can
+ // be referenced by generic signatures.
if (auto *assocType = dyn_cast<AssociatedTypeDecl>(member)) {
if (assocType->getOverriddenDecls().empty())
addAssociatedTypeDescriptor(assocType);
diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h
index 9db482e..e468265 100644
--- a/lib/TBDGen/TBDGenVisitor.h
+++ b/lib/TBDGen/TBDGenVisitor.h
@@ -66,9 +66,7 @@
void addProtocolRequirementsBaseDescriptor(ProtocolDecl *proto);
void addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType);
- void addAssociatedConformanceDescriptor(ProtocolDecl *proto,
- CanType subject,
- ProtocolDecl *requirement);
+ void addAssociatedConformanceDescriptor(AssociatedConformance conformance);
public:
TBDGenVisitor(tapi::internal::InterfaceFile &symbols,
diff --git a/stdlib/public/core/Integers.swift b/stdlib/public/core/Integers.swift
index 0418e5a..2c00e90 100644
--- a/stdlib/public/core/Integers.swift
+++ b/stdlib/public/core/Integers.swift
@@ -303,7 +303,7 @@
///
/// - Parameter x: A signed number.
/// - Returns: The absolute value of `x`.
-@_transparent
+@inlinable
public func abs<T : SignedNumeric>(_ x: T) -> T
where T.Magnitude == T {
return x.magnitude
@@ -322,9 +322,9 @@
///
/// - Parameter x: A signed number.
/// - Returns: The absolute value of `x`.
-@inlinable // FIXME(sil-serialize-all)
+@inlinable
public func abs<T : SignedNumeric & Comparable>(_ x: T) -> T {
- return x < 0 ? -x : x
+ return x < (0 as T) ? -x : x
}
extension Numeric {
@@ -1185,7 +1185,7 @@
///
/// - Returns: The sign of this number, expressed as an integer of the same
/// type.
- @_transparent
+ @inlinable
public func signum() -> Self {
return (self > (0 as Self) ? 1 : 0) - (self < (0 as Self) ? 1 : 0)
}
@@ -1196,7 +1196,7 @@
return it.next() ?? 0
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public func _binaryLogarithm() -> Int {
_precondition(self > (0 as Self))
var (quotient, remainder) =
@@ -1233,7 +1233,7 @@
/// - Parameter rhs: The value to divide this value by.
/// - Returns: A tuple containing the quotient and remainder of this value
/// divided by `rhs`.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public func quotientAndRemainder(dividingBy rhs: Self)
-> (quotient: Self, remainder: Self) {
return (self / rhs, self % rhs)
@@ -1370,7 +1370,7 @@
/// - lhs: The value to shift.
/// - rhs: The number of bits to shift `lhs` to the right.
@_semantics("optimize.sil.specialize.generic.partial.never")
- @inlinable
+ @_transparent
public static func >> <RHS: BinaryInteger>(lhs: Self, rhs: RHS) -> Self {
var r = lhs
r >>= rhs
@@ -1416,7 +1416,7 @@
/// - lhs: The value to shift.
/// - rhs: The number of bits to shift `lhs` to the left.
@_semantics("optimize.sil.specialize.generic.partial.never")
- @inlinable
+ @_transparent
public static func << <RHS: BinaryInteger>(lhs: Self, rhs: RHS) -> Self {
var r = lhs
r <<= rhs
@@ -1493,7 +1493,6 @@
}
/// A textual representation of this value.
- @inlinable // FIXME(sil-serialize-all)
public var description: String {
return _description(radix: 10, uppercase: false)
}
@@ -1505,7 +1504,6 @@
//===----------------------------------------------------------------------===//
extension BinaryInteger {
- // FIXME(ABI): using Int as the return type is wrong.
/// Returns the distance from this value to the given value, expressed as a
/// stride.
///
@@ -1514,7 +1512,7 @@
///
/// - Parameter other: The value to calculate the distance to.
/// - Returns: The distance from this value to `other`.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@inline(__always)
public func distance(to other: Self) -> Int {
if !Self.isSigned {
@@ -1542,7 +1540,6 @@
_preconditionFailure("Distance is not representable in Int")
}
- // FIXME(ABI): using Int as the parameter type is wrong.
/// Returns a value that is offset the specified distance from this value.
///
/// Use the `advanced(by:)` method in generic code to offset a value by a
@@ -1554,7 +1551,7 @@
///
/// - Parameter n: The distance to advance this value.
/// - Returns: A value that is offset from this value by `n`.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@inline(__always)
public func advanced(by n: Int) -> Self {
if !Self.isSigned {
@@ -1594,8 +1591,7 @@
/// - Parameters:
/// - lhs: An integer to compare.
/// - rhs: Another integer to compare.
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func == <
Other : BinaryInteger
>(lhs: Self, rhs: Other) -> Bool {
@@ -1669,8 +1665,7 @@
/// - Parameters:
/// - lhs: An integer to compare.
/// - rhs: Another integer to compare.
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func < <Other : BinaryInteger>(lhs: Self, rhs: Other) -> Bool {
let lhsNegative = Self.isSigned && lhs < (0 as Self)
let rhsNegative = Other.isSigned && rhs < (0 as Other)
@@ -1713,7 +1708,6 @@
/// - lhs: An integer to compare.
/// - rhs: Another integer to compare.
@_transparent
- //@inline(__always)
public static func <= <Other : BinaryInteger>(lhs: Self, rhs: Other) -> Bool {
return !(rhs < lhs)
}
@@ -1729,7 +1723,6 @@
/// - lhs: An integer to compare.
/// - rhs: Another integer to compare.
@_transparent
- //@inline(__always)
public static func >= <Other : BinaryInteger>(lhs: Self, rhs: Other) -> Bool {
return !(lhs < rhs)
}
@@ -1745,7 +1738,6 @@
/// - lhs: An integer to compare.
/// - rhs: Another integer to compare.
@_transparent
- //@inline(__always)
public static func > <Other : BinaryInteger>(lhs: Self, rhs: Other) -> Bool {
return rhs < lhs
}
@@ -1773,20 +1765,17 @@
return !(lhs == rhs)
}
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func <= (lhs: Self, rhs: Self) -> Bool {
return !(rhs < lhs)
}
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func >= (lhs: Self, rhs: Self) -> Bool {
return !(lhs < rhs)
}
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func > (lhs: Self, rhs: Self) -> Bool {
return rhs < lhs
}
@@ -2214,7 +2203,7 @@
@inlinable
public var bitWidth: Int { return Self.bitWidth }
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public func _binaryLogarithm() -> Int {
_precondition(self > (0 as Self))
return Self.bitWidth &- (leadingZeroBitCount &+ 1)
@@ -2225,7 +2214,7 @@
///
/// - Parameter value: A value to use as the little-endian representation of
/// the new integer.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public init(littleEndian value: Self) {
#if _endian(little)
self = value
@@ -2239,7 +2228,7 @@
///
/// - Parameter value: A value to use as the big-endian representation of the
/// new integer.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public init(bigEndian value: Self) {
#if _endian(big)
self = value
@@ -2253,7 +2242,7 @@
/// If necessary, the byte order of this value is reversed from the typical
/// byte order of this integer type. On a little-endian platform, for any
/// integer `x`, `x == x.littleEndian`.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public var littleEndian: Self {
#if _endian(little)
return self
@@ -2267,7 +2256,7 @@
/// If necessary, the byte order of this value is reversed from the typical
/// byte order of this integer type. On a big-endian platform, for any
/// integer `x`, `x == x.bigEndian`.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
public var bigEndian: Self {
#if _endian(big)
return self
@@ -2310,7 +2299,6 @@
/// - rhs: The number of bits to shift `lhs` to the right. If `rhs` is
/// outside the range `0..<lhs.bitWidth`, it is masked to produce a
/// value within that range.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
public static func &>> (lhs: Self, rhs: Self) -> Self {
@@ -2354,7 +2342,7 @@
/// outside the range `0..<lhs.bitWidth`, it is masked to produce a
/// value within that range.
@_semantics("optimize.sil.specialize.generic.partial.never")
- @inlinable
+ @_transparent
public static func &>> <
Other : BinaryInteger
>(lhs: Self, rhs: Other) -> Self {
@@ -2389,7 +2377,6 @@
/// - rhs: The number of bits to shift `lhs` to the right. If `rhs` is
/// outside the range `0..<lhs.bitWidth`, it is masked to produce a
/// value within that range.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
public static func &>>= <
@@ -2432,7 +2419,6 @@
/// - rhs: The number of bits to shift `lhs` to the left. If `rhs` is
/// outside the range `0..<lhs.bitWidth`, it is masked to produce a
/// value within that range.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
public static func &<< (lhs: Self, rhs: Self) -> Self {
@@ -2476,7 +2462,7 @@
/// outside the range `0..<lhs.bitWidth`, it is masked to produce a
/// value within that range.
@_semantics("optimize.sil.specialize.generic.partial.never")
- @inlinable
+ @_transparent
public static func &<< <
Other : BinaryInteger
>(lhs: Self, rhs: Other) -> Self {
@@ -2511,7 +2497,6 @@
/// - rhs: The number of bits to shift `lhs` to the left. If `rhs` is
/// outside the range `0..<lhs.bitWidth`, it is masked to produce a
/// value within that range.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
public static func &<<= <
@@ -2756,7 +2741,6 @@
/// - Parameters:
/// - lhs: The value to shift.
/// - rhs: The number of bits to shift `lhs` to the right.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
public static func >> <
@@ -2785,8 +2769,7 @@
lhs = _nonMaskingRightShift(lhs, shift)
}
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func _nonMaskingRightShift(_ lhs: Self, _ rhs: Int) -> Self {
let overshiftR = Self.isSigned ? lhs &>> (Self.bitWidth - 1) : 0
let overshiftL: Self = 0
@@ -2845,7 +2828,6 @@
/// - Parameters:
/// - lhs: The value to shift.
/// - rhs: The number of bits to shift `lhs` to the left.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
public static func << <
@@ -2874,8 +2856,7 @@
lhs = _nonMaskingLeftShift(lhs, shift)
}
- @inlinable // FIXME(sil-serialize-all)
- @inline(__always)
+ @_transparent
public static func _nonMaskingLeftShift(_ lhs: Self, _ rhs: Int) -> Self {
let overshiftR = Self.isSigned ? lhs &>> (Self.bitWidth - 1) : 0
let overshiftL: Self = 0
@@ -2972,9 +2953,8 @@
/// // y == nil
///
/// - Parameter source: A floating-point value to convert to an integer.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
- @inline(__always)
+ @inlinable
public init?<T : BinaryFloatingPoint>(exactly source: T) {
let (temporary, exact) = Self._convert(from: source)
guard exact, let value = temporary else {
@@ -3003,7 +2983,7 @@
/// // y == 0
///
/// - Parameter source: An integer to convert to this type.
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@_semantics("optimize.sil.specialize.generic.partial.never")
public init<Other : BinaryInteger>(clamping source: Other) {
if _slowPath(source < Self.min) {
@@ -3033,7 +3013,7 @@
///
/// - Parameter rhs: The value to add to this value.
/// - Returns: The sum of this value and `rhs`.
- @_transparent
+ @inline(__always)
public func unsafeAdding(_ other: Self) -> Self {
let (result, overflow) = self.addingReportingOverflow(other)
@@ -3066,7 +3046,7 @@
///
/// - Parameter rhs: The value to subtract from this value.
/// - Returns: The result of subtracting `rhs` from this value.
- @_transparent
+ @inline(__always)
public func unsafeSubtracting(_ other: Self) -> Self {
let (result, overflow) = self.subtractingReportingOverflow(other)
@@ -3099,7 +3079,7 @@
///
/// - Parameter rhs: The value to multiply by this value.
/// - Returns: The product of this value and `rhs`.
- @_transparent
+ @inline(__always)
public func unsafeMultiplied(by other: Self) -> Self {
let (result, overflow) = self.multipliedReportingOverflow(by: other)
@@ -3128,7 +3108,7 @@
///
/// - Parameter rhs: The value to divide this value by.
/// - Returns: The result of dividing this value by `rhs`.
- @_transparent
+ @inline(__always)
public func unsafeDivided(by other: Self) -> Self {
let (result, overflow) = self.dividedReportingOverflow(by: other)
@@ -3179,7 +3159,6 @@
/// // 'y' has a binary representation of 11111111_11101011
///
/// - Parameter source: An integer to convert to this type.
- @inlinable // FIXME(sil-serialize-all)
@inline(__always)
public init<T : BinaryInteger>(truncatingIfNeeded source: T) {
if Self.bitWidth <= Int.bitWidth {
@@ -3421,14 +3400,18 @@
/// to find an absolute value. In addition, because `abs(_:)` always returns
/// a value of the same type, even in a generic context, using the function
/// instead of the `magnitude` property is encouraged.
- @_transparent
- public var magnitude: Self { return self }
+ public var magnitude: Self {
+ @inline(__always)
+ get { return self }
+ }
/// A Boolean value indicating whether this type is a signed integer type.
///
/// This property is always `false` for unsigned integer types.
- @_transparent
- public static var isSigned: Bool { return false }
+ public static var isSigned: Bool {
+ @inline(__always)
+ get { return false }
+ }
}
extension UnsignedInteger where Self : FixedWidthInteger {
@@ -3451,7 +3434,6 @@
///
/// - Parameter source: A value to convert to this type of integer. The value
/// passed as `source` must be representable in this type.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init<T : BinaryInteger>(_ source: T) {
@@ -3482,7 +3464,6 @@
/// // y == nil
///
/// - Parameter source: A value to convert to this type of integer.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init?<T : BinaryInteger>(exactly source: T) {
@@ -3503,17 +3484,13 @@
/// For unsigned integer types, this value is `(2 ** bitWidth) - 1`, where
/// `**` is exponentiation.
@_transparent
- public static var max: Self {
- return ~0
- }
+ public static var max: Self { return ~0 }
/// The minimum representable integer in this type.
///
/// For unsigned integer types, this value is always `0`.
@_transparent
- public static var min: Self {
- return 0
- }
+ public static var min: Self { return 0 }
}
@@ -3532,8 +3509,10 @@
/// A Boolean value indicating whether this type is a signed integer type.
///
/// This property is always `true` for signed integer types.
- @_transparent
- public static var isSigned: Bool { return true }
+ public static var isSigned: Bool {
+ @inline(__always)
+ get { return true }
+ }
}
extension SignedInteger where Self : FixedWidthInteger {
@@ -3556,7 +3535,6 @@
///
/// - Parameter source: A value to convert to this type of integer. The value
/// passed as `source` must be representable in this type.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init<T : BinaryInteger>(_ source: T) {
@@ -3589,7 +3567,6 @@
/// // y == nil
///
/// - Parameter source: A value to convert to this type of integer.
- @inlinable // FIXME(sil-serialize-all)
@_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init?<T : BinaryInteger>(exactly source: T) {
@@ -3611,9 +3588,7 @@
/// For signed integer types, this value is `(2 ** (bitWidth - 1)) - 1`,
/// where `**` is exponentiation.
@_transparent
- public static var max: Self {
- return ~min
- }
+ public static var max: Self { return ~min }
/// The minimum representable integer in this type.
///
@@ -3657,7 +3632,7 @@
///
/// - Parameter x: The integer to convert, and instance of type `T`.
/// - Returns: The value of `x` converted to type `U`.
-@_transparent
+@inlinable
public func numericCast<T : BinaryInteger, U : BinaryInteger>(_ x: T) -> U {
return U(x)
}
@@ -3669,7 +3644,6 @@
// At the same time, since they are obsolete in Swift 4, this will not cause
// `u8 << -1` to fail due to an overflow in an unsigned value.
extension FixedWidthInteger {
- @inlinable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
@@ -3679,7 +3653,6 @@
return lhs
}
- @inlinable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
@@ -3687,7 +3660,6 @@
_nonMaskingRightShiftGeneric(&lhs, rhs)
}
- @inlinable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
@@ -3697,7 +3669,6 @@
return lhs
}
- @inlinable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4)
@_semantics("optimize.sil.specialize.generic.partial.never")
@_transparent
@@ -3707,9 +3678,8 @@
}
extension FixedWidthInteger {
- @inlinable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4, message: "Use addingReportingOverflow(_:) instead.")
- @_transparent
+ @inlinable
public static func addWithOverflow(
_ lhs: Self, _ rhs: Self
) -> (Self, overflow: Bool) {
@@ -3718,9 +3688,8 @@
return (partialValue, overflow: overflow)
}
- @inlinable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4, message: "Use subtractingReportingOverflow(_:) instead.")
- @_transparent
+ @inlinable
public static func subtractWithOverflow(
_ lhs: Self, _ rhs: Self
) -> (Self, overflow: Bool) {
@@ -3729,9 +3698,8 @@
return (partialValue, overflow: overflow)
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 4, message: "Use multipliedReportingOverflow(by:) instead.")
- @_transparent
public static func multiplyWithOverflow(
_ lhs: Self, _ rhs: Self
) -> (Self, overflow: Bool) {
@@ -3740,9 +3708,8 @@
return (partialValue, overflow: overflow)
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 4, message: "Use dividedReportingOverflow(by:) instead.")
- @_transparent
public static func divideWithOverflow(
_ lhs: Self, _ rhs: Self
) -> (Self, overflow: Bool) {
@@ -3751,9 +3718,8 @@
return (partialValue, overflow: overflow)
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 4, message: "Use remainderReportingOverflow(dividingBy:) instead.")
- @_transparent
public static func remainderWithOverflow(
_ lhs: Self, _ rhs: Self
) -> (Self, overflow: Bool) {
@@ -3764,7 +3730,7 @@
}
extension BinaryInteger {
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 3.2,
message: "Please use FixedWidthInteger protocol as a generic constraint and addingReportingOverflow(_:) method instead.")
public static func addWithOverflow(
@@ -3773,7 +3739,7 @@
fatalError("Unavailable")
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 3.2,
message: "Please use FixedWidthInteger protocol as a generic constraint and subtractingReportingOverflow(_:) method instead.")
public static func subtractWithOverflow(
@@ -3782,7 +3748,7 @@
fatalError("Unavailable")
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 3.2,
message: "Please use FixedWidthInteger protocol as a generic constraint and multipliedReportingOverflow(by:) method instead.")
public static func multiplyWithOverflow(
@@ -3791,7 +3757,7 @@
fatalError("Unavailable")
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 3.2,
message: "Please use FixedWidthInteger protocol as a generic constraint and dividedReportingOverflow(by:) method instead.")
public static func divideWithOverflow(
@@ -3800,7 +3766,7 @@
fatalError("Unavailable")
}
- @inlinable // FIXME(sil-serialize-all)
+ @inlinable
@available(swift, obsoleted: 3.2,
message: "Please use FixedWidthInteger protocol as a generic constraint and remainderReportingOverflow(dividingBy:) method instead.")
public static func remainderWithOverflow(
@@ -3820,24 +3786,24 @@
// var _ = (x &+ (y - 1)) < x
// ^
extension SignedInteger {
- @inlinable // FIXME(sil-serialize-all)
+ @_transparent
public static func _maskingAdd(_ lhs: Self, _ rhs: Self) -> Self {
fatalError("Should be overridden in a more specific type")
}
- @inlinable // FIXME(sil-serialize-all)
+ @_transparent
@available(swift, obsoleted: 4.0,
message: "Please use 'FixedWidthInteger' instead of 'SignedInteger' to get '&+' in generic code.")
public static func &+ (lhs: Self, rhs: Self) -> Self {
return _maskingAdd(lhs, rhs)
}
- @inlinable // FIXME(sil-serialize-all)
+ @_transparent
public static func _maskingSubtract(_ lhs: Self, _ rhs: Self) -> Self {
fatalError("Should be overridden in a more specific type")
}
- @inlinable // FIXME(sil-serialize-all)
+ @_transparent
@available(swift, obsoleted: 4.0,
message: "Please use 'FixedWidthInteger' instead of 'SignedInteger' to get '&-' in generic code.")
public static func &- (lhs: Self, rhs: Self) -> Self {
@@ -3848,7 +3814,7 @@
extension SignedInteger where Self : FixedWidthInteger {
// This overload is supposed to break the ambiguity between the
// implementations on SignedInteger and FixedWidthInteger
- @inlinable // FIXME(sil-serialize-all)
+ @_transparent
public static func &+ (lhs: Self, rhs: Self) -> Self {
return _maskingAdd(lhs, rhs)
}
@@ -3860,7 +3826,7 @@
// This overload is supposed to break the ambiguity between the
// implementations on SignedInteger and FixedWidthInteger
- @inlinable // FIXME(sil-serialize-all)
+ @_transparent
public static func &- (lhs: Self, rhs: Self) -> Self {
return _maskingSubtract(lhs, rhs)
}
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index 993c5d7..4b62dbb 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -3620,11 +3620,13 @@
return false;
}
- // If we don't have resilient witnesses, the template must provide
- // everything.
- assert (genericTable->WitnessTableSizeInWords ==
+ // If we don't have the exact number of witnesses expected, we require
+ // instantiation.
+ if (genericTable->WitnessTableSizeInWords !=
(genericTable->Protocol->NumRequirements +
- WitnessTableFirstRequirementOffset));
+ WitnessTableFirstRequirementOffset)) {
+ return false;
+ }
// If we have an instantiation function or private data, we require
// instantiation.
@@ -3643,39 +3645,65 @@
auto protocol = genericTable->Protocol.get();
auto requirements = protocol->getRequirements();
- auto witnesses = genericTable->ResilientWitnesses->getWitnesses();
+ llvm::ArrayRef<TargetResilientWitness<InProcess>> witnesses;
+ if (auto resilientWitnesses = genericTable->ResilientWitnesses.get())
+ witnesses = resilientWitnesses->getWitnesses();
- for (size_t i = 0, e = protocol->NumRequirements; i < e; ++i) {
- auto &reqt = requirements[i];
+ // Loop over the provided witnesses, filling in appropriate entry.
+ for (const auto &witness : witnesses) {
+ // Retrieve the requirement descriptor.
+ auto reqDescriptor = witness.Requirement.get();
- // Only certain requirements are filled in from the resilient witness table.
- switch (reqt.Flags.getKind()) {
- case ProtocolRequirementFlags::Kind::Method:
- case ProtocolRequirementFlags::Kind::Init:
- case ProtocolRequirementFlags::Kind::Getter:
- case ProtocolRequirementFlags::Kind::Setter:
- case ProtocolRequirementFlags::Kind::ReadCoroutine:
- case ProtocolRequirementFlags::Kind::ModifyCoroutine:
- case ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction:
- break;
- case ProtocolRequirementFlags::Kind::BaseProtocol:
- case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction:
- continue;
+ // The requirement descriptor may be NULL, in which case this is a
+ // requirement introduced in a later version of the protocol./
+ if (!reqDescriptor) continue;
+
+ // If the requirement descriptor doesn't land within the bounds of the
+ // requirements, abort.
+ if (reqDescriptor < requirements.begin() ||
+ reqDescriptor >= requirements.end()) {
+ fatalError(0, "generic witness table at %p contains out-of-bounds "
+ "requirement descriptor %p",
+ genericTable, reqDescriptor);
}
+ unsigned witnessIndex = (reqDescriptor - requirements.data()) +
+ WitnessTableFirstRequirementOffset;
+
+#if !NDEBUG
+ // For debug builds, warn if we already have an entry at this index.
+ if (table[witnessIndex]) {
+ warning(0, "generic witness table at %p contains duplicate entry for "
+ "requirement descriptor %p",
+ genericTable, reqDescriptor);
+ }
+#endif
+
+ table[witnessIndex] = witness.Witness.get();
+ }
+
+ // Loop over the requirements, filling in default implementations where
+ // needed.
+ for (size_t i = 0, e = protocol->NumRequirements; i < e; ++i) {
+ unsigned witnessIndex = WitnessTableFirstRequirementOffset + i;
+
+ // If we already have a witness, there's nothing to do.
+ if (table[witnessIndex])
+ continue;
+
+ // Otherwise, fill in a default implementation.
+ auto &reqt = requirements[i];
void *impl = reqt.DefaultImplementation.get();
- // Find the witness if there is one, otherwise we use the default.
- for (auto &witness : witnesses) {
- if (witness.Requirement.get() == &reqt) {
- impl = witness.Witness.get();
- break;
- }
+#if !NDEBUG
+ // For debug builds, warn if we don't have a default implementation.
+ if (!impl) {
+ warning(0, "generic witness table at %p missing an entry for "
+ "requirement descriptor %p", genericTable,
+ requirements.begin() + i);
}
+#endif
- assert(impl != nullptr && "no implementation for witness");
-
- unsigned witnessIndex = WitnessTableFirstRequirementOffset + i;
table[witnessIndex] = impl;
}
}
@@ -3716,8 +3744,7 @@
}
// Fill in any default requirements.
- if (genericTable->ResilientWitnesses)
- initializeResilientWitnessTable(genericTable, table);
+ initializeResilientWitnessTable(genericTable, table);
auto castTable = reinterpret_cast<WitnessTable*>(table);
diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt
index 35fe8a3..57244a9 100644
--- a/test/Demangle/Inputs/manglings.txt
+++ b/test/Demangle/Inputs/manglings.txt
@@ -332,3 +332,4 @@
$S1T19protocol_resilience17ResilientProtocolPTl --> associated type descriptor for T
$S18resilient_protocol21ResilientBaseProtocolTL --> protocol requirements base descriptor for resilient_protocol.ResilientBaseProtocol
$S1t1PP10AssocType2_AA1QTn --> associated conformance descriptor for t.P.AssocType2: t.Q
+$S1t1PP10AssocType2_AA1QTN --> default associated conformance accessor for t.P.AssocType2: t.Q
diff --git a/test/IRGen/abi_v7k.swift b/test/IRGen/abi_v7k.swift
index 2bb0163..d4b1af0 100644
--- a/test/IRGen/abi_v7k.swift
+++ b/test/IRGen/abi_v7k.swift
@@ -270,10 +270,10 @@
// double in d0, i32 in r0, return in d0,...,d3
// V7K: vmov [[ID:s[0-9]+]], r0
// V7K: vcvt.f64.s32 [[ID2:d[0-9]+]], [[ID]]
-// V7K: vstr d0, [sp]
+// V7K: vstr d0, [sp, #8]
// V7K: vmov.f64 d0, [[ID2]]
// V7K: bl
-// V7K: vldr [[ID3:d[0-9]+]], [sp]
+// V7K: vldr [[ID3:d[0-9]+]], [sp, #8]
// V7K: vmov.f64 d2, [[ID3]]
func testRet2(w : Double, i : Int) -> MyRect {
var r = MyRect(x : Double(i), y : 2.0, w : 3.0, h : 4.0)
diff --git a/test/IRGen/protocol_resilience_descriptors.swift b/test/IRGen/protocol_resilience_descriptors.swift
index 7dd512e..5f6c8ca 100644
--- a/test/IRGen/protocol_resilience_descriptors.swift
+++ b/test/IRGen/protocol_resilience_descriptors.swift
@@ -14,6 +14,7 @@
// Protocol descriptor
// CHECK-DEFINITION-LABEL: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsMp" ={{( protected)?}} constant
+// CHECK-DEFINITION-SAME: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0TN"
// CHECK-DEFINITION-SAME: $S2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPTM
// CHECK-DEFINITION-SAME: $S2T218resilient_protocol29ProtocolWithAssocTypeDefaultsPTM
@@ -25,6 +26,9 @@
// CHECK-DEFINITION: @"$S1T18resilient_protocol24ProtocolWithRequirementsPTl" ={{( dllexport)?}}{{( protected)?}} alias
// CHECK-DEFINITION: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0Tn" ={{( dllexport)?}}{{( protected)?}} alias
+// Default associated conformance witnesses
+// CHECK-DEFINITION-LABEL: define internal swiftcc i8** @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0TN"
+
// Default associated type witnesses
// CHECK-DEFINITION-LABEL: define internal swiftcc %swift.metadata_response @"$S2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPTM"
@@ -32,6 +36,8 @@
// CHECK-DEFINITION: getelementptr inbounds i8*, i8** [[WTABLE:%.*]], i32 2
// CHECK-DEFINITION: call{{.*}}S18resilient_protocol7WrapperVMa
+// CHECK-DEFINITION-LABEL: define internal swiftcc %swift.metadata_response @"$S9AssocType18resilient_protocol20ResilientSelfDefaultPTM
+
import resilient_protocol
// ----------------------------------------------------------------------------
@@ -51,6 +57,12 @@
public struct ConditionallyConforms<Element> { }
public struct Y { }
+// CHECK-USAGE: @"$S31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAAWr" = internal
+// CHECK-USAGE-SAME: $S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0Tn
+// CHECK-USAGE-SAME: $S31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAA2T2_AD014OtherResilientI0PWT
+public struct ConformsWithAssocRequirements : ProtocolWithAssocTypeDefaults {
+}
+
// CHECK-USAGE: @"$Sx1T_MXA" =
// CHECK-USAGE-SAME: i32 0
// CHECK-USAGE-SAME: @"{{got.|__imp_}}$S18resilient_protocol24ProtocolWithRequirementsMp"
diff --git a/test/Inputs/resilient_protocol.swift b/test/Inputs/resilient_protocol.swift
index e6dfcb8..9a93674 100644
--- a/test/Inputs/resilient_protocol.swift
+++ b/test/Inputs/resilient_protocol.swift
@@ -34,3 +34,7 @@
associatedtype T1 = Self
associatedtype T2: OtherResilientProtocol = Wrapper<T1>
}
+
+public protocol ResilientSelfDefault : ResilientBaseProtocol {
+ associatedtype AssocType: ResilientBaseProtocol = Self
+}
diff --git a/test/Parse/raw_string.swift b/test/Parse/raw_string.swift
index 953b923..d96ba2f 100644
--- a/test/Parse/raw_string.swift
+++ b/test/Parse/raw_string.swift
@@ -132,3 +132,6 @@
]
"""#
// CHECK: "[\n {\n \"id\": \"12345\",\n \"title\": \"A title that \\\"contains\\\" \\\\\\\"\"\n }\n]"
+
+_ = #"# #"#
+// CHECK: "# #"
diff --git a/test/Parse/raw_string_errors.swift b/test/Parse/raw_string_errors.swift
index ca19b41..0ba693f 100644
--- a/test/Parse/raw_string_errors.swift
+++ b/test/Parse/raw_string_errors.swift
@@ -1,14 +1,24 @@
// RUN: %target-typecheck-verify-swift
-#"\##("invalid")"#
+let _ = "foo\(#"bar"##)baz"
+// expected-error@-1{{too many '#' characters in closing delimiter}}
+// expected-error@-2{{expected ',' separator}}
+// expected-error@-3{{expected expression in list of expressions}}
+
+let _ = #"\##("invalid")"#
// expected-error@-1{{too many '#' characters in delimited escape}}
// expected-error@-2{{invalid escape sequence in literal}}
-####"invalid"###
+let _ = ####"invalid"###
// expected-error@-1{{unterminated string literal}}
-###"invalid"####
-// expected-error@-1{{too many '#' characters in closing delimiter}}
+let _ = ###"invalid"######
+// expected-error@-1{{too many '#' characters in closing delimiter}}{{24-27=}}
// expected-error@-2{{consecutive statements on a line must be separated by ';'}}
// expected-error@-3{{expected expression}}
-// expected-warning@-4{{string literal is unused}}
+
+let _ = ##"""##
+ foobar
+ ##"""##
+// expected-error@-3{{multi-line string literal content must begin on a new line}}{{14-14=\n}}
+// expected-error@-2{{multi-line string literal closing delimiter must begin on a new line}}{{5-5=\n}}
diff --git a/test/Parse/string_literal_eof1.swift b/test/Parse/string_literal_eof1.swift
new file mode 100644
index 0000000..accc6a0
--- /dev/null
+++ b/test/Parse/string_literal_eof1.swift
@@ -0,0 +1,5 @@
+// RUN: %target-typecheck-verify-swift
+
+// NOTE: DO NOT add a newline at EOF.
+// expected-error@+1 {{unterminated string literal}}
+_ = "foo\(
\ No newline at end of file
diff --git a/test/Parse/string_literal_eof2.swift b/test/Parse/string_literal_eof2.swift
new file mode 100644
index 0000000..c049557
--- /dev/null
+++ b/test/Parse/string_literal_eof2.swift
@@ -0,0 +1,5 @@
+// RUN: %target-typecheck-verify-swift
+
+// NOTE: DO NOT add a newline at EOF.
+// expected-error@+1 {{unterminated string literal}}
+_ = "foo\("bar
\ No newline at end of file
diff --git a/test/Parse/string_literal_eof3.swift b/test/Parse/string_literal_eof3.swift
new file mode 100644
index 0000000..a5425e6
--- /dev/null
+++ b/test/Parse/string_literal_eof3.swift
@@ -0,0 +1,10 @@
+// RUN: %target-typecheck-verify-swift
+
+// expected-error@+2 {{unterminated string literal}}
+// expected-error@+1 {{invalid escape sequence in literal}}
+_ = "foo \
+
+// NOTE: DO NOT add a newline at EOF.
+// expected-error@+2 {{unterminated string literal}}
+// expected-error@+1 {{invalid escape sequence in literal}}
+_ = "foo \
\ No newline at end of file
diff --git a/test/SIL/Parser/default_witness_tables.sil b/test/SIL/Parser/default_witness_tables.sil
index bb1b8e9..8153e21 100644
--- a/test/SIL/Parser/default_witness_tables.sil
+++ b/test/SIL/Parser/default_witness_tables.sil
@@ -48,7 +48,7 @@
// CHECK-LABEL: sil_default_witness_table ResilientProtocol {
-// CHECK: no_default
+// CHECK: associated_type_protocol (T: Proto): Wrapper<Self>: specialize <Self> (<T> Wrapper<T>: Proto module witness_tables)
// CHECK: associated_type T: Wrapper<Self>
// CHECK: no_default
// CHECK: no_default
@@ -58,7 +58,7 @@
// CHECK: }
sil_default_witness_table ResilientProtocol {
- no_default
+ associated_type_protocol (T: Proto): Wrapper<Self>: specialize <Self> (<T> Wrapper<T>: Proto module witness_tables)
associated_type T: Wrapper<Self>
no_default
no_default
diff --git a/test/SILGen/protocol_resilience.swift b/test/SILGen/protocol_resilience.swift
index e930bfb..e75df7e 100644
--- a/test/SILGen/protocol_resilience.swift
+++ b/test/SILGen/protocol_resilience.swift
@@ -251,6 +251,13 @@
inoutFunc(&OtherConformingType.staticPropertyInExtension)
}
+// Protocol is public -- needs resilient witness table
+public struct ConformsToP: P { }
+
+public protocol ResilientAssocTypes {
+ associatedtype AssocType: P = ConformsToP
+}
+
// CHECK-LABEL: sil_default_witness_table P {
// CHECK-NEXT: }
@@ -312,3 +319,8 @@
// CHECK-NEXT: method #ReabstractSelfRefined.callback!setter.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvs
// CHECK-NEXT: method #ReabstractSelfRefined.callback!modify.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvM
// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_default_witness_table ResilientAssocTypes {
+// CHECK-NEXT: associated_type_protocol (AssocType: P): ConformsToP: P module protocol_resilience
+// CHECK-NEXT: associated_type AssocType: ConformsToP
+// CHECK-NEXT: }
diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift
index 34e9637..5ae49f9 100644
--- a/test/api-digester/Inputs/cake.swift
+++ b/test/api-digester/Inputs/cake.swift
@@ -40,4 +40,11 @@
public extension Int {
public func foo() {}
-}
\ No newline at end of file
+}
+
+@_fixed_layout
+public struct fixedLayoutStruct {
+ public var a = 1
+ private var b = 2
+ var c = 3
+}
diff --git a/test/api-digester/Inputs/cake1.swift b/test/api-digester/Inputs/cake1.swift
index 7ec7e43..a3351b0 100644
--- a/test/api-digester/Inputs/cake1.swift
+++ b/test/api-digester/Inputs/cake1.swift
@@ -47,3 +47,17 @@
public extension P1 where Self: P2 {
func P1Constraint() {}
}
+
+@_fixed_layout
+public struct fixedLayoutStruct {
+ public var b = 2
+ public func foo() {}
+ public var a = 1
+}
+
+@_frozen
+public enum FrozenKind {
+ case Unchanged
+ case Fixed
+ case Rigid
+}
\ No newline at end of file
diff --git a/test/api-digester/Inputs/cake2.swift b/test/api-digester/Inputs/cake2.swift
index 651ac79..da3fe96 100644
--- a/test/api-digester/Inputs/cake2.swift
+++ b/test/api-digester/Inputs/cake2.swift
@@ -47,3 +47,22 @@
public extension P1 {
func P1Constraint() {}
}
+
+@_fixed_layout
+public struct fixedLayoutStruct {
+ public var a = 1
+ public func OKChange() {}
+ private static let constant = 0
+ public var b = 2
+ public func foo() {}
+ private var c = 3
+ private lazy var lazy_d = 4
+}
+
+@_frozen
+public enum FrozenKind {
+ case Unchanged
+ case Rigid
+ case Fixed
+ case AddedCase
+}
\ No newline at end of file
diff --git a/test/api-digester/Outputs/Cake-abi.txt b/test/api-digester/Outputs/Cake-abi.txt
index 093eff1..d162bc6 100644
--- a/test/api-digester/Outputs/Cake-abi.txt
+++ b/test/api-digester/Outputs/Cake-abi.txt
@@ -6,6 +6,7 @@
/* Removed Decls */
cake1: Constructor Somestruct2.init(_:) has been removed
+cake1: Constructor fixedLayoutStruct.init(b:a:) has been removed
cake1: Func C4.foo() has been removed
/* Moved Decls */
@@ -29,3 +30,12 @@
cake1: Struct C6 is now with @_fixed_layout
cake1: Var C1.CIIns1 changes from weak to strong
cake1: Var C1.CIIns2 changes from strong to weak
+
+/* Fixed-layout Type changes */
+cake1: EnumElement FrozenKind.Fixed in a non-resilient type changes position from 1 to 2
+cake1: EnumElement FrozenKind.Rigid in a non-resilient type changes position from 2 to 1
+cake1: Var fixedLayoutStruct.a in a non-resilient type changes position from 1 to 0
+cake1: Var fixedLayoutStruct.b in a non-resilient type changes position from 0 to 1
+cake2: EnumElement FrozenKind.AddedCase is added to a non-resilient type
+cake2: Var fixedLayoutStruct.c is added to a non-resilient type
+cake2: Var fixedLayoutStruct.lazy_d.storage is added to a non-resilient type
\ No newline at end of file
diff --git a/test/api-digester/Outputs/Cake.txt b/test/api-digester/Outputs/Cake.txt
index e46efe9..92857e0 100644
--- a/test/api-digester/Outputs/Cake.txt
+++ b/test/api-digester/Outputs/Cake.txt
@@ -6,6 +6,7 @@
/* Removed Decls */
cake1: Constructor Somestruct2.init(_:) has been removed
+cake1: Constructor fixedLayoutStruct.init(b:a:) has been removed
cake1: Func C4.foo() has been removed
/* Moved Decls */
diff --git a/test/api-digester/Outputs/cake-abi.json b/test/api-digester/Outputs/cake-abi.json
index 3a068eb..b980795 100644
--- a/test/api-digester/Outputs/cake-abi.json
+++ b/test/api-digester/Outputs/cake-abi.json
@@ -95,6 +95,7 @@
"usr": "s:4cake2S1VACycfc",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -125,6 +126,7 @@
"location": "",
"moduleName": "cake",
"genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -241,6 +243,7 @@
"usr": "s:4cake2C1C3InsACSgXwvg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -269,6 +272,7 @@
"usr": "s:4cake2C1C3InsACSgXwvs",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -323,6 +327,7 @@
"usr": "s:4cake2C1C4Ins2ACXovg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -343,6 +348,7 @@
"usr": "s:4cake2C1C4Ins2ACXovs",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -370,6 +376,7 @@
"usr": "s:4cake2C1CACycfc",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -462,6 +469,7 @@
"usr": "s:4cake6NumberO3oneyA2CmF",
"location": "",
"moduleName": "cake",
+ "fixedbinaryorder": 0,
"children": [
{
"kind": "TypeFunc",
@@ -499,6 +507,7 @@
"usr": "s:4cake6NumberO8RawValuea",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -516,6 +525,7 @@
"usr": "s:4cake6NumberO9hashValueSivp",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -531,6 +541,7 @@
"usr": "s:4cake6NumberO9hashValueSivg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -550,6 +561,7 @@
"usr": "s:4cake6NumberO4hash4intoys6HasherVz_tF",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -572,6 +584,7 @@
"usr": "s:4cake6NumberO8rawValueACSgSi_tcfc",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Inlinable"
],
@@ -606,6 +619,7 @@
"usr": "s:4cake6NumberO8rawValueSivp",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -621,6 +635,7 @@
"usr": "s:4cake6NumberO8rawValueSivg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Inlinable"
],
@@ -675,6 +690,281 @@
},
{
"kind": "TypeDecl",
+ "name": "fixedLayoutStruct",
+ "printedName": "fixedLayoutStruct",
+ "declKind": "Struct",
+ "usr": "s:4cake17fixedLayoutStructV",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "FixedLayout"
+ ],
+ "children": [
+ {
+ "kind": "Var",
+ "name": "a",
+ "printedName": "a",
+ "declKind": "Var",
+ "usr": "s:4cake17fixedLayoutStructV1aSivp",
+ "location": "",
+ "moduleName": "cake",
+ "fixedbinaryorder": 0,
+ "declAttributes": [
+ "HasInitialValue"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1aSivg",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Setter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1aSivs",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "mutating": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Var",
+ "name": "b",
+ "printedName": "b",
+ "declKind": "Var",
+ "usr": "s:4cake17fixedLayoutStructV1b33_3D8926C30F7417F2EF9A277D0C73FBDBLLSivp",
+ "location": "",
+ "moduleName": "cake",
+ "fixedbinaryorder": 1,
+ "declAttributes": [
+ "HasInitialValue"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1b33_3D8926C30F7417F2EF9A277D0C73FBDBLLSivg",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Setter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1b33_3D8926C30F7417F2EF9A277D0C73FBDBLLSivs",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "mutating": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Var",
+ "name": "c",
+ "printedName": "c",
+ "declKind": "Var",
+ "usr": "s:4cake17fixedLayoutStructV1cSivp",
+ "location": "",
+ "moduleName": "cake",
+ "fixedbinaryorder": 2,
+ "declAttributes": [
+ "HasInitialValue"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1cSivg",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Setter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1cSivs",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "mutating": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init(a:b:c:)",
+ "declKind": "Constructor",
+ "usr": "s:4cake17fixedLayoutStructV1a1b1cACSi_S2itc33_3D8926C30F7417F2EF9A277D0C73FBDBLlfc",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "fixedLayoutStruct",
+ "printedName": "fixedLayoutStruct",
+ "usr": "s:4cake17fixedLayoutStructV"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init()",
+ "declKind": "Constructor",
+ "usr": "s:4cake17fixedLayoutStructVACycfc",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "fixedLayoutStruct",
+ "printedName": "fixedLayoutStruct",
+ "usr": "s:4cake17fixedLayoutStructV"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "TypeDecl",
"name": "Int",
"printedName": "Int",
"declKind": "Struct",
diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json
index 56af1b7..994ab4e 100644
--- a/test/api-digester/Outputs/cake.json
+++ b/test/api-digester/Outputs/cake.json
@@ -102,6 +102,7 @@
"usr": "s:4cake2S1VACycfc",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -132,6 +133,7 @@
"location": "",
"moduleName": "cake",
"genericSig": "<T1, T2, T3>",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -248,6 +250,7 @@
"usr": "s:4cake2C1C3InsACSgXwvg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -276,6 +279,7 @@
"usr": "s:4cake2C1C3InsACSgXwvs",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -330,6 +334,7 @@
"usr": "s:4cake2C1C4Ins2ACXovg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -350,6 +355,7 @@
"usr": "s:4cake2C1C4Ins2ACXovs",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Transparent"
],
@@ -377,6 +383,7 @@
"usr": "s:4cake2C1CACycfc",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -469,6 +476,7 @@
"usr": "s:4cake6NumberO3oneyA2CmF",
"location": "",
"moduleName": "cake",
+ "fixedbinaryorder": 0,
"children": [
{
"kind": "TypeFunc",
@@ -513,6 +521,7 @@
"usr": "s:4cake6NumberO8RawValuea",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -530,6 +539,7 @@
"usr": "s:4cake6NumberO9hashValueSivp",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -545,6 +555,7 @@
"usr": "s:4cake6NumberO9hashValueSivg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -564,6 +575,7 @@
"usr": "s:4cake6NumberO4hash4intoys6HasherVz_tF",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -586,6 +598,7 @@
"usr": "s:4cake6NumberO8rawValueACSgSi_tcfc",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Inlinable"
],
@@ -620,6 +633,7 @@
"usr": "s:4cake6NumberO8rawValueSivp",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"children": [
{
"kind": "TypeNominal",
@@ -635,6 +649,7 @@
"usr": "s:4cake6NumberO8rawValueSivg",
"location": "",
"moduleName": "cake",
+ "implicit": true,
"declAttributes": [
"Inlinable"
],
@@ -689,6 +704,143 @@
},
{
"kind": "TypeDecl",
+ "name": "fixedLayoutStruct",
+ "printedName": "fixedLayoutStruct",
+ "declKind": "Struct",
+ "usr": "s:4cake17fixedLayoutStructV",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "FixedLayout"
+ ],
+ "children": [
+ {
+ "kind": "Var",
+ "name": "a",
+ "printedName": "a",
+ "declKind": "Var",
+ "usr": "s:4cake17fixedLayoutStructV1aSivp",
+ "location": "",
+ "moduleName": "cake",
+ "fixedbinaryorder": 0,
+ "declAttributes": [
+ "HasInitialValue"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1aSivg",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Setter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake17fixedLayoutStructV1aSivs",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "mutating": true,
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init(a:b:c:)",
+ "declKind": "Constructor",
+ "usr": "s:4cake17fixedLayoutStructV1a1b1cACSi_S2itc33_3D8926C30F7417F2EF9A277D0C73FBDBLlfc",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "fixedLayoutStruct",
+ "printedName": "fixedLayoutStruct",
+ "usr": "s:4cake17fixedLayoutStructV"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init()",
+ "declKind": "Constructor",
+ "usr": "s:4cake17fixedLayoutStructVACycfc",
+ "location": "",
+ "moduleName": "cake",
+ "implicit": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "fixedLayoutStruct",
+ "printedName": "fixedLayoutStruct",
+ "usr": "s:4cake17fixedLayoutStructV"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "TypeDecl",
"name": "Int",
"printedName": "Int",
"declKind": "Struct",
diff --git a/test/api-digester/Outputs/clang-module-dump.txt b/test/api-digester/Outputs/clang-module-dump.txt
index c26a73a..46c293e 100644
--- a/test/api-digester/Outputs/clang-module-dump.txt
+++ b/test/api-digester/Outputs/clang-module-dump.txt
@@ -54,6 +54,7 @@
"usr": "c:objc(cs)NSObject(im)init",
"location": "",
"moduleName": "Foo",
+ "implicit": true,
"declAttributes": [
"Override",
"ObjC"
diff --git a/test/api-digester/apinotes-diags.swift b/test/api-digester/apinotes-diags.swift
index 4e64c05..6a7b06d 100644
--- a/test/api-digester/apinotes-diags.swift
+++ b/test/api-digester/apinotes-diags.swift
@@ -6,6 +6,12 @@
// RUN: %api-digester %clang-importer-sdk-nosource -dump-sdk -module APINotesTest -o %t.dump2.json -module-cache-path %t.module-cache -swift-version 3 -I %S/Inputs/APINotesRight
// RUN: %api-digester %clang-importer-sdk-nosource -dump-sdk -module APINotesTest -o %t.dump3.json -module-cache-path %t.module-cache -swift-version 4 -I %S/Inputs/APINotesRight
// RUN: %api-digester -diagnose-sdk -print-module -input-paths %t.dump1.json -input-paths %t.dump3.json > %t.result
-// RUN: diff -u %S/Outputs/apinotes-diags.txt %t.result
+
+// RUN: %clang -E -P -x c %S/Outputs/apinotes-diags.txt -o - | sed '/^\s*$/d' > %t.expected
+// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
+// RUN: diff -u %t.expected %t.result.tmp
+
// RUN: %api-digester -diagnose-sdk -print-module -input-paths %t.dump2.json -input-paths %t.dump3.json > %t.result
-// RUN: diff -u %S/Outputs/apinotes-diags-3-4.txt %t.result
+// RUN: %clang -E -P -x c %S/Outputs/apinotes-diags-3-4.txt -o - | sed '/^\s*$/d' > %t.expected
+// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
+// RUN: diff -u %t.expected %t.result.tmp
diff --git a/test/api-digester/compare-dump.swift b/test/api-digester/compare-dump.swift
index 3a8b92a..e70f166 100644
--- a/test/api-digester/compare-dump.swift
+++ b/test/api-digester/compare-dump.swift
@@ -6,9 +6,15 @@
// RUN: %api-digester -dump-sdk -module cake1 -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod -I %S/Inputs/APINotesLeft
// RUN: %api-digester -dump-sdk -module cake2 -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod -I %S/Inputs/APINotesRight
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json > %t.result
-// RUN: diff -u %S/Outputs/Cake.txt %t.result
+
+// RUN: %clang -E -P -x c %S/Outputs/Cake.txt -o - | sed '/^\s*$/d' > %t.expected
+// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
+// RUN: diff -u %t.expected %t.result.tmp
// RUN: %api-digester -dump-sdk -module cake1 -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod -I %S/Inputs/APINotesLeft -abi
// RUN: %api-digester -dump-sdk -module cake2 -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod -I %S/Inputs/APINotesRight -abi
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -abi > %t.result
-// RUN: diff -u %S/Outputs/Cake-abi.txt %t.result
+
+// RUN: %clang -E -P -x c %S/Outputs/Cake-abi.txt -o - | sed '/^\s*$/d' > %t.expected
+// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
+// RUN: diff -u %t.expected %t.result.tmp
diff --git a/test/decl/protocol/resilient_defaults.swift b/test/decl/protocol/resilient_defaults.swift
new file mode 100644
index 0000000..b959241
--- /dev/null
+++ b/test/decl/protocol/resilient_defaults.swift
@@ -0,0 +1,18 @@
+// RUN: %target-typecheck-verify-swift -enable-resilience
+
+public struct Wrapper<T: P>: P { }
+extension Wrapper: Q where T: Q { }
+
+public protocol PBase {
+ associatedtype AssocType
+}
+
+public protocol P: PBase {
+ override associatedtype AssocType: P = Wrapper<Self>
+ // expected-note@-1{{associated type 'AssocType' has default type 'Wrapper<Self>' written here}}
+}
+
+public protocol Q: P where Self.AssocType: Q { }
+
+public protocol R: Q where Self.AssocType: R { }
+// expected-warning@-1{{default type 'Wrapper<Self>' for associated type 'AssocType' does not satisfy constraint 'Self.AssocType': 'R'}}
diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift
index 4a38054..85b1a62 100644
--- a/test/expr/expressions.swift
+++ b/test/expr/expressions.swift
@@ -505,6 +505,9 @@
_ = 'ab\nc' // expected-error{{single-quoted string literal found, use '"'}}{{7-14="ab\\nc"}}
_ = "abc\('def')" // expected-error{{single-quoted string literal found, use '"'}}{{13-18="def"}}
+ _ = 'ab\("c")' // expected-error{{single-quoted string literal found, use '"'}}{{7-17="ab\\("c")"}}
+ _ = 'a\('b')c' // expected-error{{single-quoted string literal found, use '"'}}{{7-17="a\\('b')c"}}
+ // expected-error@-1{{single-quoted string literal found, use '"'}}{{11-14="b"}}
_ = "abc' // expected-error{{unterminated string literal}}
_ = 'abc" // expected-error{{unterminated string literal}}
diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp
index 396f6bd..2430cc9 100644
--- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp
+++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp
@@ -42,11 +42,13 @@
StringRef USR;
StringRef Location;
StringRef ModuleName;
+ bool IsImplicit = false;
bool IsThrowing = false;
bool IsMutating = false;
bool IsStatic = false;
bool IsDeprecated = false;
Optional<uint8_t> SelfIndex;
+ Optional<unsigned> FixedBinaryOrder;
ReferenceOwnership ReferenceOwnership = ReferenceOwnership::Strong;
std::vector<DeclAttrKind> DeclAttrs;
std::vector<TypeAttrKind> TypeAttrs;
@@ -81,8 +83,8 @@
SDKNodeDecl::SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind)
: SDKNode(Info, Kind), DKind(Info.DKind), Usr(Info.USR),
Location(Info.Location), ModuleName(Info.ModuleName),
- DeclAttributes(Info.DeclAttrs), IsStatic(Info.IsStatic),
- IsDeprecated(Info.IsDeprecated),
+ DeclAttributes(Info.DeclAttrs), IsImplicit(Info.IsImplicit),
+ IsStatic(Info.IsStatic), IsDeprecated(Info.IsDeprecated),
ReferenceOwnership(uint8_t(Info.ReferenceOwnership)),
GenericSig(Info.GenericSig) {}
@@ -108,7 +110,8 @@
SDKNodeDecl(Info, SDKNodeKind::DeclTypeAlias) {}
SDKNodeDeclVar::SDKNodeDeclVar(SDKNodeInitInfo Info):
- SDKNodeDecl(Info, SDKNodeKind::DeclVar) {}
+ SDKNodeDecl(Info, SDKNodeKind::DeclVar),
+ FixedBinaryOrder(Info.FixedBinaryOrder) {}
SDKNodeDeclAbstractFunc::SDKNodeDeclAbstractFunc(SDKNodeInitInfo Info,
SDKNodeKind Kind): SDKNodeDecl(Info, Kind), IsThrowing(Info.IsThrowing),
@@ -153,8 +156,10 @@
}
}
-unsigned SDKNode::getChildIndex(NodePtr Child) const {
- return std::find(Children.begin(), Children.end(), Child) - Children.begin();
+unsigned SDKNode::getChildIndex(const SDKNode* Child) const {
+ auto It = std::find(Children.begin(), Children.end(), Child);
+ assert(It != Children.end() && "cannot find the child");
+ return It - Children.begin();
}
SDKNode* SDKNode::getOnlyChild() const {
@@ -503,6 +508,9 @@
case KeyKind::KK_selfIndex:
Info.SelfIndex = getAsInt(Pair.getValue());
break;
+ case KeyKind::KK_fixedbinaryorder:
+ Info.FixedBinaryOrder = getAsInt(Pair.getValue());
+ break;
case KeyKind::KK_usr:
Info.USR = GetScalarString(Pair.getValue());
break;
@@ -555,6 +563,9 @@
case KeyKind::KK_deprecated:
Info.IsDeprecated = true;
break;
+ case KeyKind::KK_implicit:
+ Info.IsImplicit = true;
+ break;
case KeyKind::KK_ownership:
Info.ReferenceOwnership =
swift::ReferenceOwnership(getAsInt(Pair.getValue()));
@@ -671,8 +682,24 @@
return false;
LLVM_FALLTHROUGH;
}
+
+ case SDKNodeKind::DeclVar: {
+ if (getSDKContext().checkingABI()) {
+ // If we're checking ABI, the definition order matters.
+ // If they're both members for fixed layout types, we never consider
+ // them equal because we need to check definition orders.
+ if (auto *LV = dyn_cast<SDKNodeDeclVar>(this)) {
+ if (auto *RV = dyn_cast<SDKNodeDeclVar>(&Other)) {
+ if (LV->hasFixedBinaryOrder() && RV->hasFixedBinaryOrder()) {
+ if (LV->getFixedBinaryOrder() != RV->getFixedBinaryOrder())
+ return false;
+ }
+ }
+ }
+ }
+ LLVM_FALLTHROUGH;
+ }
case SDKNodeKind::DeclType:
- case SDKNodeKind::DeclVar:
case SDKNodeKind::DeclTypeAlias: {
auto Left = this->getAs<SDKNodeDecl>();
auto Right = (&Other)->getAs<SDKNodeDecl>();
@@ -684,6 +711,7 @@
return false;
if (Left->getGenericSignature() != Right->getGenericSignature())
return false;
+
LLVM_FALLTHROUGH;
}
case SDKNodeKind::Root: {
@@ -902,6 +930,39 @@
return StringRef();
}
+static Optional<unsigned> getFixedBinaryOrder(ValueDecl *VD) {
+ auto D = VD->getDeclContext()->getAsDecl();
+ if (!D)
+ return None;
+
+ if (auto *ED = dyn_cast<EnumDecl>(D)) {
+ auto Check = [](Decl *M) {
+ return isa<EnumElementDecl>(M);
+ };
+ if (!ED->isResilient() && Check(VD)) {
+ auto Members = ED->getMembers();
+ auto End = std::find(Members.begin(), Members.end(), VD);
+ assert(End != Members.end());
+ return std::count_if(Members.begin(), End, Check);
+ }
+ }
+ if (auto *SD = dyn_cast<StructDecl>(D)) {
+ auto Check = [](Decl *M) {
+ if (auto *STD = dyn_cast<AbstractStorageDecl>(M)) {
+ return STD->hasStorage() && !STD->isStatic();
+ }
+ return false;
+ };
+ if (!SD->isResilient() && Check(VD)) {
+ auto Members = SD->getMembers();
+ auto End = std::find(Members.begin(), Members.end(), VD);
+ assert(End != Members.end());
+ return std::count_if(Members.begin(), End, Check);
+ }
+ }
+ return llvm::None;
+}
+
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Type Ty,
TypeInitInfo TypeInfo) :
Ctx(Ctx), Name(getTypeName(Ctx, Ty, TypeInfo.IsImplicitlyUnwrappedOptional)),
@@ -921,10 +982,12 @@
PrintedName(getPrintedName(Ctx, VD)), DKind(VD->getKind()),
USR(calculateUsr(Ctx, VD)), Location(calculateLocation(Ctx, VD)),
ModuleName(VD->getModuleContext()->getName().str()),
+ IsImplicit(VD->isImplicit()),
IsThrowing(isFuncThrowing(VD)), IsMutating(isFuncMutating(VD)),
IsStatic(VD->isStatic()),
IsDeprecated(VD->getAttrs().getDeprecated(VD->getASTContext())),
- SelfIndex(getSelfIndex(VD)), ReferenceOwnership(getReferenceOwnership(VD)),
+ SelfIndex(getSelfIndex(VD)), FixedBinaryOrder(getFixedBinaryOrder(VD)),
+ ReferenceOwnership(getReferenceOwnership(VD)),
GenericSig(printGenericSignature(Ctx, VD)) {
// Calculate usr for its super class.
@@ -1054,7 +1117,7 @@
return Func;
}
-static bool shouldIgnore(Decl *D, const Decl* Parent) {
+static bool shouldIgnore(Decl *D, const Decl* Parent, SDKContext &Ctx) {
if (D->isPrivateStdlibDecl(false))
return true;
if (AvailableAttr::isUnavailable(D))
@@ -1072,6 +1135,10 @@
case AccessLevel::Internal:
case AccessLevel::Private:
case AccessLevel::FilePrivate:
+ // Private vars with fixed binary orders can have ABI-impact, so we should
+ // whitelist them if we're checking ABI.
+ if (Ctx.checkingABI() && getFixedBinaryOrder(VD).hasValue())
+ break;
return true;
case AccessLevel::Public:
case AccessLevel::Open:
@@ -1153,7 +1220,7 @@
IterableDeclContext *Context,
std::set<ExtensionDecl*> &HandledExts) {
for (auto *Member : Context->getMembers()) {
- if (shouldIgnore(Member, Context->getDecl()))
+ if (shouldIgnore(Member, Context->getDecl(), Ctx))
continue;
if (auto Func = dyn_cast<FuncDecl>(Member)) {
Root->addChild(constructFunctionNode(Ctx, Func, SDKNodeKind::DeclFunction));
@@ -1182,7 +1249,7 @@
llvm::SmallVector<Decl*, 512> Decls;
M->getDisplayDecls(Decls);
for (auto D : Decls) {
- if (shouldIgnore(D, nullptr))
+ if (shouldIgnore(D, nullptr, Ctx))
continue;
if (KnownDecls.count(D))
continue;
@@ -1300,6 +1367,16 @@
if (bool isDeprecated = D->isDeprecated())
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_deprecated).data(),
isDeprecated);
+ if (bool isImplicit = D->isImplicit())
+ out.mapRequired(getKeyContent(Ctx, KeyKind::KK_implicit).data(),
+ isImplicit);
+ if (auto V = dyn_cast<SDKNodeDeclVar>(value)) {
+ if (V->hasFixedBinaryOrder()) {
+ auto Order = V->getFixedBinaryOrder();
+ out.mapRequired(getKeyContent(Ctx, KeyKind::KK_fixedbinaryorder).data(),
+ Order);
+ }
+ }
if (auto F = dyn_cast<SDKNodeDeclAbstractFunc>(value)) {
if (bool isThrowing = F->isThrowing())
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_throwing).data(),
diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.h b/tools/swift-api-digester/ModuleAnalyzerNodes.h
index 11eac7f..660af51 100644
--- a/tools/swift-api-digester/ModuleAnalyzerNodes.h
+++ b/tools/swift-api-digester/ModuleAnalyzerNodes.h
@@ -220,7 +220,6 @@
std::set<NodeAnnotation> Annotations;
std::map<NodeAnnotation, StringRef> AnnotateComments;
NodePtr Parent = nullptr;
-
protected:
SDKNode(SDKNodeInitInfo Info, SDKNodeKind Kind);
@@ -253,7 +252,7 @@
void addChild(SDKNode *Child);
ArrayRef<SDKNode*> getChildren() const;
bool hasSameChildren(const SDKNode &Other) const;
- unsigned getChildIndex(NodePtr Child) const;
+ unsigned getChildIndex(const SDKNode *Child) const;
SDKNode* getOnlyChild() const;
SDKContext &getSDKContext() const { return Ctx; }
SDKNodeRoot *getRootNode() const;
@@ -275,6 +274,7 @@
StringRef Location;
StringRef ModuleName;
std::vector<DeclAttrKind> DeclAttributes;
+ bool IsImplicit;
bool IsStatic;
bool IsDeprecated;
uint8_t ReferenceOwnership;
@@ -301,6 +301,7 @@
bool isSDKPrivate() const;
bool isDeprecated() const { return IsDeprecated; };
bool hasDeclAttribute(DeclAttrKind DAKind) const;
+ bool isImplicit() const { return IsImplicit; };
bool isStatic() const { return IsStatic; };
StringRef getGenericSignature() const { return GenericSig; }
StringRef getScreenInfo() const;
@@ -440,9 +441,12 @@
};
class SDKNodeDeclVar : public SDKNodeDecl {
+ Optional<unsigned> FixedBinaryOrder;
public:
SDKNodeDeclVar(SDKNodeInitInfo Info);
static bool classof(const SDKNode *N);
+ bool hasFixedBinaryOrder() const { return FixedBinaryOrder.hasValue(); }
+ unsigned getFixedBinaryOrder() const { return *FixedBinaryOrder; }
};
class SDKNodeDeclAbstractFunc : public SDKNodeDecl {
@@ -538,6 +542,7 @@
CheckerOptions Opts);
int findDeclUsr(StringRef dumpPath, CheckerOptions Opts);
+
} // end of abi namespace
} // end of ide namespace
} // end of Swift namespace
diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.cpp b/tools/swift-api-digester/ModuleDiagsConsumer.cpp
index c00bad3..88178bd 100644
--- a/tools/swift-api-digester/ModuleDiagsConsumer.cpp
+++ b/tools/swift-api-digester/ModuleDiagsConsumer.cpp
@@ -47,6 +47,9 @@
return "/* RawRepresentable Changes */";
case LocalDiagID::generic_sig_change:
return "/* Generic Signature Changes */";
+ case LocalDiagID::decl_added:
+ case LocalDiagID::decl_reorder:
+ return "/* Fixed-layout Type Changes */";
default:
return StringRef();
}
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index bc3c9e4..9f0f218 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -709,6 +709,17 @@
Desc);
}
}
+ // Detect re-ordering if they're from structs with a fixed layout.
+ auto *LV = dyn_cast<SDKNodeDeclVar>(L);
+ auto *RV = dyn_cast<SDKNodeDeclVar>(R);
+ if (LV && RV &&
+ LV->hasFixedBinaryOrder() && RV->hasFixedBinaryOrder() &&
+ LV->getFixedBinaryOrder() != RV->getFixedBinaryOrder()) {
+ Ctx.getDiags().diagnose(SourceLoc(), diag::decl_reorder,
+ LV->getScreenInfo(),
+ LV->getFixedBinaryOrder(),
+ RV->getFixedBinaryOrder());
+ }
}
// Diagnose generic signature change
@@ -751,6 +762,14 @@
case NodeMatchReason::Added:
assert(!Left);
Right->annotate(NodeAnnotation::Added);
+ if (Ctx.checkingABI()) {
+ if (auto *VAD = dyn_cast<SDKNodeDeclVar>(Right)) {
+ if (VAD->hasFixedBinaryOrder()) {
+ Ctx.getDiags().diagnose(SourceLoc(), diag::decl_added,
+ VAD->getScreenInfo());
+ }
+ }
+ }
return;
case NodeMatchReason::Removed:
assert(!Right);
diff --git a/utils/build-script-impl b/utils/build-script-impl
index 25e9ea2..80d1caf 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -2879,7 +2879,7 @@
# Watchpoint testing is currently disabled: see rdar://38566150.
if [[ "$(true_false ${LLDB_TEST_SWIFT_ONLY})" == "TRUE" ]]; then
LLDB_TEST_SUBDIR_CLAUSE="--test-subdir lang/swift"
- LLDB_TEST_CATEGORIES="--skip-category=watchpoint --skip-category=dwo --skip-category=dwarf"
+ LLDB_TEST_CATEGORIES="--skip-category=watchpoint --skip-category=dwo"
else
LLDB_TEST_SUBDIR_CLAUSE=""
LLDB_TEST_CATEGORIES="--skip-category=watchpoint"
diff --git a/validation-test/Evolution/Inputs/protocol_add_requirements.swift b/validation-test/Evolution/Inputs/protocol_add_requirements.swift
index 6e2eb34..ba05853 100644
--- a/validation-test/Evolution/Inputs/protocol_add_requirements.swift
+++ b/validation-test/Evolution/Inputs/protocol_add_requirements.swift
@@ -176,24 +176,23 @@
#endif
}
-public struct Wrapper<T> { }
+public protocol SimpleProtocol {
+ static func getString() -> String
+}
+
+public struct Wrapper<T>: SimpleProtocol {
+ public static func getString() -> String {
+ return "I am a wrapper for \(T.self)"
+ }
+}
public protocol AddAssocTypesProtocol {
- // FIXME: The presence of a single method requirement causes us to
- // create a resilient witness table, avoiding a runtime assertion.
- func dummy()
-
#if AFTER
associatedtype AssocType = Self
- associatedtype AssocType2 = Wrapper<AssocType>
+ associatedtype AssocType2: SimpleProtocol = Wrapper<AssocType>
#endif
}
-extension AddAssocTypesProtocol {
- public func dummy() { }
-}
-
-
public func doSomethingWithAssocTypes<T: AddAssocTypesProtocol>(_ value: T)
-> String {
#if AFTER
@@ -202,3 +201,17 @@
return "there are no associated types yet"
#endif
}
+
+public func doSomethingWithAssocConformances<T: AddAssocTypesProtocol>(_ value: T)
+ -> String {
+#if AFTER
+ let at2: Any.Type = T.AssocType2.self
+ if let simpleType = at2 as? SimpleProtocol.Type {
+ return simpleType.getString()
+ }
+
+ return "missing associated conformance"
+#else
+ return "there are no associated conformances yet"
+#endif
+}
diff --git a/validation-test/Evolution/test_protocol_add_requirements.swift b/validation-test/Evolution/test_protocol_add_requirements.swift
index 046b6ee..2acfb7e 100644
--- a/validation-test/Evolution/test_protocol_add_requirements.swift
+++ b/validation-test/Evolution/test_protocol_add_requirements.swift
@@ -154,5 +154,16 @@
}
}
+ProtocolAddRequirementsTest.test("AddAssociatedConformanceRequirements") {
+ let addString = AddAssociatedType<String>()
+ let stringResult = doSomethingWithAssocConformances(addString)
+
+ if getVersion() == 0 {
+ expectEqual("there are no associated conformances yet", stringResult)
+ } else {
+ expectEqual("I am a wrapper for AddAssociatedType<String>", stringResult)
+ }
+}
+
runAllTests()