mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[serialization] Handle cross-module references to values in extensions.
Previously, cross-references used a simple access path to refer to values in other modules, but extensions have no name. They also accidentally picked up values in extensions anyway, because lookupDirect includes members in extensions. Now, we filter out values that don't come from the referenced module, which may not be the same module the base type comes from. Swift SVN r6301
This commit is contained in:
@@ -485,6 +485,18 @@ DeclContext *ModuleFile::getDeclContext(DeclID DID) {
|
||||
llvm_unreachable("unknown DeclContext kind");
|
||||
}
|
||||
|
||||
/// Returns the appropriate module for the given name.
|
||||
///
|
||||
/// An empty name represents the builtin module. All other names are looked up
|
||||
/// in the ASTContext.
|
||||
static Module *getModule(ASTContext &ctx, Identifier name) {
|
||||
if (name.empty())
|
||||
return ctx.TheBuiltinModule;
|
||||
|
||||
// FIXME: provide a real source location.
|
||||
return ctx.getModule(std::make_pair(name, SourceLoc()), false);
|
||||
}
|
||||
|
||||
|
||||
/// Translate from the Serialization assocativity enum values to the AST
|
||||
/// strongly-typed enum.
|
||||
@@ -1210,20 +1222,21 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
Identifier moduleName = getIdentifier(rawAccessPath.front());
|
||||
rawAccessPath = rawAccessPath.slice(1);
|
||||
|
||||
Module *M;
|
||||
if (moduleName.empty()) {
|
||||
M = ctx.TheBuiltinModule;
|
||||
} else {
|
||||
// FIXME: provide a real source location.
|
||||
M = ctx.getModule(std::make_pair(moduleName, SourceLoc()), false);
|
||||
}
|
||||
Module *M = getModule(ctx, moduleName);
|
||||
assert(M && "missing dependency");
|
||||
|
||||
switch (kind) {
|
||||
case XRefKind::SwiftValue: {
|
||||
case XRefKind::SwiftValue:
|
||||
case XRefKind::SwiftExtensionValue: {
|
||||
// Start by looking up the top-level decl in the module.
|
||||
Module *baseModule = M;
|
||||
if (kind == XRefKind::SwiftExtensionValue) {
|
||||
baseModule = getModule(ctx, getIdentifier(rawAccessPath.front()));
|
||||
rawAccessPath = rawAccessPath.slice(1);
|
||||
}
|
||||
|
||||
SmallVector<ValueDecl *, 8> values;
|
||||
M->lookupValue(Module::AccessPathTy(),
|
||||
baseModule->lookupValue(Module::AccessPathTy(),
|
||||
getIdentifier(rawAccessPath.front()),
|
||||
NLKind::QualifiedLookup,
|
||||
values);
|
||||
@@ -1232,40 +1245,42 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
// Then, follow the chain of nested ValueDecls until we run out of
|
||||
// identifiers in the access path.
|
||||
SmallVector<ValueDecl *, 8> baseValues;
|
||||
while (!rawAccessPath.empty()) {
|
||||
for (IdentifierID nextID : rawAccessPath) {
|
||||
baseValues.swap(values);
|
||||
values.clear();
|
||||
for (auto base : baseValues) {
|
||||
// FIXME: extensions?
|
||||
if (auto nominal = dyn_cast<NominalTypeDecl>(base)) {
|
||||
Identifier memberName = getIdentifier(rawAccessPath.front());
|
||||
Identifier memberName = getIdentifier(nextID);
|
||||
auto members = nominal->lookupDirect(memberName);
|
||||
values.append(members.begin(), members.end());
|
||||
}
|
||||
}
|
||||
rawAccessPath = rawAccessPath.slice(1);
|
||||
}
|
||||
|
||||
// If we have a type to validate against, filter out any ValueDecls that
|
||||
// don't match that type.
|
||||
CanType expectedTy;
|
||||
Type maybeExpectedTy = getType(expectedTypeID);
|
||||
if (maybeExpectedTy)
|
||||
if (Type maybeExpectedTy = getType(expectedTypeID))
|
||||
expectedTy = maybeExpectedTy->getCanonicalType();
|
||||
|
||||
ValueDecl *result = nullptr;
|
||||
for (auto value : values) {
|
||||
if (!expectedTy || value->getType()->getCanonicalType() == expectedTy) {
|
||||
if (value->getModuleContext() != M)
|
||||
continue;
|
||||
if (expectedTy && value->getType()->getCanonicalType() != expectedTy)
|
||||
continue;
|
||||
|
||||
if (!result || result == value) {
|
||||
result = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// It's an error if more than one value has the same type.
|
||||
// FIXME: Functions and constructors can overload based on parameter
|
||||
// names.
|
||||
if (result) {
|
||||
error();
|
||||
return nullptr;
|
||||
}
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
|
||||
// It's an error if lookup doesn't actually find anything -- that means
|
||||
// the module's out of date.
|
||||
|
||||
@@ -227,10 +227,6 @@ private:
|
||||
/// Returns the decl context with the given ID, deserializing it if needed.
|
||||
DeclContext *getDeclContext(serialization::DeclID DID);
|
||||
|
||||
Optional<Decl *> requestDecl(serialization::DeclID);
|
||||
|
||||
Optional<Type> requestType(serialization::TypeID);
|
||||
|
||||
/// Returns the decl with the given ID, deserializing it if needed.
|
||||
///
|
||||
/// \param DID The ID for the decl within this module.
|
||||
|
||||
@@ -72,9 +72,10 @@ using AbstractCCField = BCFixed<2>;
|
||||
// VERSION_MAJOR.
|
||||
enum XRefKind : uint8_t {
|
||||
SwiftValue = 0,
|
||||
SwiftExtensionValue,
|
||||
SwiftOperator
|
||||
};
|
||||
using XRefKindField = BCFixed<1>;
|
||||
using XRefKindField = BCFixed<2>;
|
||||
|
||||
// These IDs must \em not be renumbered or reordered without incrementing
|
||||
// VERSION_MAJOR.
|
||||
@@ -637,7 +638,9 @@ namespace decls_block {
|
||||
XREF,
|
||||
XRefKindField, // reference kind
|
||||
TypeIDField, // type if value, operator kind if operator
|
||||
BCArray<IdentifierIDField> // access path
|
||||
BCArray<IdentifierIDField> // extension module name (if extension value)
|
||||
// base module name
|
||||
// access path
|
||||
>;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,14 @@ namespace {
|
||||
/// \returns The ID for the given Identifier in this module.
|
||||
IdentifierID addIdentifierRef(Identifier ident);
|
||||
|
||||
/// Records the use of the given module.
|
||||
///
|
||||
/// The module's name will be scheduled for serialization if necessary.
|
||||
///
|
||||
/// \returns The ID for the identifier for the module's name, or 0 for the
|
||||
/// builtin module.
|
||||
IdentifierID addModuleRef(const Module *M);
|
||||
|
||||
/// Returns the declaration the given generic parameter list is associated
|
||||
/// with.
|
||||
const Decl *getGenericContext(const GenericParamList *paramList);
|
||||
@@ -347,6 +355,14 @@ IdentifierID Serializer::addIdentifierRef(Identifier ident) {
|
||||
return id;
|
||||
}
|
||||
|
||||
IdentifierID Serializer::addModuleRef(const Module *M) {
|
||||
assert(M != TU && "cannot form cross-reference to module being serialized");
|
||||
if (M == TU->Ctx.TheBuiltinModule)
|
||||
return 0;
|
||||
|
||||
return addIdentifierRef(M->Name);
|
||||
}
|
||||
|
||||
const Decl *Serializer::getGenericContext(const GenericParamList *paramList) {
|
||||
auto contextDecl = GenericContexts.lookup(paramList);
|
||||
assert(contextDecl && "Generic parameters not registered yet!");
|
||||
@@ -762,19 +778,21 @@ bool Serializer::writeCrossReference(const Decl *D) {
|
||||
|
||||
// Build up the access path by walking through parent DeclContexts.
|
||||
const DeclContext *DC;
|
||||
const ExtensionDecl *extension = nullptr;
|
||||
for (DC = D->getDeclContext(); !DC->isModuleContext(); DC = DC->getParent()) {
|
||||
// FIXME: Handle references to things in extensions.
|
||||
if (isa<ExtensionDecl>(DC))
|
||||
return false;
|
||||
if ((extension = dyn_cast<ExtensionDecl>(DC)))
|
||||
DC = extension->getExtendedType()->getNominalOrBoundGenericNominal();
|
||||
|
||||
auto value = cast<ValueDecl>(getDeclForContext(DC));
|
||||
accessPath.push_back(addIdentifierRef(value->getName()));
|
||||
}
|
||||
|
||||
if (DC == TU->Ctx.TheBuiltinModule)
|
||||
accessPath.push_back(0);
|
||||
else
|
||||
accessPath.push_back(addIdentifierRef(cast<Module>(DC)->Name));
|
||||
accessPath.push_back(addModuleRef(cast<Module>(DC)));
|
||||
if (extension) {
|
||||
assert(kind == XRefKind::SwiftValue);
|
||||
kind = XRefKind::SwiftExtensionValue;
|
||||
accessPath.push_back(addModuleRef(extension->getModuleContext()));
|
||||
}
|
||||
|
||||
// Store the access path in forward order.
|
||||
std::reverse(accessPath.begin(), accessPath.end());
|
||||
|
||||
9
test/Serialization/Inputs/xref_distraction.swift
Normal file
9
test/Serialization/Inputs/xref_distraction.swift
Normal file
@@ -0,0 +1,9 @@
|
||||
typealias MyInt64 = ()
|
||||
|
||||
struct AliasWrapper {
|
||||
typealias Boolean = ()
|
||||
}
|
||||
|
||||
extension Int {
|
||||
typealias EspeciallyMagicalInt = ()
|
||||
}
|
||||
Reference in New Issue
Block a user