[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:
Jordan Rose
2013-07-16 23:10:33 +00:00
parent 213829f946
commit 6e4f36cab2
5 changed files with 80 additions and 39 deletions

View File

@@ -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.

View File

@@ -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.

View File

@@ -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
>;
}

View File

@@ -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());

View File

@@ -0,0 +1,9 @@
typealias MyInt64 = ()
struct AliasWrapper {
typealias Boolean = ()
}
extension Int {
typealias EspeciallyMagicalInt = ()
}