Skip to content

Module selectors (formerly module qualifiers) #28834

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
82d6df9
Add feature flag for module selector
beccadax Dec 20, 2019
1d04748
Add tok::colon_colon to parser
beccadax Dec 21, 2019
913316f
Parse module selectors in permitted locations
beccadax Dec 21, 2019
9268124
Diagnose incorrect uses of module selectors
beccadax Dec 21, 2019
8ad33f6
Allow `::` as an alias for `.` in imports
beccadax Dec 21, 2019
efb67d4
[NFC] Give withoutArgumentLabels() a context arg
beccadax Dec 21, 2019
525d4d5
[NFC] Stub module selector DeclNameRef/Loc members
beccadax Dec 21, 2019
e251675
[NFC] Add representations for DeclNameRef/Loc with module selector
beccadax Dec 21, 2019
cc8f0fd
[NFC] Serialize module selector fields
beccadax Dec 21, 2019
6a5624e
Make expected errors in module_selector test more readable
beccadax Dec 21, 2019
2d42900
Support module selectors in qualified lookup
beccadax Dec 21, 2019
efb6ebc
Root unqualified lookups with module selectors at file scope
beccadax Dec 21, 2019
143ccc6
[NFC] Improve some lookup-related doc comments
beccadax Dec 21, 2019
fbb20c5
Support module selectors in unqualified lookup
beccadax Dec 21, 2019
dff40f3
Improve diagnostics for types with incorrect module selectors
beccadax Dec 21, 2019
31fd9a3
Add correct(ish) example
beccadax Dec 21, 2019
58bf67b
Improve expression diagnostics for incorrect module selectors
beccadax Dec 21, 2019
6c1bc33
Handle module selectors in UDRE lookups
beccadax Dec 21, 2019
2376bf9
Correct fix-its in module_selector test
beccadax Dec 21, 2019
9dad71b
Fix crash when module in selector doesn’t exist
beccadax Dec 21, 2019
c21199f
Add notes to module_selector test about untested things
beccadax Dec 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2467,11 +2467,10 @@ class ValueDecl : public Decl {
/// names.
DeclBaseName getBaseName() const { return Name.getBaseName(); }

/// Generates a DeclNameRef referring to this declaration with as much
/// specificity as possible.
DeclNameRef createNameRef() const {
return DeclNameRef(getFullName());
}
/// Generates a DeclNameRef referring to this declaration.
///
/// \param moduleSelector If true, the name ref includes the module name.
DeclNameRef createNameRef(bool moduleSelector = false) const;

/// Retrieve the name to use for this declaration when interoperating
/// with the Objective-C runtime.
Expand Down
47 changes: 34 additions & 13 deletions include/swift/AST/DeclNameLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,63 @@ class ASTContext;
class DeclNameLoc {
/// Source location information.
///
/// If \c NumArgumentLabels == 0, this is the SourceLoc for the base name.
/// Otherwise, it points to an array of SourceLocs, which contains:
/// If \c NumArgumentLabels == 0 and \c !HasModuleSelectorLoc, this is the
/// SourceLoc for the base name. Otherwise, it points to an array of
/// SourceLocs, which contains:
/// * The module selector location
/// * The base name location
/// * The left parentheses location
/// * The right parentheses location
/// * The locations of each of the argument labels.
const void *LocationInfo;

/// The number of argument labels stored in the name.
unsigned NumArgumentLabels;
uint32_t NumArgumentLabels;
bool HasModuleSelectorLoc;

enum {
BaseNameIndex = 0,
LParenIndex = 1,
RParenIndex = 2,
FirstArgumentLabelIndex = 3,
ModuleSelectorIndex = 1,
LParenIndex = 2,
RParenIndex = 3,
FirstArgumentLabelIndex = 4,
};

/// Retrieve a pointer to either the only source location that was
/// stored or to the array of source locations that was stored.
SourceLoc const * getSourceLocs() const {
if (NumArgumentLabels == 0)
if (NumArgumentLabels == 0 && !HasModuleSelectorLoc)
return reinterpret_cast<SourceLoc const *>(&LocationInfo);

return reinterpret_cast<SourceLoc const *>(LocationInfo);
}

public:
/// Create an invalid declaration name location.
DeclNameLoc() : LocationInfo(0), NumArgumentLabels(0) { }
DeclNameLoc()
: LocationInfo(0), NumArgumentLabels(0), HasModuleSelectorLoc(false) { }

/// Create declaration name location information for a base name.
explicit DeclNameLoc(SourceLoc baseNameLoc)
: LocationInfo(baseNameLoc.getOpaquePointerValue()),
NumArgumentLabels(0) { }
NumArgumentLabels(0), HasModuleSelectorLoc(false) { }

explicit DeclNameLoc(ASTContext &ctx, SourceLoc moduleSelectorLoc,
SourceLoc baseNameLoc)
: DeclNameLoc(ctx, moduleSelectorLoc, baseNameLoc,
SourceLoc(), {}, SourceLoc()) { }

/// Create declaration name location information for a compound
/// name.
DeclNameLoc(ASTContext &ctx, SourceLoc baseNameLoc,
SourceLoc lParenLoc,
ArrayRef<SourceLoc> argumentLabelLocs,
SourceLoc rParenLoc)
: DeclNameLoc(ctx, SourceLoc(), baseNameLoc,
lParenLoc, argumentLabelLocs, rParenLoc) { }

DeclNameLoc(ASTContext &ctx, SourceLoc moduleSelectorLoc,
SourceLoc baseNameLoc,
SourceLoc lParenLoc,
ArrayRef<SourceLoc> argumentLabelLocs,
SourceLoc rParenLoc);
Expand Down Expand Up @@ -105,8 +123,13 @@ class DeclNameLoc {
return getSourceLocs()[FirstArgumentLabelIndex + index];
}

SourceLoc getModuleSelectorLoc() const {
if (!HasModuleSelectorLoc) return SourceLoc();
return getSourceLocs()[ModuleSelectorIndex];
}

SourceLoc getStartLoc() const {
return getBaseNameLoc();
return HasModuleSelectorLoc ? getModuleSelectorLoc() : getBaseNameLoc();
}

SourceLoc getEndLoc() const {
Expand All @@ -115,9 +138,7 @@ class DeclNameLoc {

/// Retrieve the complete source range for this declaration name.
SourceRange getSourceRange() const {
if (NumArgumentLabels == 0) return getBaseNameLoc();

return SourceRange(getBaseNameLoc(), getRParenLoc());
return SourceRange(getStartLoc(), getEndLoc());
}
};

Expand Down
8 changes: 8 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ ERROR(forbidden_interpolated_string,none,
ERROR(forbidden_extended_escaping_string,none,
"%0 cannot be an extended escaping string literal", (StringRef))

ERROR(expected_identifier_in_module_selector,none,
"expected identifier in module selector", ())
ERROR(module_selector_not_allowed_here,none,
"name cannot be qualified with module selector here", ())
ERROR(module_selector_not_allowed_in_decl,none,
"%select{%1|name of %1 declaration}0 cannot be qualified with module "
"selector", (bool, StringRef))

//------------------------------------------------------------------------------
// MARK: Lexer diagnostics
//------------------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,16 @@ ERROR(use_undeclared_type,none,
"use of undeclared type %0", (DeclNameRef))
ERROR(use_undeclared_type_did_you_mean,none,
"use of undeclared type %0; did you mean to use '%1'?", (DeclNameRef, StringRef))
ERROR(type_not_in_module,none,
"type %0 is not imported through module %1", (DeclName, Identifier))
ERROR(decl_not_in_module,none,
"declaration %0 is not imported through module %1", (DeclName, Identifier))
NOTE(note_change_module_selector,none,
"did you mean module %0?", (Identifier))
NOTE(note_remove_module_selector,none,
"did you mean the local declaration?", ())
NOTE(note_add_explicit_self_with_module_selector,none,
"did you mean the member of 'self'?", ())
NOTE(note_typo_candidate_implicit_member,none,
"did you mean the implicitly-synthesized %1 '%0'?", (StringRef, StringRef))
NOTE(note_remapped_type,none,
Expand Down
110 changes: 81 additions & 29 deletions include/swift/AST/Identifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,74 +615,127 @@ void simple_display(llvm::raw_ostream &out, DeclName name);
/// An in-source reference to another declaration, including qualification
/// information.
class DeclNameRef {
DeclName FullName;
friend class ASTContext;

/// Contains the name and module for a DeclNameRef with a module selector.
struct alignas(Identifier) SelectiveDeclNameRef : llvm::FoldingSetNode {
Identifier moduleSelector; // Note: currently can never be empty().
DeclName fullName;

SelectiveDeclNameRef(Identifier moduleSelector, DeclName fullName)
: moduleSelector(moduleSelector), fullName(fullName) { }

/// Uniquing for the ASTContext.
static void Profile(llvm::FoldingSetNodeID &id, Identifier moduleSelector,
DeclName fullName);

void Profile(llvm::FoldingSetNodeID &id) {
Profile(id, moduleSelector, fullName);
}

// Make vanilla new/delete illegal for SelectiveDeclNameRef.
void *operator new(size_t Bytes) = delete;
void operator delete(void *Data) = delete;

// Only allow allocation of SelectiveDeclNameRef using the allocator
// in ASTContext or by doing a placement new.
void *operator new(size_t Bytes, const ASTContext &C,
unsigned Alignment = alignof(SelectiveDeclNameRef));
void *operator new(size_t Bytes, void *Mem) {
assert(Mem);
return Mem;
}
};

llvm::PointerUnion<DeclName, SelectiveDeclNameRef *> storage;

explicit DeclNameRef(void *Opaque)
: storage(decltype(storage)::getFromOpaqueValue(Opaque)) { }

void initialize(ASTContext &C, Identifier moduleScope, DeclName fullName);

public:
static DeclNameRef createSubscript();
static DeclNameRef createConstructor();

DeclNameRef() : FullName() { }
DeclNameRef() : storage(DeclName()) { }

void *getOpaqueValue() const { return FullName.getOpaqueValue(); }
void *getOpaqueValue() const {
return storage.getOpaqueValue();
}
static DeclNameRef getFromOpaqueValue(void *p);

explicit DeclNameRef(ASTContext &C, Identifier moduleSelector,
DeclName fullName) {
initialize(C, moduleSelector, fullName);
}

explicit DeclNameRef(ASTContext &C, Identifier moduleSelector,
DeclBaseName baseName, ArrayRef<Identifier> argLabels) {
initialize(C, moduleSelector, DeclName(C, baseName, argLabels));
}

explicit DeclNameRef(DeclName FullName)
: FullName(FullName) { }
: storage(FullName) { }

bool hasModuleSelector() const {
return storage.is<SelectiveDeclNameRef *>();
}

explicit DeclNameRef(DeclBaseName BaseName)
: FullName(BaseName) { }
Identifier getModuleSelector() const {
if (!hasModuleSelector())
return Identifier();

explicit DeclNameRef(Identifier BaseName)
: FullName(BaseName) { }
return storage.get<SelectiveDeclNameRef *>()->moduleSelector;
}

/// The name of the declaration being referenced.
DeclName getFullName() const {
return FullName;
}
if (!hasModuleSelector())
return storage.get<DeclName>();

DeclName &getFullName() {
return FullName;
return storage.get<SelectiveDeclNameRef *>()->fullName;
}

/// The base name of the declaration being referenced.
DeclBaseName getBaseName() const {
return FullName.getBaseName();
return getFullName().getBaseName();
}

Identifier getBaseIdentifier() const {
return FullName.getBaseIdentifier();
return getFullName().getBaseIdentifier();
}

ArrayRef<Identifier> getArgumentNames() const {
return FullName.getArgumentNames();
return getFullName().getArgumentNames();
}

bool isSimpleName() const {
return FullName.isSimpleName();
return getFullName().isSimpleName();
}

bool isSimpleName(DeclBaseName name) const {
return FullName.isSimpleName(name);
return getFullName().isSimpleName(name);
}

bool isSimpleName(StringRef name) const {
return FullName.isSimpleName(name);
return getFullName().isSimpleName(name);
}

bool isSpecial() const {
return FullName.isSpecial();
return getFullName().isSpecial();
}

bool isOperator() const {
return FullName.isOperator();
return getFullName().isOperator();
}

bool isCompoundName() const {
return FullName.isCompoundName();
return getFullName().isCompoundName();
}

explicit operator bool() const {
return (bool)FullName;
return (bool)getFullName();
}

/// Compare two declaration names, producing -1 if \c *this comes before
Expand Down Expand Up @@ -722,7 +775,7 @@ class DeclNameRef {
return lhs.compare(rhs) >= 0;
}

DeclNameRef withoutArgumentLabels() const;
DeclNameRef withoutArgumentLabels(ASTContext &C) const;
DeclNameRef withArgumentLabels(ASTContext &C,
ArrayRef<Identifier> argumentNames) const;

Expand Down Expand Up @@ -753,19 +806,18 @@ class DeclNameRef {
};

inline DeclNameRef DeclNameRef::getFromOpaqueValue(void *p) {
return DeclNameRef(DeclName::getFromOpaqueValue(p));
return DeclNameRef(p);
}

inline DeclNameRef DeclNameRef::withoutArgumentLabels() const {
return DeclNameRef(getBaseName());
inline DeclNameRef DeclNameRef::withoutArgumentLabels(ASTContext &C) const {
return DeclNameRef(C, getModuleSelector(), getBaseName());
}

inline DeclNameRef DeclNameRef::withArgumentLabels(
ASTContext &C, ArrayRef<Identifier> argumentNames) const {
return DeclNameRef(DeclName(C, getBaseName(), argumentNames));
return DeclNameRef(C, getModuleSelector(), getBaseName(), argumentNames);
}


inline DeclNameRef DeclNameRef::createSubscript() {
return DeclNameRef(DeclBaseName::createSubscript());
}
Expand Down Expand Up @@ -931,7 +983,7 @@ namespace llvm {
static inline swift::DeclNameRef getFromVoidPointer(void *ptr) {
return swift::DeclNameRef::getFromOpaqueValue(ptr);
}
enum { NumLowBitsAvailable = PointerLikeTypeTraits<swift::DeclName>::NumLowBitsAvailable };
enum { NumLowBitsAvailable = PointerLikeTypeTraits<swift::DeclName>::NumLowBitsAvailable - 1 };
};

// DeclNameRefs hash just like DeclNames.
Expand Down
6 changes: 3 additions & 3 deletions include/swift/AST/ModuleNameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ enum class ResolutionKind {

void simple_display(llvm::raw_ostream &out, ResolutionKind kind);

/// Performs a lookup into the given module and it's imports.
/// Performs a lookup into the given module and its imports.
///
/// If 'moduleOrFile' is a ModuleDecl, we search the module and it's
/// If 'moduleOrFile' is a ModuleDecl, we search the module and its
/// public imports. If 'moduleOrFile' is a SourceFile, we search the
/// file's parent module, the module's public imports, and the source
/// file's private imports.
///
/// \param moduleOrFile The module or file unit whose imports to search.
/// \param moduleOrFile The module or file unit to search, including imports.
/// \param name The name to look up.
/// \param[out] decls Any found decls will be added to this vector.
/// \param lookupKind Whether this lookup is qualified or unqualified.
Expand Down
9 changes: 9 additions & 0 deletions include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,14 @@ class AccessFilteringDeclConsumer final : public VisibleDeclConsumer {
/// \returns true if any declarations were removed, false otherwise.
bool removeOverriddenDecls(SmallVectorImpl<ValueDecl*> &decls);

/// Remove any declarations in the given set that do not match the
/// module selector, if it is not empty.
///
/// \returns true if any declarations were removed, false otherwise.
bool removeOutOfModuleDecls(SmallVectorImpl<ValueDecl*> &decls,
Identifier moduleSelector,
const DeclContext *dc);

/// Remove any declarations in the given set that are shadowed by
/// other declarations in that set.
///
Expand Down Expand Up @@ -474,6 +482,7 @@ namespace namelookup {
/// Once name lookup has gathered a set of results, perform any necessary
/// steps to prune the result set before returning it to the caller.
void pruneLookupResultSet(const DeclContext *dc, NLOptions options,
Identifier moduleSelector,
SmallVectorImpl<ValueDecl *> &decls);

/// Do nothing if debugClient is null.
Expand Down
Loading