mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
functions. This involves a few steps: - When assigning archetypes to type parameters, also walk all of the protocols to which the type parameter conforms and assign archetypes to each of the associated types. - When performing name lookup into an archetype, look into all of the protocols to which it conforms. If we find something, it can be referenced via the new ArchetypeMemberRefExpr. - When type-checking ArchetypeMemberRefExpr, substitute the values of the various associated types into the type of the member, so the resulting expression involves the archetypes for the enclosing generic method. The rest of the type checking essentially follows from the fact that archetypes are unique types which (therefore) have no behavior beyond what is provided via the protocols they conform to. However, there is still much work to do to ensure that we get the archetypes set up correctly. Swift SVN r2201
410 lines
15 KiB
C++
410 lines
15 KiB
C++
//===--- NameBinding.cpp - Name Binding -----------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements name binding for Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Subsystems.h"
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/AST/Component.h"
|
|
#include "swift/AST/Diagnostics.h"
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/ADT/TinyPtrVector.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/system_error.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include <algorithm>
|
|
using namespace swift;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// NameBinder
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
typedef TranslationUnit::ImportedModule ImportedModule;
|
|
typedef llvm::PointerUnion<const ImportedModule*, OneOfType*> BoundScope;
|
|
|
|
namespace {
|
|
class NameBinder {
|
|
llvm::error_code findModule(StringRef Module,
|
|
SourceLoc ImportLoc,
|
|
llvm::OwningPtr<llvm::MemoryBuffer> &Buffer);
|
|
|
|
public:
|
|
TranslationUnit *TU;
|
|
ASTContext &Context;
|
|
bool ImportedBuiltinModule;
|
|
|
|
NameBinder(TranslationUnit *TU)
|
|
: TU(TU), Context(TU->Ctx), ImportedBuiltinModule(false) {
|
|
for (auto M : TU->getImportedModules())
|
|
Context.LoadedModules[M.second->Name.str()] = M.second;
|
|
}
|
|
~NameBinder() {
|
|
}
|
|
|
|
template<typename ...ArgTypes>
|
|
InFlightDiagnostic diagnose(ArgTypes... Args) {
|
|
return Context.Diags.diagnose(Args...);
|
|
}
|
|
|
|
void addImport(ImportDecl *ID, SmallVectorImpl<ImportedModule> &Result);
|
|
void addStandardLibraryImport(SmallVectorImpl<ImportedModule> &Result);
|
|
|
|
/// resolveIdentifierType - Perform name binding for a IdentifierType,
|
|
/// resolving it or diagnosing the error as appropriate and return true on
|
|
/// failure. On failure, this leaves IdentifierType alone, otherwise it
|
|
/// fills in the Components.
|
|
bool resolveIdentifierType(IdentifierType *DNT, DeclContext *DC);
|
|
|
|
private:
|
|
/// getModule - Load a module referenced by an import statement,
|
|
/// emitting an error at the specified location and returning null on
|
|
/// failure.
|
|
Module *getModule(std::pair<Identifier,SourceLoc> ModuleID);
|
|
};
|
|
}
|
|
|
|
llvm::error_code NameBinder::findModule(StringRef Module,
|
|
SourceLoc ImportLoc,
|
|
llvm::OwningPtr<llvm::MemoryBuffer> &Buffer) {
|
|
std::string ModuleFilename = Module.str() + std::string(".swift");
|
|
|
|
llvm::SmallString<128> InputFilename;
|
|
|
|
// First, search in the directory corresponding to the import location.
|
|
// FIXME: This screams for a proper FileManager abstraction.
|
|
llvm::SourceMgr &SourceMgr = Context.SourceMgr;
|
|
int CurrentBufferID = SourceMgr.FindBufferContainingLoc(ImportLoc.Value);
|
|
if (CurrentBufferID >= 0) {
|
|
const llvm::MemoryBuffer *ImportingBuffer
|
|
= SourceMgr.getBufferInfo(CurrentBufferID).Buffer;
|
|
StringRef CurrentDirectory
|
|
= llvm::sys::path::parent_path(ImportingBuffer->getBufferIdentifier());
|
|
if (!CurrentDirectory.empty()) {
|
|
InputFilename = CurrentDirectory;
|
|
llvm::sys::path::append(InputFilename, ModuleFilename);
|
|
llvm::error_code Err = llvm::MemoryBuffer::getFile(InputFilename, Buffer);
|
|
if (!Err)
|
|
return Err;
|
|
}
|
|
}
|
|
|
|
// Second, search in the current directory.
|
|
llvm::error_code Err = llvm::MemoryBuffer::getFile(ModuleFilename, Buffer);
|
|
if (!Err)
|
|
return Err;
|
|
|
|
// If we fail, search each import search path.
|
|
for (auto Path : Context.ImportSearchPaths) {
|
|
InputFilename = Path;
|
|
llvm::sys::path::append(InputFilename, ModuleFilename);
|
|
Err = llvm::MemoryBuffer::getFile(InputFilename, Buffer);
|
|
if (!Err)
|
|
return Err;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
Module *NameBinder::getModule(std::pair<Identifier, SourceLoc> ModuleID) {
|
|
// TODO: We currently just recursively parse referenced modules. This works
|
|
// fine for now since they are each a single file. Ultimately we'll want a
|
|
// compiled form of AST's like clang's that support lazy deserialization.
|
|
|
|
// FIXME: We shouldn't really allow arbitrary modules to import Builtin.
|
|
if (ModuleID.first.str() == "Builtin") {
|
|
ImportedBuiltinModule = true;
|
|
return TU->Ctx.TheBuiltinModule;
|
|
}
|
|
|
|
Module *M = Context.LoadedModules.lookup(ModuleID.first.str());
|
|
if (M) return M;
|
|
|
|
// Open the input file.
|
|
llvm::OwningPtr<llvm::MemoryBuffer> InputFile;
|
|
if (llvm::error_code Err = findModule(ModuleID.first.str(), ModuleID.second,
|
|
InputFile)) {
|
|
diagnose(ModuleID.second, diag::sema_opening_import,
|
|
ModuleID.first.str(), Err.message());
|
|
return 0;
|
|
}
|
|
|
|
unsigned BufferID =
|
|
Context.SourceMgr.AddNewSourceBuffer(InputFile.take(),
|
|
ModuleID.second.Value);
|
|
|
|
// For now, treat all separate modules as unique components.
|
|
Component *Comp = new (Context.Allocate<Component>(1)) Component();
|
|
TranslationUnit *ImportedTU;
|
|
ImportedTU = new (Context) TranslationUnit(ModuleID.first, Comp, Context,
|
|
/*IsMainModule*/false,
|
|
/*IsReplModule*/false);
|
|
|
|
parseIntoTranslationUnit(ImportedTU, BufferID);
|
|
Context.LoadedModules[ModuleID.first.str()] = ImportedTU;
|
|
|
|
// We have to do name binding on it to ensure that types are fully resolved.
|
|
// This should eventually be eliminated by having actual fully resolved binary
|
|
// dumps of the code instead of reparsing though.
|
|
// FIXME: We also need to deal with circular imports!
|
|
performNameBinding(ImportedTU);
|
|
performTypeChecking(ImportedTU);
|
|
|
|
return ImportedTU;
|
|
}
|
|
|
|
|
|
void NameBinder::addImport(ImportDecl *ID,
|
|
SmallVectorImpl<ImportedModule> &Result) {
|
|
ArrayRef<ImportDecl::AccessPathElement> Path = ID->getAccessPath();
|
|
Module *M = getModule(Path[0]);
|
|
if (M == 0) return;
|
|
|
|
// FIXME: Validate the access path against the module. Reject things like
|
|
// import swift.aslkdfja
|
|
if (Path.size() > 2) {
|
|
diagnose(Path[2].second, diag::invalid_declaration_imported);
|
|
return;
|
|
}
|
|
|
|
Result.push_back(std::make_pair(Path.slice(1), M));
|
|
}
|
|
|
|
void NameBinder::
|
|
addStandardLibraryImport(SmallVectorImpl<ImportedModule> &Result) {
|
|
// FIXME: The current model is that if a module doesn't explicitly import
|
|
// Builtin or swift, we implicitly import swift. This isn't really ideal.
|
|
if (ImportedBuiltinModule)
|
|
return;
|
|
for (ImportedModule M : Result)
|
|
if (M.second->Name.str() == "swift")
|
|
return;
|
|
if (TU->Name.str() == "swift")
|
|
return;
|
|
|
|
Identifier SwiftID = Context.getIdentifier("swift");
|
|
Module *M = getModule(std::make_pair(SwiftID, TU->Decls[0]->getStartLoc()));
|
|
if (M == 0) return;
|
|
Result.push_back(std::make_pair(Module::AccessPathTy(), M));
|
|
}
|
|
|
|
/// resolveIdentifierType - Perform name binding for a IdentifierType,
|
|
/// resolving it or diagnosing the error as appropriate and return true on
|
|
/// failure. On failure, this leaves IdentifierType alone, otherwise it fills
|
|
/// in the Components.
|
|
bool NameBinder::resolveIdentifierType(IdentifierType *DNT, DeclContext *DC) {
|
|
const MutableArrayRef<IdentifierType::Component> &Components =DNT->Components;
|
|
|
|
// If name lookup for the base of the type didn't get resolved in the
|
|
// parsing phase, perform lookup on it.
|
|
if (Components[0].Value.isNull()) {
|
|
Identifier Name = Components[0].Id;
|
|
SourceLoc Loc = Components[0].Loc;
|
|
|
|
// Perform an unqualified lookup.
|
|
UnqualifiedLookup Globals(Name, DC);
|
|
|
|
if (Globals.Results.size() > 1) {
|
|
diagnose(Loc, diag::abiguous_type_base, Name)
|
|
<< SourceRange(Loc, Components.back().Loc);
|
|
for (auto Result : Globals.Results) {
|
|
if (Globals.Results[0].hasValueDecl())
|
|
diagnose(Result.getValueDecl()->getStartLoc(), diag::found_candidate);
|
|
else
|
|
diagnose(Loc, diag::found_candidate);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (Globals.Results.empty()) {
|
|
diagnose(Loc, Components.size() == 1 ?
|
|
diag::use_undeclared_type : diag::unknown_name_in_type, Name)
|
|
<< SourceRange(Loc, Components.back().Loc);
|
|
return true;
|
|
}
|
|
|
|
switch (Globals.Results[0].Kind) {
|
|
case UnqualifiedLookupResult::ModuleMember:
|
|
case UnqualifiedLookupResult::LocalDecl:
|
|
case UnqualifiedLookupResult::MemberProperty:
|
|
case UnqualifiedLookupResult::MemberFunction:
|
|
case UnqualifiedLookupResult::MetatypeMember:
|
|
case UnqualifiedLookupResult::ExistentialMember:
|
|
case UnqualifiedLookupResult::ArchetypeMember:
|
|
Components[0].Value = Globals.Results[0].getValueDecl();
|
|
break;
|
|
case UnqualifiedLookupResult::ModuleName:
|
|
Components[0].Value = Globals.Results[0].getNamedModule();
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(!Components[0].Value.isNull() && "Failed to get a base");
|
|
|
|
// Now that we have a base, iteratively resolve subsequent member entries.
|
|
auto LastOne = Components[0];
|
|
for (auto &C : Components.slice(1, Components.size()-1)) {
|
|
// TODO: Only support digging into modules so far.
|
|
if (auto M = LastOne.Value.dyn_cast<Module*>()) {
|
|
SmallVector<ValueDecl*, 8> Decls;
|
|
M->lookupValue(Module::AccessPathTy(), C.Id,
|
|
NLKind::QualifiedLookup, Decls);
|
|
if (Decls.size() == 1 && isa<TypeDecl>(Decls.back()))
|
|
C.Value = cast<TypeDecl>(Decls.back());
|
|
} else {
|
|
diagnose(C.Loc, diag::unknown_dotted_type_base, LastOne.Id)
|
|
<< SourceRange(Components[0].Loc, Components.back().Loc);
|
|
return true;
|
|
}
|
|
|
|
if (C.Value.isNull()) {
|
|
diagnose(C.Loc, diag::invalid_member_type, C.Id, LastOne.Id)
|
|
<< SourceRange(Components[0].Loc, Components.back().Loc);
|
|
return true;
|
|
}
|
|
|
|
LastOne = C;
|
|
}
|
|
|
|
// Finally, sanity check that the last value is a type.
|
|
if (ValueDecl *Last = Components.back().Value.dyn_cast<ValueDecl*>())
|
|
if (auto TAD = dyn_cast<TypeDecl>(Last)) {
|
|
Components[Components.size()-1].Value = TAD->getDeclaredType();
|
|
return false;
|
|
}
|
|
|
|
diagnose(Components.back().Loc,
|
|
Components.size() == 1 ? diag::named_definition_isnt_type :
|
|
diag::dotted_reference_not_type, Components.back().Id)
|
|
<< SourceRange(Components[0].Loc, Components.back().Loc);
|
|
return true;
|
|
}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// performNameBinding
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// \brief Determine the number of type contexts from DC to the module
|
|
/// context.
|
|
static unsigned getDeclContextTypeDepth(DeclContext *DC) {
|
|
unsigned Depth = 0;
|
|
while (!DC->isModuleContext()) {
|
|
if (DC->isTypeContext())
|
|
++Depth;
|
|
DC = DC->getParent();
|
|
}
|
|
return Depth;
|
|
}
|
|
|
|
/// performNameBinding - Once parsing is complete, this walks the AST to
|
|
/// resolve names and do other top-level validation.
|
|
///
|
|
/// At this parsing has been performed, but we still have UnresolvedDeclRefExpr
|
|
/// nodes for unresolved value names, and we may have unresolved type names as
|
|
/// well. This handles import directives and forward references.
|
|
void swift::performNameBinding(TranslationUnit *TU, unsigned StartElem) {
|
|
// Make sure we skip adding the standard library imports if the
|
|
// translation unit is empty.
|
|
if (TU->Decls.empty()) {
|
|
TU->ASTStage = TranslationUnit::NameBound;
|
|
return;
|
|
}
|
|
|
|
bool IsInitialNameBinding = TU->getImportedModules().empty();
|
|
|
|
// Reset the name lookup cache so we find new decls.
|
|
// FIXME: This is inefficient.
|
|
TU->clearLookupCache();
|
|
|
|
NameBinder Binder(TU);
|
|
|
|
SmallVector<ImportedModule, 8> ImportedModules;
|
|
ImportedModules.append(TU->getImportedModules().begin(),
|
|
TU->getImportedModules().end());
|
|
|
|
// Do a prepass over the declarations to find and load the imported modules.
|
|
for (unsigned i = StartElem, e = TU->Decls.size(); i != e; ++i)
|
|
if (ImportDecl *ID = dyn_cast<ImportDecl>(TU->Decls[i]))
|
|
Binder.addImport(ID, ImportedModules);
|
|
|
|
// Add the standard library import.
|
|
// FIXME: The semantics here are sort of strange if an import statement is
|
|
// after the first "chunk" in the main module.
|
|
if (IsInitialNameBinding)
|
|
Binder.addStandardLibraryImport(ImportedModules);
|
|
|
|
// FIXME: This algorithm has quadratic memory usage. (In practice,
|
|
// import statements after the first "chunk" should be rare, though.)
|
|
if (ImportedModules.size() > TU->getImportedModules().size())
|
|
TU->setImportedModules(TU->Ctx.AllocateCopy(ImportedModules));
|
|
|
|
// FIXME: This is quadratic time for TUs with multiple chunks.
|
|
// FIXME: Can we make this more efficient?
|
|
// Check for declarations with the same name which aren't overloaded
|
|
// vars/funcs.
|
|
llvm::DenseMap<Identifier, ValueDecl*> CheckTypes;
|
|
for (unsigned i = 0, e = TU->Decls.size(); i != e; ++i) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(TU->Decls[i])) {
|
|
// FIXME: I'm not sure this check is really correct.
|
|
if (VD->getName().empty())
|
|
continue;
|
|
ValueDecl *&LookupD = CheckTypes[VD->getName()];
|
|
ValueDecl *PrevD = LookupD;
|
|
LookupD = VD;
|
|
if (i >= StartElem) {
|
|
if (PrevD && !((isa<VarDecl>(VD) || isa<FuncDecl>(VD)) &&
|
|
(isa<VarDecl>(PrevD) || isa<FuncDecl>(PrevD)))) {
|
|
Binder.diagnose(VD->getStartLoc(), diag::invalid_redecl);
|
|
Binder.diagnose(PrevD->getStartLoc(), diag::invalid_redecl_prev,
|
|
VD->getName());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop over all the unresolved dotted types in the translation unit,
|
|
// resolving them if possible. We first sort the types by their context
|
|
// depth, so they the outermost types (e.g., those on extension declarations)
|
|
// are resolved first.
|
|
// FIXME: This is far from perfect; we also need to deal with a.b.c types
|
|
// that occur in an outer context.
|
|
typedef TranslationUnit::IdentTypeAndContext IdentTypeAndContext;
|
|
SmallVector<IdentTypeAndContext, 4> UnresolvedIdTypes;
|
|
UnresolvedIdTypes.append(TU->getUnresolvedIdentifierTypes().begin(),
|
|
TU->getUnresolvedIdentifierTypes().end());
|
|
std::stable_sort(UnresolvedIdTypes.begin(), UnresolvedIdTypes.end(),
|
|
[](IdentTypeAndContext lhs, IdentTypeAndContext rhs) {
|
|
return getDeclContextTypeDepth(lhs.second) <
|
|
getDeclContextTypeDepth(rhs.second);
|
|
});
|
|
|
|
for (auto IdAndContext : UnresolvedIdTypes) {
|
|
if (Binder.resolveIdentifierType(IdAndContext.first,
|
|
IdAndContext.second)) {
|
|
// This IdentifierType resolved to the error type.
|
|
for (auto &C : IdAndContext.first->Components)
|
|
C.Value = TU->Ctx.TheErrorType;
|
|
}
|
|
}
|
|
|
|
TU->ASTStage = TranslationUnit::NameBound;
|
|
verify(TU);
|
|
}
|
|
|