mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
conformances rdar://16539292 This is a hack in visible decl lookup. The general solution that would also improve type checker errors would be to make the type checker keep these broken conformances and syntethize missing declarations to make downstream code type check. For that, see: <rdar://problem/16723339> [QoI] Type checker should not be dropping protocol conformances explicitly spelled in the source Swift SVN r16818
364 lines
11 KiB
C++
364 lines
11 KiB
C++
//===--- NameLookup.h - Swift Name Lookup Routines --------------*- C++ -*-===//
|
|
//
|
|
// 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 defines interfaces for performing name lookup.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_NAME_LOOKUP_H
|
|
#define SWIFT_AST_NAME_LOOKUP_H
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "swift/AST/Identifier.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/Basic/Optional.h"
|
|
#include "swift/Basic/SourceLoc.h"
|
|
|
|
namespace swift {
|
|
class ASTContext;
|
|
class DeclContext;
|
|
class DeclName;
|
|
class Expr;
|
|
class LazyResolver;
|
|
class Module;
|
|
class TupleType;
|
|
class Type;
|
|
class TypeDecl;
|
|
class ValueDecl;
|
|
|
|
/// UnqualifiedLookupResult - One result of unqualified lookup.
|
|
struct UnqualifiedLookupResult {
|
|
private:
|
|
ValueDecl *Base;
|
|
union {
|
|
ValueDecl *Value;
|
|
Module *NamedModule;
|
|
};
|
|
|
|
public:
|
|
/// Kind - The kind of reference.
|
|
enum KindTy {
|
|
/// ModuleMember - "x" refers to a value declared at module scope.
|
|
ModuleMember,
|
|
|
|
/// LocalDecl - "x" refers to a value declared in a local scope.
|
|
LocalDecl,
|
|
|
|
/// MemberProperty - "x" refers to an instance property of a type which
|
|
/// is a containing scope.
|
|
MemberProperty,
|
|
|
|
/// MemberFunction - "x" refers to an instance function of a type
|
|
/// is a containing scope. If the lookup is inside an instance function
|
|
/// of the containing type, it refers to the instance function; otherwise,
|
|
/// it refers to the curried function on the metatype.
|
|
MemberFunction,
|
|
|
|
/// MetatypeMember - "x" refers to a member of a metatype "A", which is a
|
|
/// referred to by BaseDecl.
|
|
MetatypeMember,
|
|
|
|
/// ExistentialMember - "x" refers to a member of an existential type,
|
|
/// which is referred to by BaseDecl.
|
|
ExistentialMember,
|
|
|
|
/// ArchetypeMember - "x" refers to a member of an archetype type,
|
|
/// which is referred to by BaseDecl.
|
|
ArchetypeMember,
|
|
|
|
/// MetaArchetypeMember - "x" refers to a member of the metatype of an
|
|
/// archetype type, which is referred to by BaseDecl. The base is evaluated
|
|
/// and ignored.
|
|
MetaArchetypeMember,
|
|
|
|
/// ModuleName - "x" refers to a module, either the current
|
|
/// module or an imported module.
|
|
ModuleName
|
|
} Kind;
|
|
|
|
bool hasValueDecl() const {
|
|
return Kind != ModuleName;
|
|
}
|
|
|
|
ValueDecl *getValueDecl() const {
|
|
assert(hasValueDecl());
|
|
return Value;
|
|
}
|
|
|
|
Module *getNamedModule() const {
|
|
assert(Kind == ModuleName);
|
|
return NamedModule;
|
|
}
|
|
|
|
ValueDecl *getBaseDecl() const {
|
|
return Base;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getModuleMember(ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = nullptr;
|
|
R.Value = value;
|
|
R.Kind = ModuleMember;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getLocalDecl(ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = nullptr;
|
|
R.Value = value;
|
|
R.Kind = LocalDecl;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getMemberProperty(ValueDecl *base,
|
|
ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = base;
|
|
R.Value = value;
|
|
R.Kind = MemberProperty;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getMemberFunction(ValueDecl *base,
|
|
ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = base;
|
|
R.Value = value;
|
|
R.Kind = MemberFunction;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getMetatypeMember(ValueDecl *base,
|
|
ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = base;
|
|
R.Value = value;
|
|
R.Kind = MetatypeMember;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getExistentialMember(ValueDecl *base,
|
|
ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = base;
|
|
R.Value = value;
|
|
R.Kind = ExistentialMember;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getArchetypeMember(ValueDecl *base,
|
|
ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = base;
|
|
R.Value = value;
|
|
R.Kind = ArchetypeMember;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getMetaArchetypeMember(ValueDecl *base,
|
|
ValueDecl *value) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = base;
|
|
R.Value = value;
|
|
R.Kind = MetaArchetypeMember;
|
|
return R;
|
|
}
|
|
|
|
static UnqualifiedLookupResult getModuleName(Module *m) {
|
|
UnqualifiedLookupResult R;
|
|
R.Base = nullptr;
|
|
R.NamedModule = m;
|
|
R.Kind = ModuleName;
|
|
return R;
|
|
}
|
|
};
|
|
|
|
/// \brief This class implements and represents the result of performing
|
|
/// unqualified lookup (i.e. lookup for a plain identifier).
|
|
class UnqualifiedLookup {
|
|
public:
|
|
/// \brief Lookup an unqualified identifier \p Name in the context.
|
|
///
|
|
/// If the current DeclContext is nested in a function body, the SourceLoc
|
|
/// is used to determine which declarations in that body are visible.
|
|
UnqualifiedLookup(DeclName Name, DeclContext *DC,
|
|
LazyResolver *TypeResolver,
|
|
SourceLoc Loc = SourceLoc(),
|
|
bool IsTypeLookup = false);
|
|
|
|
/// \brief Look up an identifier \p Name in the module named \p Module.
|
|
///
|
|
/// Note that this will not resolve types.
|
|
static Optional<UnqualifiedLookup> forModuleAndName(ASTContext &C,
|
|
StringRef Module,
|
|
StringRef Name);
|
|
|
|
SmallVector<UnqualifiedLookupResult, 4> Results;
|
|
|
|
/// \brief Return true if anything was found by the name lookup.
|
|
bool isSuccess() const { return !Results.empty(); }
|
|
|
|
/// \brief Get the result as a single type, or a null type if that fails.
|
|
TypeDecl *getSingleTypeResult();
|
|
};
|
|
|
|
/// Describes the reason why a certain declaration is visible.
|
|
enum class DeclVisibilityKind {
|
|
/// Declaration is a local variable or type.
|
|
LocalVariable,
|
|
|
|
/// Declaration is a function parameter.
|
|
FunctionParameter,
|
|
|
|
/// Declaration is a generic parameter.
|
|
GenericParameter,
|
|
|
|
/// Declaration is a member of the immediately enclosing nominal decl.
|
|
///
|
|
/// For example, 'Foo' is visible at (1) because of this.
|
|
/// \code
|
|
/// struct A {
|
|
/// typealias Foo = Int
|
|
/// func f() {
|
|
/// // (1)
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
MemberOfCurrentNominal,
|
|
|
|
/// Declaration that is a requirement of a protocol implemented by the
|
|
/// immediately enclosing nominal decl, in case the nominal decl does not
|
|
/// supply a witness for this requirement.
|
|
///
|
|
/// For example, 'foo' is visible at (1) because of this.
|
|
/// \code
|
|
/// protocol P {
|
|
/// func foo()
|
|
/// }
|
|
/// struct A : P {
|
|
/// func bar() {
|
|
/// // (1)
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
MemberOfProtocolImplementedByCurrentNominal,
|
|
|
|
/// Declaration is a member of the superclass of the immediately enclosing
|
|
/// nominal decl.
|
|
MemberOfSuper,
|
|
|
|
/// Declaration is a member of the non-immediately enclosing nominal decl.
|
|
///
|
|
/// For example, 'Foo' is visible at (1) because of this.
|
|
/// \code
|
|
/// struct A {
|
|
/// typealias Foo = Int
|
|
/// struct B {
|
|
/// func foo() {
|
|
/// // (1)
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
MemberOfOutsideNominal,
|
|
|
|
/// Declaration is visible at the top level because it is declared in this
|
|
/// module or in a imported module.
|
|
VisibleAtTopLevel,
|
|
|
|
/// Declaration was found via \c AnyObject or \c AnyObject.Type.
|
|
DynamicLookup,
|
|
};
|
|
|
|
/// An abstract base class for a visitor that consumes declarations found within
|
|
/// a given context.
|
|
class VisibleDeclConsumer {
|
|
virtual void anchor();
|
|
public:
|
|
virtual ~VisibleDeclConsumer() = default;
|
|
|
|
/// This method is called by findVisibleDecls() every time it finds a decl.
|
|
virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) = 0;
|
|
};
|
|
|
|
/// A consumer that inserts found decls into an externally-owned SmallVector.
|
|
class VectorDeclConsumer : public VisibleDeclConsumer {
|
|
virtual void anchor();
|
|
public:
|
|
SmallVectorImpl<ValueDecl *> &results;
|
|
explicit VectorDeclConsumer(SmallVectorImpl<ValueDecl *> &decls)
|
|
: results(decls) {}
|
|
|
|
virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
|
|
results.push_back(VD);
|
|
}
|
|
};
|
|
|
|
/// \brief Remove any declarations in the given set that are shadowed by
|
|
/// other declarations in that set.
|
|
///
|
|
/// \param decls The set of declarations being considered.
|
|
/// \param curModule The current module.
|
|
/// \param typeResolver Used to resolve overload types.
|
|
void removeShadowedDecls(SmallVectorImpl<ValueDecl*> &decls,
|
|
const Module *curModule,
|
|
LazyResolver *typeResolver);
|
|
|
|
/// Finds decls visible in the given context and feeds them to the given
|
|
/// VisibleDeclConsumer. If the current DeclContext is nested in a function,
|
|
/// the SourceLoc is used to determine which declarations in that function
|
|
/// are visible.
|
|
void lookupVisibleDecls(VisibleDeclConsumer &Consumer,
|
|
const DeclContext *DC,
|
|
LazyResolver *typeResolver,
|
|
bool IncludeTopLevel,
|
|
SourceLoc Loc = SourceLoc());
|
|
|
|
/// Finds decls visible as members of the given type and feeds them to the given
|
|
/// VisibleDeclConsumer.
|
|
///
|
|
/// \param CurrDC the DeclContext from which the lookup is done.
|
|
void lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer,
|
|
Type BaseTy,
|
|
const DeclContext *CurrDC,
|
|
LazyResolver *typeResolver);
|
|
|
|
namespace namelookup {
|
|
enum class ResolutionKind {
|
|
/// Lookup can match any number of decls, as long as they are all
|
|
/// overloadable.
|
|
///
|
|
/// If non-overloadable decls are returned, this indicates ambiguous lookup.
|
|
Overloadable,
|
|
|
|
/// Lookup should match a single decl.
|
|
Exact,
|
|
|
|
/// Lookup should match a single decl that declares a type.
|
|
TypesOnly
|
|
};
|
|
|
|
/// Performs a qualified lookup into the given module and, if necessary, its
|
|
/// reexports, observing proper shadowing rules.
|
|
void
|
|
lookupVisibleDeclsInModule(Module *M, Module::AccessPathTy accessPath,
|
|
SmallVectorImpl<ValueDecl *> &decls,
|
|
NLKind lookupKind,
|
|
ResolutionKind resolutionKind,
|
|
LazyResolver *typeResolver,
|
|
ArrayRef<Module::ImportedModule> extraImports = {});
|
|
} // end namespace namelookup
|
|
} // end namespace swift
|
|
|
|
#endif
|