Merge pull request #9989 from ahoppen/introduce-special-declnames
Introduce special decl names
diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h
index 40da25f..a6b82ed 100644
--- a/include/swift/AST/Identifier.h
+++ b/include/swift/AST/Identifier.h
@@ -51,6 +51,8 @@
/// ASTContext. It just wraps a nul-terminated "const char*".
class Identifier {
friend class ASTContext;
+ friend class DeclBaseName;
+
const char *Pointer;
/// Constructor, only accessible by ASTContext, which handles the uniquing.
@@ -207,6 +209,19 @@
/// Wrapper that may either be an Identifier or a special name
/// (e.g. for subscripts)
class DeclBaseName {
+public:
+ enum class Kind: uint8_t {
+ Normal,
+ Subscript
+ };
+
+private:
+ /// In a special DeclName represenenting a subscript, this opaque pointer
+ /// is used as the data of the base name identifier.
+ /// This is an implementation detail that should never leak outside of
+ /// DeclName.
+ static void *SubscriptIdentifierData;
+
Identifier Ident;
public:
@@ -214,7 +229,19 @@
DeclBaseName(Identifier I) : Ident(I) {}
- bool isSpecial() const { return false; }
+ static DeclBaseName createSubscript() {
+ return DeclBaseName(Identifier((const char *)SubscriptIdentifierData));
+ }
+
+ Kind getKind() const {
+ if (Ident.get() == SubscriptIdentifierData) {
+ return Kind::Subscript;
+ } else {
+ return Kind::Normal;
+ }
+ }
+
+ bool isSpecial() const { return getKind() != Kind::Normal; }
/// Return the identifier backing the name. Assumes that the name is not
/// special.
@@ -238,12 +265,17 @@
StringRef userFacingName() const {
if (empty())
return "_";
- return getIdentifier().str();
+
+ switch (getKind()) {
+ case Kind::Normal:
+ return getIdentifier().str();
+ case Kind::Subscript:
+ return "subscript";
+ }
}
int compare(DeclBaseName other) const {
- // TODO: Sort special names cleverly
- return getIdentifier().compare(other.getIdentifier());
+ return userFacingName().compare(other.userFacingName());
}
bool operator==(StringRef Str) const {
diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def
index 1937658..fabeb8e 100644
--- a/include/swift/AST/KnownIdentifiers.def
+++ b/include/swift/AST/KnownIdentifiers.def
@@ -90,7 +90,6 @@
IDENTIFIER(some)
IDENTIFIER(storage)
IDENTIFIER(stringValue)
-IDENTIFIER(subscript)
IDENTIFIER(super)
IDENTIFIER(superDecoder)
IDENTIFIER(superEncoder)
diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h
index 75eb0e3..dd40305 100644
--- a/include/swift/Serialization/ModuleFile.h
+++ b/include/swift/Serialization/ModuleFile.h
@@ -740,7 +740,11 @@
/// Returns the type with the given ID, deserializing it if needed.
llvm::Expected<Type> getTypeChecked(serialization::TypeID TID);
- /// Returns the identifier with the given ID, deserializing it if needed.
+ /// Returns the base name with the given ID, deserializing it if needed.
+ DeclBaseName getDeclBaseName(serialization::IdentifierID IID);
+
+ /// Convenience method to retrieve the identifier backing the name with
+ /// given ID. Asserts that the name with this ID is not special.
Identifier getIdentifier(serialization::IdentifierID IID);
/// Returns the decl with the given ID, deserializing it if needed.
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 90832f9..42dbbd2 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 349; // Last change: '@autoclosure' and '@noescape' no longer decl attributes.
+const uint16_t VERSION_MINOR = 350; // Last change: special decl names
using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
@@ -342,18 +342,27 @@
// These IDs must \em not be renumbered or reordered without incrementing
// VERSION_MAJOR.
-enum SpecialModuleID : uint8_t {
+enum class DeclNameKind: uint8_t {
+ Normal,
+ Subscript
+};
+
+// These IDs must \em not be renumbered or reordered without incrementing
+// VERSION_MAJOR.
+enum SpecialIdentifierID : uint8_t {
/// Special IdentifierID value for the Builtin module.
BUILTIN_MODULE_ID = 0,
/// Special IdentifierID value for the current module.
CURRENT_MODULE_ID,
/// Special value for the module for imported Objective-C headers.
OBJC_HEADER_MODULE_ID,
+ /// Special value for the special subscript name
+ SUBSCRIPT_ID,
- /// The number of special modules. This value should never be encoded;
+ /// The number of special Identifier IDs. This value should never be encoded;
/// it should only be used to count the number of names above. As such, it
/// is correct and necessary to add new values above this one.
- NUM_SPECIAL_MODULES
+ NUM_SPECIAL_IDS
};
// These IDs must \em not be renumbered or reordered without incrementing
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index 9d5b4ab..f5fbc72 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -540,8 +540,15 @@
break;
}
} else if (decl->hasName()) {
- // TODO: Handle special names
- appendIdentifier(decl->getBaseName().getIdentifier().str());
+ // FIXME: Should a mangled subscript name contain the string "subscript"?
+ switch (decl->getBaseName().getKind()) {
+ case DeclBaseName::Kind::Normal:
+ appendIdentifier(decl->getBaseName().getIdentifier().str());
+ break;
+ case DeclBaseName::Kind::Subscript:
+ appendIdentifier("subscript");
+ break;
+ }
} else {
assert(AllowNamelessEntities && "attempt to mangle unnamed decl");
// Fall back to an unlikely name, so that we still generate a valid
diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp
index 1fae6e5..a743912 100644
--- a/lib/AST/Identifier.cpp
+++ b/lib/AST/Identifier.cpp
@@ -20,6 +20,8 @@
#include "llvm/Support/ConvertUTF.h"
using namespace swift;
+void *DeclBaseName::SubscriptIdentifierData =
+ &DeclBaseName::SubscriptIdentifierData;
raw_ostream &llvm::operator<<(raw_ostream &OS, Identifier I) {
if (I.get() == nullptr)
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index dcf9c97..0ebb9e7 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -2974,7 +2974,7 @@
auto &clangCtx = getClangASTContext();
auto clangTU = clangCtx.getTranslationUnitDecl();
- for (auto entry : table.lookup(name.getBaseIdentifier().str(), clangTU)) {
+ for (auto entry : table.lookup(name.getBaseName(), clangTU)) {
// If the entry is not visible, skip it.
if (!isVisibleClangEntry(clangCtx, entry)) continue;
@@ -3070,7 +3070,7 @@
// Look for namespace-scope entities with each base name.
for (auto baseName : baseNames) {
- lookupValue(table, SwiftContext.getIdentifier(baseName), consumer);
+ lookupValue(table, baseName.toDeclBaseName(SwiftContext), consumer);
}
}
@@ -3079,9 +3079,8 @@
DeclName name,
VisibleDeclConsumer &consumer) {
auto &clangCtx = getClangASTContext();
- auto baseName = name.getBaseIdentifier().str();
- for (auto clangDecl : table.lookupObjCMembers(baseName)) {
+ for (auto clangDecl : table.lookupObjCMembers(name.getBaseName())) {
// If the entry is not visible, skip it.
if (!isVisibleClangEntry(clangCtx, clangDecl)) continue;
@@ -3121,7 +3120,7 @@
// Look for Objective-C members with each base name.
for (auto baseName : baseNames) {
- lookupObjCMembers(table, SwiftContext.getIdentifier(baseName), consumer);
+ lookupObjCMembers(table, baseName.toDeclBaseName(SwiftContext), consumer);
}
}
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 2e4ab67..3782850 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -5410,7 +5410,7 @@
Impl.findLookupTable(*getClangSubmoduleForDecl(accessor));
assert(lookupTable && "No lookup table?");
bool foundAccessor = false;
- for (auto entry : lookupTable->lookup(propertyName.str(),
+ for (auto entry : lookupTable->lookup(SerializedSwiftName(propertyName),
importedName.getEffectiveContext())) {
auto decl = entry.dyn_cast<clang::NamedDecl *>();
if (!decl)
@@ -6246,7 +6246,7 @@
// Build the subscript declaration.
auto &C = Impl.SwiftContext;
auto bodyParams = getterThunk->getParameterList(1)->clone(C);
- DeclName name(C, C.Id_subscript, {Identifier()});
+ DeclName name(C, DeclBaseName::createSubscript(), {Identifier()});
auto subscript = Impl.createDeclWithClangNode<SubscriptDecl>(
getter->getClangNode(), getOverridableAccessibility(dc), name,
decl->getLoc(), bodyParams, decl->getLoc(),
diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp
index b470a24..016af64 100644
--- a/lib/ClangImporter/SwiftLookupTable.cpp
+++ b/lib/ClangImporter/SwiftLookupTable.cpp
@@ -179,12 +179,12 @@
clang::serialization::ModuleFile &getModuleFile() { return ModuleFile; }
/// Retrieve the set of base names that are stored in the on-disk hash table.
- SmallVector<StringRef, 4> getBaseNames();
+ SmallVector<SerializedSwiftName, 4> getBaseNames();
/// Retrieve the set of entries associated with the given base name.
///
/// \returns true if we found anything, false otherwise.
- bool lookup(StringRef baseName,
+ bool lookup(SerializedSwiftName baseName,
SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries);
/// Retrieve the declaration IDs of the categories.
@@ -205,6 +205,15 @@
};
} // namespace swift
+DeclBaseName SerializedSwiftName::toDeclBaseName(ASTContext &Context) const {
+ switch (Kind) {
+ case DeclBaseName::Kind::Normal:
+ return Context.getIdentifier(Name);
+ case DeclBaseName::Kind::Subscript:
+ return DeclBaseName::createSubscript();
+ }
+}
+
bool SwiftLookupTable::contextRequiresName(ContextKind kind) {
switch (kind) {
case ContextKind::ObjCClass:
@@ -305,9 +314,9 @@
/// declaration context or typedef name.
clang::NamedDecl *SwiftLookupTable::resolveContext(StringRef unresolvedName) {
// Look for a context with the given Swift name.
- for (auto entry : lookup(unresolvedName,
- std::make_pair(ContextKind::TranslationUnit,
- StringRef()))) {
+ for (auto entry :
+ lookup(SerializedSwiftName(unresolvedName),
+ std::make_pair(ContextKind::TranslationUnit, StringRef()))) {
if (auto decl = entry.dyn_cast<clang::NamedDecl *>()) {
if (isa<clang::TagDecl>(decl) ||
isa<clang::ObjCInterfaceDecl>(decl) ||
@@ -488,7 +497,7 @@
}
// Populate cache from reader if necessary.
- findOrCreate(name.getBaseIdentifier().str());
+ findOrCreate(name.getBaseName());
auto context = *contextOpt;
@@ -499,7 +508,7 @@
}
// Find the list of entries for this base name.
- auto &entries = LookupTable[name.getBaseIdentifier().str()];
+ auto &entries = LookupTable[name.getBaseName()];
auto decl = newEntry.dyn_cast<clang::NamedDecl *>();
auto macro = newEntry.dyn_cast<clang::MacroInfo *>();
for (auto &entry : entries) {
@@ -520,8 +529,9 @@
entries.push_back(entry);
}
-auto SwiftLookupTable::findOrCreate(StringRef baseName)
- -> llvm::DenseMap<StringRef, SmallVector<FullTableEntry, 2>>::iterator {
+auto SwiftLookupTable::findOrCreate(SerializedSwiftName baseName)
+ -> llvm::DenseMap<SerializedSwiftName,
+ SmallVector<FullTableEntry, 2>>::iterator {
// If there is no base name, there is nothing to find.
if (baseName.empty()) return LookupTable.end();
@@ -545,7 +555,7 @@
}
SmallVector<SwiftLookupTable::SingleEntry, 4>
-SwiftLookupTable::lookup(StringRef baseName,
+SwiftLookupTable::lookup(SerializedSwiftName baseName,
llvm::Optional<StoredContext> searchContext) {
SmallVector<SwiftLookupTable::SingleEntry, 4> result;
@@ -634,7 +644,7 @@
}
SmallVector<SwiftLookupTable::SingleEntry, 4>
-SwiftLookupTable::lookup(StringRef baseName,
+SwiftLookupTable::lookup(SerializedSwiftName baseName,
EffectiveClangContext searchContext) {
// Translate context.
Optional<StoredContext> context;
@@ -646,12 +656,12 @@
return lookup(baseName, context);
}
-SmallVector<StringRef, 4> SwiftLookupTable::allBaseNames() {
+SmallVector<SerializedSwiftName, 4> SwiftLookupTable::allBaseNames() {
// If we have a reader, enumerate its base names.
if (Reader) return Reader->getBaseNames();
// Otherwise, walk the lookup table.
- SmallVector<StringRef, 4> result;
+ SmallVector<SerializedSwiftName, 4> result;
for (const auto &entry : LookupTable) {
result.push_back(entry.first);
}
@@ -659,7 +669,7 @@
}
SmallVector<clang::NamedDecl *, 4>
-SwiftLookupTable::lookupObjCMembers(StringRef baseName) {
+SwiftLookupTable::lookupObjCMembers(SerializedSwiftName baseName) {
SmallVector<clang::NamedDecl *, 4> result;
// Find the lookup table entry for this base name.
@@ -805,14 +815,21 @@
void SwiftLookupTable::dump() const {
// Dump the base name -> full table entry mappings.
- SmallVector<StringRef, 4> baseNames;
+ SmallVector<SerializedSwiftName, 4> baseNames;
for (const auto &entry : LookupTable) {
baseNames.push_back(entry.first);
}
llvm::array_pod_sort(baseNames.begin(), baseNames.end());
llvm::errs() << "Base name -> entry mappings:\n";
for (auto baseName : baseNames) {
- llvm::errs() << " " << baseName << ":\n";
+ switch (baseName.Kind) {
+ case DeclBaseName::Kind::Normal:
+ llvm::errs() << " " << baseName.Name << ":\n";
+ break;
+ case DeclBaseName::Kind::Subscript:
+ llvm::errs() << " subscript:\n";
+ break;
+ }
const auto &entries = LookupTable.find(baseName)->second;
for (const auto &entry : entries) {
llvm::errs() << " ";
@@ -915,11 +932,14 @@
/// Trait used to write the on-disk hash table for the base name -> entities
/// mapping.
class BaseNameToEntitiesTableWriterInfo {
+ static_assert(sizeof(DeclBaseName::Kind) <= sizeof(uint8_t),
+ "kind serialized as uint8_t");
+
SwiftLookupTable &Table;
clang::ASTWriter &Writer;
public:
- using key_type = StringRef;
+ using key_type = SerializedSwiftName;
using key_type_ref = key_type;
using data_type = SmallVector<SwiftLookupTable::FullTableEntry, 2>;
using data_type_ref = data_type &;
@@ -933,14 +953,16 @@
}
hash_value_type ComputeHash(key_type_ref key) {
- return llvm::HashString(key);
+ return llvm::DenseMapInfo<SerializedSwiftName>::getHashValue(key);
}
std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
key_type_ref key,
data_type_ref data) {
- // The length of the key.
- uint32_t keyLength = key.size();
+ uint32_t keyLength = sizeof(uint8_t); // For the flag of the name's kind
+ if (key.Kind == DeclBaseName::Kind::Normal) {
+ keyLength += key.Name.size(); // The name's length
+ }
// # of entries
uint32_t dataLength = sizeof(uint16_t);
@@ -968,7 +990,10 @@
}
void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
- out << key;
+ endian::Writer<little> writer(out);
+ writer.write<uint8_t>((uint8_t)key.Kind);
+ if (key.Kind == swift::DeclBaseName::Kind::Normal)
+ writer.OS << key.Name;
}
void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
@@ -1089,7 +1114,7 @@
SmallVector<uint64_t, 64> ScratchRecord;
// First, gather the sorted list of base names.
- SmallVector<StringRef, 2> baseNames;
+ SmallVector<SerializedSwiftName, 2> baseNames;
for (const auto &entry : table.LookupTable)
baseNames.push_back(entry.first);
llvm::array_pod_sort(baseNames.begin(), baseNames.end());
@@ -1162,7 +1187,7 @@
/// Used to deserialize the on-disk base name -> entities table.
class BaseNameToEntitiesTableReaderInfo {
public:
- using internal_key_type = StringRef;
+ using internal_key_type = SerializedSwiftName;
using external_key_type = internal_key_type;
using data_type = SmallVector<SwiftLookupTable::FullTableEntry, 2>;
using hash_value_type = uint32_t;
@@ -1177,7 +1202,7 @@
}
hash_value_type ComputeHash(internal_key_type key) {
- return llvm::HashString(key);
+ return llvm::DenseMapInfo<SerializedSwiftName>::getHashValue(key);
}
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
@@ -1192,7 +1217,18 @@
}
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
- return StringRef((const char *)data, length);
+ uint8_t kind = endian::readNext<uint8_t, little, unaligned>(data);
+ switch (kind) {
+ case (uint8_t)DeclBaseName::Kind::Normal: {
+ StringRef str(reinterpret_cast<const char *>(data),
+ length - sizeof(uint8_t));
+ return SerializedSwiftName(str);
+ }
+ case (uint8_t)DeclBaseName::Kind::Subscript:
+ return SerializedSwiftName(DeclBaseName::Kind::Subscript);
+ default:
+ llvm_unreachable("Unknown kind for DeclBaseName");
+ }
}
static data_type ReadData(internal_key_type key, const uint8_t *data,
@@ -1447,9 +1483,9 @@
}
-SmallVector<StringRef, 4> SwiftLookupTableReader::getBaseNames() {
+SmallVector<SerializedSwiftName, 4> SwiftLookupTableReader::getBaseNames() {
auto table = static_cast<SerializedBaseNameToEntitiesTable*>(SerializedTable);
- SmallVector<StringRef, 4> results;
+ SmallVector<SerializedSwiftName, 4> results;
for (auto key : table->keys()) {
results.push_back(key);
}
@@ -1457,8 +1493,8 @@
}
bool SwiftLookupTableReader::lookup(
- StringRef baseName,
- SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries) {
+ SerializedSwiftName baseName,
+ SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries) {
auto table = static_cast<SerializedBaseNameToEntitiesTable*>(SerializedTable);
// Look for an entry with this base name.
@@ -1556,7 +1592,7 @@
// Also add the subscript entry, if needed.
if (importedName.isSubscriptAccessor())
table.addEntry(DeclName(nameImporter.getContext(),
- nameImporter.getContext().Id_subscript,
+ DeclBaseName::createSubscript(),
ArrayRef<Identifier>()),
named, importedName.getEffectiveContext());
diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h
index e09e7aa..e917275 100644
--- a/lib/ClangImporter/SwiftLookupTable.h
+++ b/lib/ClangImporter/SwiftLookupTable.h
@@ -45,6 +45,102 @@
namespace swift {
+/// A name from a SwiftLookupTable that has not been deserialized into a
+/// DeclBaseName yet.
+struct SerializedSwiftName {
+ /// The kind of the name if it is a special name
+ DeclBaseName::Kind Kind;
+ /// The name of the idenifier if it is not a special name
+ StringRef Name;
+
+ SerializedSwiftName() : Kind(DeclBaseName::Kind::Normal), Name(StringRef()) {}
+
+ explicit SerializedSwiftName(DeclBaseName::Kind Kind)
+ : Kind(Kind), Name(StringRef()) {}
+
+ explicit SerializedSwiftName(StringRef Name)
+ : Kind(DeclBaseName::Kind::Normal), Name(Name) {}
+
+ SerializedSwiftName(DeclBaseName BaseName) {
+ Kind = BaseName.getKind();
+ if (BaseName.getKind() == DeclBaseName::Kind::Normal) {
+ Name = BaseName.getIdentifier().str();
+ }
+ }
+
+ /// Deserialize the name, adding it to the context's identifier table
+ DeclBaseName toDeclBaseName(ASTContext &Context) const;
+
+ bool empty() const {
+ return Kind == DeclBaseName::Kind::Normal && Name.empty();
+ }
+
+ /// Return a string representation of the name that can be used for sorting
+ StringRef userFacingName() const {
+ switch (Kind) {
+ case DeclBaseName::Kind::Normal:
+ return Name;
+ case DeclBaseName::Kind::Subscript:
+ return "subscript";
+ }
+ }
+
+ bool operator<(SerializedSwiftName RHS) const {
+ return userFacingName() < RHS.userFacingName();
+ }
+
+ bool operator==(SerializedSwiftName RHS) const {
+ if (Kind != RHS.Kind)
+ return false;
+
+ if (Kind == DeclBaseName::Kind::Normal) {
+ assert(RHS.Kind == DeclBaseName::Kind::Normal);
+ return Name == RHS.Name;
+ } else {
+ return true;
+ }
+ }
+};
+
+} // end namespace swift
+
+namespace llvm {
+
+using swift::SerializedSwiftName;
+
+// Inherit the DenseMapInfo from StringRef but add a few special cases for
+// special names
+template<> struct DenseMapInfo<SerializedSwiftName> {
+ static SerializedSwiftName getEmptyKey() {
+ return SerializedSwiftName(DenseMapInfo<StringRef>::getEmptyKey());
+ }
+ static SerializedSwiftName getTombstoneKey() {
+ return SerializedSwiftName(DenseMapInfo<StringRef>::getTombstoneKey());
+ }
+ static unsigned getHashValue(SerializedSwiftName Val) {
+ if (Val.Kind == swift::DeclBaseName::Kind::Normal) {
+ return DenseMapInfo<StringRef>::getHashValue(Val.Name);
+ } else {
+ return (unsigned)Val.Kind;
+ }
+ }
+ static bool isEqual(SerializedSwiftName LHS, SerializedSwiftName RHS) {
+ if (LHS.Kind != RHS.Kind)
+ return false;
+
+ if (LHS.Kind == swift::DeclBaseName::Kind::Normal) {
+ assert(RHS.Kind == swift::DeclBaseName::Kind::Normal);
+ return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name);
+ } else {
+ return LHS.Kind == RHS.Kind;
+ }
+ }
+};
+
+} // end namespace llvm
+
+namespace swift {
+
/// The context into which a Clang declaration will be imported.
///
/// When the context into which a declaration will be imported matches
@@ -170,7 +266,7 @@
/// Lookup table minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 14; // Swift 2 names
+const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 15; // Special names
/// A lookup table that maps Swift names to the set of Clang
/// declarations with that particular name.
@@ -276,7 +372,8 @@
private:
/// A table mapping from the base name of Swift entities to all of
/// the C entities that have that name, in all contexts.
- llvm::DenseMap<StringRef, SmallVector<FullTableEntry, 2>> LookupTable;
+ llvm::DenseMap<SerializedSwiftName, SmallVector<FullTableEntry, 2>>
+ LookupTable;
/// The list of Objective-C categories and extensions.
llvm::SmallVector<clang::ObjCCategoryDecl *, 4> Categories;
@@ -299,9 +396,9 @@
friend class SwiftLookupTableReader;
friend class SwiftLookupTableWriter;
- /// Find or create the table entry for the given base name.
- llvm::DenseMap<StringRef, SmallVector<FullTableEntry, 2>>::iterator
- findOrCreate(StringRef baseName);
+ /// Find or create the table entry for the given base name.
+ llvm::DenseMap<SerializedSwiftName, SmallVector<FullTableEntry, 2>>::iterator
+ findOrCreate(SerializedSwiftName baseName);
/// Add the given entry to the list of entries, if it's not already
/// present.
@@ -360,7 +457,8 @@
/// entities should reside. This may be None to indicate that
/// all results from all contexts should be produced.
SmallVector<SingleEntry, 4>
- lookup(StringRef baseName, llvm::Optional<StoredContext> searchContext);
+ lookup(SerializedSwiftName baseName,
+ llvm::Optional<StoredContext> searchContext);
/// Retrieve the set of global declarations that are going to be
/// imported as members into the given context.
@@ -379,15 +477,16 @@
/// \param searchContext The context in which the resulting set of
/// entities should reside. This may be None to indicate that
/// all results from all contexts should be produced.
- SmallVector<SingleEntry, 4>
- lookup(StringRef baseName, EffectiveClangContext searchContext);
+ SmallVector<SingleEntry, 4> lookup(SerializedSwiftName baseName,
+ EffectiveClangContext searchContext);
/// Retrieve the set of base names that are stored in the lookup table.
- SmallVector<StringRef, 4> allBaseNames();
+ SmallVector<SerializedSwiftName, 4> allBaseNames();
/// Lookup Objective-C members with the given base name, regardless
/// of context.
- SmallVector<clang::NamedDecl *, 4> lookupObjCMembers(StringRef baseName);
+ SmallVector<clang::NamedDecl *, 4>
+ lookupObjCMembers(SerializedSwiftName baseName);
/// Retrieve the set of Objective-C categories and extensions.
ArrayRef<clang::ObjCCategoryDecl *> categories();
diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp
index 1c8f443..bf9448d 100644
--- a/lib/IRGen/IRGenDebugInfo.cpp
+++ b/lib/IRGen/IRGenDebugInfo.cpp
@@ -400,8 +400,7 @@
}
SmallVector<char, 64> Buf;
- // TODO: Handle special names
- StringRef Name = (VD->getBaseName().getIdentifier().str() +
+ StringRef Name = (VD->getBaseName().userFacingName() +
Twine(Kind)).toStringRef(Buf);
return BumpAllocatedString(Name);
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b15f047..238f473 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -5512,7 +5512,8 @@
}
// Build an AST for the subscript declaration.
- DeclName name = DeclName(Context, Context.Id_subscript, argumentNames);
+ DeclName name = DeclName(Context, DeclBaseName::createSubscript(),
+ argumentNames);
auto *Subscript = new (Context) SubscriptDecl(name,
SubscriptLoc, Indices.get(),
ArrowLoc, ElementTy.get(),
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index 7d2f8c6..96b5423 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -406,9 +406,6 @@
case tok::kw_init:
Result = P.Context.Id_init;
break;
- case tok::kw_subscript:
- Result = P.Context.Id_subscript;
- break;
default:
// If it's some other keyword, grab an identifier for it.
if (P.Tok.isKeyword()) {
@@ -955,8 +952,8 @@
}
/// Find the top-level ValueDecl or Module given a name.
-static llvm::PointerUnion<ValueDecl*, ModuleDecl*> lookupTopDecl(Parser &P,
- Identifier Name) {
+static llvm::PointerUnion<ValueDecl *, ModuleDecl *>
+lookupTopDecl(Parser &P, DeclBaseName Name) {
// Use UnqualifiedLookup to look through all of the imports.
// We have to lie and say we're done with parsing to make this happen.
assert(P.SF.ASTStage == SourceFile::Parsing &&
@@ -970,7 +967,7 @@
}
/// Find the ValueDecl given an interface type and a member name.
-static ValueDecl *lookupMember(Parser &P, Type Ty, Identifier Name,
+static ValueDecl *lookupMember(Parser &P, Type Ty, DeclBaseName Name,
SourceLoc Loc,
SmallVectorImpl<ValueDecl *> &Lookup,
bool ExpectMultipleResults) {
@@ -1108,13 +1105,21 @@
SmallVectorImpl<ValueDecl *> &values) {
// Handle sil-dotted-path.
Identifier Id;
- SmallVector<Identifier, 4> FullName;
+ SmallVector<DeclBaseName, 4> FullName;
SmallVector<SourceLoc, 4> Locs;
do {
Locs.push_back(P.Tok.getLoc());
- if (parseSILIdentifier(Id, diag::expected_sil_constant))
- return true;
- FullName.push_back(Id);
+ switch (P.Tok.getKind()) {
+ case tok::kw_subscript:
+ P.consumeToken();
+ FullName.push_back(DeclBaseName::createSubscript());
+ break;
+ default:
+ if (parseSILIdentifier(Id, diag::expected_sil_constant))
+ return true;
+ FullName.push_back(Id);
+ break;
+ }
} while (P.consumeIf(tok::period));
// Look up ValueDecl from a dotted path.
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index a1edd3d..c69a438 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -1575,9 +1575,13 @@
// Getter selectors can belong to families if their name begins with the
// wrong thing.
if (FD->getAccessorStorageDecl()->isObjC() || c.isForeign) {
- // TODO: Handle special names (subscript).
- auto name = FD->getAccessorStorageDecl()->getBaseName().getIdentifier();
- return getSelectorFamily(name);
+ auto declName = FD->getAccessorStorageDecl()->getBaseName();
+ switch (declName.getKind()) {
+ case DeclBaseName::Kind::Normal:
+ return getSelectorFamily(declName.getIdentifier());
+ case DeclBaseName::Kind::Subscript:
+ return SelectorFamily::None;
+ }
}
return SelectorFamily::None;
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 2bf4c2b..7fc669a 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -237,10 +237,13 @@
printFullContext(Decl->getDeclContext(), OS);
assert(Decl->hasName());
- if (Decl->isOperator())
+ if (Decl->isOperator()) {
OS << '"' << Decl->getBaseName() << '"';
- else
+ } else if (Decl->getBaseName() == "subscript") {
+ OS << '`' << Decl->getBaseName() << '`';
+ } else {
OS << Decl->getBaseName();
+ }
}
/// SILDeclRef uses sigil "#" and prints the fully qualified dotted path.
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 2baecba..33b0fc9 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -2526,7 +2526,7 @@
};
// TODO: This should handle tuple member lookups, like x.1231 as well.
- if (memberName.isSimpleName(CS->getASTContext().Id_subscript)) {
+ if (memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript) {
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
.highlight(baseRange);
} else if (auto metatypeTy = baseObjTy->getAs<MetatypeType>()) {
@@ -5699,7 +5699,7 @@
CS->getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
return diagnoseMemberFailures(SE, baseExpr, ConstraintKind::ValueMember,
- CS->getASTContext().Id_subscript,
+ DeclBaseName::createSubscript(),
FunctionRefKind::DoubleApply, locator,
callback);
}
@@ -7540,7 +7540,7 @@
};
// Local function to perform name lookup for the current index.
- auto performLookup = [&](Identifier componentName, SourceLoc componentNameLoc,
+ auto performLookup = [&](DeclBaseName componentName, SourceLoc componentNameLoc,
Type &lookupType) -> LookupResult {
assert(currentType && "Non-beginning state must have a type");
if (!currentType->mayHaveMembers())
@@ -7560,13 +7560,13 @@
// Local function to print a component to the string.
bool needDot = false;
- auto printComponent = [&](Identifier component) {
+ auto printComponent = [&](DeclBaseName component) {
if (needDot)
keyPathOS << ".";
else
needDot = true;
- keyPathOS << component.str();
+ keyPathOS << component;
};
bool isInvalid = false;
@@ -7574,7 +7574,7 @@
for (auto &component : KPE->getComponents()) {
auto componentNameLoc = component.getLoc();
- Identifier componentName;
+ DeclBaseName componentName;
switch (auto kind = component.getKind()) {
case KeyPathExpr::Component::Kind::UnresolvedProperty: {
@@ -7584,7 +7584,7 @@
}
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
- componentName = TC.Context.Id_subscript;
+ componentName = DeclBaseName::createSubscript();
break;
case KeyPathExpr::Component::Kind::Invalid:
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 3b54812..f7f4a47 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -1031,8 +1031,6 @@
ValueDecl *declOrNull,
ConstraintLocator *memberLocator = nullptr,
ConstraintLocator *indexLocator = nullptr) {
- ASTContext &Context = CS.getASTContext();
-
// Locators used in this expression.
if (!indexLocator)
indexLocator
@@ -1128,7 +1126,7 @@
CS.addBindOverloadConstraint(fnTy, choice, memberLocator,
CurDC);
} else {
- CS.addValueMemberConstraint(baseTy, Context.Id_subscript,
+ CS.addValueMemberConstraint(baseTy, DeclBaseName::createSubscript(),
fnTy, CurDC, FunctionRefKind::DoubleApply,
memberLocator);
}
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 3d152f3..1cee9e9 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -2888,7 +2888,8 @@
result.OverallResult = MemberLookupResult::HasResults;
// If we're looking for a subscript, consider key path operations.
- if (memberName.isSimpleName(getASTContext().Id_subscript)) {
+ if (memberName.isSimpleName() &&
+ memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript) {
result.ViableCandidates.push_back(
OverloadChoice(baseTy, OverloadChoiceKind::KeyPathApplication));
}
@@ -2897,7 +2898,7 @@
// of the tuple.
if (auto baseTuple = baseObjTy->getAs<TupleType>()) {
// Tuples don't have compound-name members.
- if (!memberName.isSimpleName())
+ if (!memberName.isSimpleName() || memberName.isSpecial())
return result; // No result.
StringRef nameStr = memberName.getBaseIdentifier().str();
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 74d7608..34b6c47 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -1794,8 +1794,7 @@
// don't currently pre-filter subscript overload sets by argument
// keywords, so "subscript" is still the name that keypath subscripts
// are looked up by.
- auto &C = getBaseType()->getASTContext();
- return DeclName(C.Id_subscript);
+ return DeclBaseName::createSubscript();
}
case OverloadChoiceKind::BaseType:
case OverloadChoiceKind::TupleIndex:
diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp
index 64019f0..ef9d590 100644
--- a/lib/Sema/TypeCheckNameLookup.cpp
+++ b/lib/Sema/TypeCheckNameLookup.cpp
@@ -492,15 +492,22 @@
// TODO: maybe ignore certain kinds of missing / present labels for the
// first argument label?
// TODO: word-based rather than character-based?
- // TODO: Handle special names
+ if (argName.getBaseName().getKind() != paramName.getBaseName().getKind()) {
+ return UnreasonableCallEditDistance;
+ }
+
+ if (argName.getBaseName().getKind() != DeclBaseName::Kind::Normal) {
+ return 0;
+ }
+ assert(argName.getBaseName().getKind() == DeclBaseName::Kind::Normal);
+
StringRef argBase = argName.getBaseIdentifier().str();
StringRef paramBase = paramName.getBaseIdentifier().str();
unsigned distance = argBase.edit_distance(paramBase, maxEditDistance);
// Bound the distance to UnreasonableCallEditDistance.
- if (distance >= maxEditDistance ||
- distance > (paramBase.size() + 2) / 3) {
+ if (distance >= maxEditDistance || distance > (paramBase.size() + 2) / 3) {
return UnreasonableCallEditDistance;
}
@@ -638,13 +645,11 @@
isa<FuncDecl>(decl) ? "method" :
"member");
- // TODO: Handle special names
return tc.diagnose(parentDecl, diag::note_typo_candidate_implicit_member,
decl->getBaseName().getIdentifier().str(), kind);
}
}
- // TODO: Handle special names
return tc.diagnose(decl, diag::note_typo_candidate,
decl->getBaseName().getIdentifier().str());
}
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 961d0ba..433d1d0 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -5790,8 +5790,11 @@
score = lhsFirstName.edit_distance(rhsFirstName.str(), true, limit);
}
} else {
- // TODO: Handling of special names
- score = 0;
+ if (lhs.getBaseName().getKind() == rhs.getBaseName().getKind()) {
+ score = 0;
+ } else {
+ return None;
+ }
}
if (score > limit) return None;
@@ -5921,8 +5924,7 @@
/// argument labels.
static unsigned getNameLength(DeclName name) {
unsigned length = 0;
- // TODO: Handle special names
- if (!name.getBaseName().empty())
+ if (!name.getBaseName().empty() && !name.getBaseName().isSpecial())
length += name.getBaseIdentifier().str().size();
for (auto arg : name.getArgumentNames()) {
if (!arg.empty())
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index f2bcb9b..22fc8a6 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1201,7 +1201,7 @@
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
isStatic);
- Identifier name = getIdentifier(IID);
+ DeclBaseName name = getDeclBaseName(IID);
pathTrace.addValue(name);
Type filterTy = getType(TID);
@@ -1376,7 +1376,7 @@
case XREF_VALUE_PATH_PIECE:
case XREF_INITIALIZER_PATH_PIECE: {
TypeID TID = 0;
- Identifier memberName;
+ DeclBaseName memberName;
Optional<swift::CtorInitializerKind> ctorInit;
bool isType = false;
bool inProtocolExt = false;
@@ -1385,7 +1385,7 @@
case XREF_TYPE_PATH_PIECE: {
IdentifierID IID;
XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
- memberName = getIdentifier(IID);
+ memberName = getDeclBaseName(IID);
isType = true;
break;
}
@@ -1394,7 +1394,7 @@
IdentifierID IID;
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
isStatic);
- memberName = getIdentifier(IID);
+ memberName = getDeclBaseName(IID);
break;
}
@@ -1613,11 +1613,24 @@
return values.front();
}
-Identifier ModuleFile::getIdentifier(IdentifierID IID) {
+DeclBaseName ModuleFile::getDeclBaseName(IdentifierID IID) {
if (IID == 0)
return Identifier();
- size_t rawID = IID - NUM_SPECIAL_MODULES;
+ if (IID < NUM_SPECIAL_IDS) {
+ switch (static_cast<SpecialIdentifierID>(static_cast<uint8_t>(IID))) {
+ case BUILTIN_MODULE_ID:
+ case CURRENT_MODULE_ID:
+ case OBJC_HEADER_MODULE_ID:
+ llvm_unreachable("Cannot get DeclBaseName of special module id");
+ case SUBSCRIPT_ID:
+ return DeclBaseName::createSubscript();
+ case NUM_SPECIAL_IDS:
+ llvm_unreachable("implementation detail only");
+ }
+ }
+
+ size_t rawID = IID - NUM_SPECIAL_IDS;
assert(rawID < Identifiers.size() && "invalid identifier ID");
auto identRecord = Identifiers[rawID];
@@ -1634,6 +1647,12 @@
return getContext().getIdentifier(rawStrPtr.slice(0, terminatorOffset));
}
+Identifier ModuleFile::getIdentifier(IdentifierID IID) {
+ auto name = getDeclBaseName(IID);
+ assert(!name.isSpecial());
+ return name.getIdentifier();
+}
+
DeclContext *ModuleFile::getLocalDeclContext(DeclContextID DCID) {
assert(DCID != 0 && "invalid local DeclContext ID 0");
auto &declContextOrOffset = LocalDeclContexts[DCID-1];
@@ -1776,8 +1795,8 @@
}
ModuleDecl *ModuleFile::getModule(ModuleID MID) {
- if (MID < NUM_SPECIAL_MODULES) {
- switch (static_cast<SpecialModuleID>(static_cast<uint8_t>(MID))) {
+ if (MID < NUM_SPECIAL_IDS) {
+ switch (static_cast<SpecialIdentifierID>(static_cast<uint8_t>(MID))) {
case BUILTIN_MODULE_ID:
return getContext().TheBuiltinModule;
case CURRENT_MODULE_ID:
@@ -1787,7 +1806,9 @@
static_cast<ClangImporter *>(getContext().getClangModuleLoader());
return clangImporter->getImportedHeaderModule();
}
- case NUM_SPECIAL_MODULES:
+ case SUBSCRIPT_ID:
+ llvm_unreachable("Modules cannot be named with special names");
+ case NUM_SPECIAL_IDS:
llvm_unreachable("implementation detail only");
}
}
@@ -3380,7 +3401,7 @@
SmallVector<Identifier, 2> argNames;
for (auto argNameID : argNameAndDependencyIDs.slice(0, numArgNames))
argNames.push_back(getIdentifier(argNameID));
- DeclName name(ctx, ctx.Id_subscript, argNames);
+ DeclName name(ctx, DeclBaseName::createSubscript(), argNames);
Expected<Decl *> overridden = getDeclChecked(overriddenID);
if (!overridden) {
diff --git a/lib/Serialization/DeserializationErrors.h b/lib/Serialization/DeserializationErrors.h
index 90dd72c..afe319a 100644
--- a/lib/Serialization/DeserializationErrors.h
+++ b/lib/Serialization/DeserializationErrors.h
@@ -150,7 +150,7 @@
public:
explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
- void addValue(Identifier name) {
+ void addValue(DeclBaseName name) {
path.push_back({ PathPiece::Kind::Value, name });
}
diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp
index 9357e87..649a57d 100644
--- a/lib/Serialization/ModuleFile.cpp
+++ b/lib/Serialization/ModuleFile.cpp
@@ -299,19 +299,26 @@
/// Used to deserialize entries in the on-disk decl hash table.
class ModuleFile::DeclTableInfo {
public:
- using internal_key_type = StringRef;
+ using internal_key_type = std::pair<DeclBaseName::Kind, StringRef>;
using external_key_type = DeclBaseName;
using data_type = SmallVector<std::pair<uint8_t, DeclID>, 8>;
using hash_value_type = uint32_t;
using offset_type = unsigned;
internal_key_type GetInternalKey(external_key_type ID) {
- // TODO: Handle special names
- return ID.getIdentifier().str();
+ if (ID.getKind() == DeclBaseName::Kind::Normal) {
+ return {DeclBaseName::Kind::Normal, ID.getIdentifier().str()};
+ } else {
+ return {ID.getKind(), StringRef()};
+ }
}
hash_value_type ComputeHash(internal_key_type key) {
- return llvm::HashString(key);
+ if (key.first == DeclBaseName::Kind::Normal) {
+ return llvm::HashString(key.second);
+ } else {
+ return (hash_value_type)key.first;
+ }
}
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
@@ -325,8 +332,18 @@
}
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
- // TODO: Handle special names
- return StringRef(reinterpret_cast<const char *>(data), length);
+ uint8_t kind = endian::readNext<uint8_t, little, unaligned>(data);
+ switch (kind) {
+ case static_cast<uint8_t>(DeclNameKind::Normal): {
+ StringRef str(reinterpret_cast<const char *>(data),
+ length - sizeof(uint8_t));
+ return {DeclBaseName::Kind::Normal, str};
+ }
+ case static_cast<uint8_t>(DeclNameKind::Subscript):
+ return {DeclBaseName::Kind::Subscript, StringRef()};
+ default:
+ llvm_unreachable("Unknown DeclNameKind");
+ }
}
static data_type ReadData(internal_key_type key, const uint8_t *data,
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 322f91f..517480e 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -85,16 +85,23 @@
using offset_type = unsigned;
hash_value_type ComputeHash(key_type_ref key) {
- assert(!key.empty());
- // TODO: Handle special names
- return llvm::HashString(key.getIdentifier().str());
+ switch (key.getKind()) {
+ case DeclBaseName::Kind::Normal:
+ assert(!key.empty());
+ return llvm::HashString(key.getIdentifier().str());
+ case DeclBaseName::Kind::Subscript:
+ return static_cast<uint8_t>(DeclNameKind::Subscript);
+ }
}
std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
key_type_ref key,
data_type_ref data) {
- // TODO: Handle special names
- uint32_t keyLength = key.getIdentifier().str().size();
+ uint32_t keyLength = sizeof(uint8_t); // For the flag of the name's kind
+ if (key.getKind() == DeclBaseName::Kind::Normal) {
+ keyLength += key.getIdentifier().str().size(); // The name's length
+ }
+
uint32_t dataLength = (sizeof(uint32_t) + 1) * data.size();
endian::Writer<little> writer(out);
writer.write<uint16_t>(keyLength);
@@ -103,8 +110,16 @@
}
void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
- // TODO: Handle special names
- out << key.getIdentifier().str();
+ endian::Writer<little> writer(out);
+ switch (key.getKind()) {
+ case DeclBaseName::Kind::Normal:
+ writer.write<uint8_t>(static_cast<uint8_t>(DeclNameKind::Normal));
+ writer.OS << key.getIdentifier().str();
+ break;
+ case DeclBaseName::Kind::Subscript:
+ writer.write<uint8_t>(static_cast<uint8_t>(DeclNameKind::Subscript));
+ break;
+ }
}
void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
@@ -479,16 +494,22 @@
}
IdentifierID Serializer::addDeclBaseNameRef(DeclBaseName ident) {
- if (ident.empty())
- return 0;
+ switch (ident.getKind()) {
+ case DeclBaseName::Kind::Normal: {
+ if (ident.empty())
+ return 0;
- IdentifierID &id = IdentifierIDs[ident.getIdentifier()];
- if (id != 0)
+ IdentifierID &id = IdentifierIDs[ident.getIdentifier()];
+ if (id != 0)
+ return id;
+
+ id = ++LastIdentifierID;
+ IdentifiersToWrite.push_back(ident.getIdentifier());
return id;
-
- id = ++LastIdentifierID;
- IdentifiersToWrite.push_back(ident.getIdentifier());
- return id;
+ }
+ case DeclBaseName::Kind::Subscript:
+ return SUBSCRIPT_ID;
+ }
}
IdentifierID Serializer::addModuleRef(const ModuleDecl *M) {
@@ -1708,12 +1729,9 @@
abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code];
bool isProtocolExt = SD->getDeclContext()->getAsProtocolExtensionContext();
- auto iid = addDeclBaseNameRef(SD->getBaseName().getIdentifier());
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
- addTypeRef(ty),
- iid,
- isProtocolExt,
- SD->isStatic());
+ addTypeRef(ty), SUBSCRIPT_ID,
+ isProtocolExt, SD->isStatic());
break;
}
@@ -4348,8 +4366,7 @@
// Add operator methods.
// Note that we don't have to add operators that are already in the
// top-level list.
- auto iid = memberValue->getBaseName().getIdentifier();
- operatorMethodDecls[iid].push_back({
+ operatorMethodDecls[memberValue->getBaseName()].push_back({
/*ignored*/0,
S.addDeclRef(memberValue)
});
diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h
index e65d04f..e885cfd 100644
--- a/lib/Serialization/Serialization.h
+++ b/lib/Serialization/Serialization.h
@@ -221,10 +221,10 @@
/// The last assigned IdentifierID for types from this module.
///
- /// Note that special module IDs must not be valid IdentifierIDs, except that
- /// 0 will always represent the empty identifier.
+ /// Note that special module IDs and IDs of special names must not be valid
+ /// IdentifierIDs, except that 0 will always represent the empty identifier.
uint32_t /*IdentifierID*/ LastIdentifierID =
- serialization::NUM_SPECIAL_MODULES - 1;
+ serialization::NUM_SPECIAL_IDS - 1;
/// The last assigned GenericEnvironmentID for generic environments from this
/// module.
diff --git a/test/Interpreter/subscripting.swift b/test/Interpreter/subscripting.swift
new file mode 100644
index 0000000..f3151b5
--- /dev/null
+++ b/test/Interpreter/subscripting.swift
@@ -0,0 +1,17 @@
+// RUN: %target-run-simple-swift | %FileCheck %s
+// REQUIRES: executable_test
+
+// Check that subscripts and functions named subscript can exist side-by-side
+struct Foo {
+ subscript() -> String {
+ return "subscript"
+ }
+
+ func `subscript`() -> String {
+ return "func"
+ }
+}
+
+let f = Foo()
+print(f[]) // CHECK: subscript
+print(f.subscript()) // CHECK: func
diff --git a/test/SIL/Parser/function_named_subscript.sil b/test/SIL/Parser/function_named_subscript.sil
new file mode 100644
index 0000000..3830d01
--- /dev/null
+++ b/test/SIL/Parser/function_named_subscript.sil
@@ -0,0 +1,23 @@
+// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
+
+// Make sure that we can parse escaped subscripts (representing functions named "subscript") in vtables
+
+sil_stage raw
+
+import Builtin
+import Swift
+import SwiftShims
+
+class SubscriptAsFunction {
+ func `subscript`()
+}
+
+sil hidden @_T04test19SubscriptAsFunctionC9subscriptyyF : $@convention(method) (@guaranteed SubscriptAsFunction) -> () {
+bb0(%0 : $SubscriptAsFunction):
+ return undef : $()
+}
+
+sil_vtable SubscriptAsFunction {
+ // CHECK: #SubscriptAsFunction.`subscript`!1: (SubscriptAsFunction) -> () -> () : _T04test19SubscriptAsFunctionC9subscriptyyF
+ #SubscriptAsFunction.`subscript`!1: (SubscriptAsFunction) -> () -> () : _T04test19SubscriptAsFunctionC9subscriptyyF
+}
diff --git a/test/SILGen/vtables.swift b/test/SILGen/vtables.swift
index aee60e7..09517c7 100644
--- a/test/SILGen/vtables.swift
+++ b/test/SILGen/vtables.swift
@@ -171,3 +171,15 @@
// CHECK-LABEL: sil_vtable DerivedWithoutDefaults {
// CHECK: #BaseWithDefaults.a!1: {{.*}} : _T07vtables22DerivedWithoutDefaultsC1a{{[_0-9a-zA-Z]*}}F
+
+
+
+// Escape identifiers that represent special names
+
+class SubscriptAsFunction {
+ func `subscript`() {}
+}
+
+// CHECK-LABEL: sil_vtable SubscriptAsFunction {
+// CHECK-NOT: #SubscriptAsFunction.subscript
+// CHECK: #SubscriptAsFunction.`subscript`!1
diff --git a/test/decl/protocol/conforms/fixit_stub.swift b/test/decl/protocol/conforms/fixit_stub.swift
index 776be7b..4224a08 100644
--- a/test/decl/protocol/conforms/fixit_stub.swift
+++ b/test/decl/protocol/conforms/fixit_stub.swift
@@ -192,3 +192,9 @@
func bar2() {}
}
+protocol ProtocolHasSubscriptFunction {
+ func `subscript`() // expected-note{{protocol requires function 'subscript()' with type '() -> ()'; do you want to add a stub?}} {{74-74=\n func `subscript`() {\n <#code#>\n \}\n}}
+}
+class ProtocolHasSubscriptFunctionAdopter: ProtocolHasSubscriptFunction { // expected-error{{type 'ProtocolHasSubscriptFunctionAdopter' does not conform to protocol 'ProtocolHasSubscriptFunction'}}
+
+}
diff --git a/test/decl/subscript/subscripting.swift b/test/decl/subscript/subscripting.swift
index 88a7a91..32058f5 100644
--- a/test/decl/subscript/subscripting.swift
+++ b/test/decl/subscript/subscripting.swift
@@ -310,3 +310,12 @@
}
}
}
+
+// SR-2575
+struct SR2575 {
+ subscript() -> Int {
+ return 1
+ }
+}
+
+SR2575().subscript() // expected-error{{type 'SR2575' has no member 'subscript'}}
diff --git a/test/expr/unary/selector/selector.swift b/test/expr/unary/selector/selector.swift
index 7eef1c0..127d1cf 100644
--- a/test/expr/unary/selector/selector.swift
+++ b/test/expr/unary/selector/selector.swift
@@ -115,7 +115,7 @@
}
func testParseErrors4() {
- _ = #selector(C1.subscript) // expected-error{{type 'C1.Type' has no subscript members}}
+ _ = #selector(C1.subscript) // expected-error{{type 'C1' has no member 'subscript'}}
}
// SR-1827
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 9cc803d..3533d1a 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -1091,13 +1091,30 @@
return false;
}
+/// Converts a DeclBaseName to a string by assigning special names strings and
+/// escaping identifiers that would clash with these strings using '`'
+static StringRef getEscapedName(DeclBaseName name) {
+ switch (name.getKind()) {
+ case DeclBaseName::Kind::Subscript:
+ return "subscript";
+ case DeclBaseName::Kind::Normal:
+ return llvm::StringSwitch<StringRef>(name.getIdentifier().str())
+ .Case("subscript", "`subscript`")
+ .Default(name.getIdentifier().str());
+ }
+}
+
static StringRef getPrintedName(SDKContext &Ctx, ValueDecl *VD) {
llvm::SmallString<32> Result;
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD)) {
auto DM = FD->getFullName();
- // TODO: Handle special names
- Result.append(DM.getBaseName().empty() ? "_" :DM.getBaseIdentifier().str());
+ if (DM.getBaseName().empty()) {
+ Result.append("_");
+ } else {
+ Result.append(getEscapedName(DM.getBaseName()));
+ }
+
Result.append("(");
for (auto Arg : DM.getArgumentNames()) {
Result.append(Arg.empty() ? "_" : Arg.str());
@@ -1107,8 +1124,7 @@
return Ctx.buffer(Result.str());
}
auto DM = VD->getFullName();
- // TODO: Handle special names
- Result.append(DM.getBaseIdentifier().str());
+ Result.append(getEscapedName(DM.getBaseName()));
return Ctx.buffer(Result.str());
}
@@ -1147,9 +1163,8 @@
TypeAttrs.push_back(TypeAttrKind::TAK_noescape);
}
-// TODO: Handle special names
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) : Ctx(Ctx),
- Name(VD->hasName() ? VD->getBaseName().getIdentifier().str() : Ctx.buffer("_")),
+ Name(VD->hasName() ? getEscapedName(VD->getBaseName()) : Ctx.buffer("_")),
PrintedName(getPrintedName(Ctx, VD)), DKind(VD->getKind()),
USR(calculateUsr(Ctx, VD)), Location(calculateLocation(Ctx, VD)),
ModuleName(VD->getModuleContext()->getName().str()),
diff --git a/validation-test/Sema/type_checker_crashers/rdar27017206.swift b/validation-test/Sema/type_checker_crashers/rdar27017206.swift
deleted file mode 100644
index 6d2857a..0000000
--- a/validation-test/Sema/type_checker_crashers/rdar27017206.swift
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: not --crash %target-swift-frontend %s -typecheck
-// REQUIRES: asserts
-
-var str = "Hello"
-String(str.characters.subscript(
- str.characters.startIndex..<str.characters.endIndex))
diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27017206.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27017206.swift
new file mode 100644
index 0000000..77a067e
--- /dev/null
+++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27017206.swift
@@ -0,0 +1,5 @@
+// RUN: not %target-swift-frontend %s -typecheck
+
+var str = "Hello"
+String(str.characters.subscript(
+ str.characters.startIndex..<str.characters.endIndex))