Skip to content

Commit 1ed3cae

Browse files
committed
[NFC] Add new ImportPath types
1 parent 5afe2f9 commit 1ed3cae

File tree

1 file changed

+293
-0
lines changed

1 file changed

+293
-0
lines changed

include/swift/AST/Import.h

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@
1919
#ifndef SWIFT_IMPORT_H
2020
#define SWIFT_IMPORT_H
2121

22+
#include "swift/AST/Identifier.h"
23+
#include "swift/Basic/Located.h"
24+
#include "llvm/ADT/ArrayRef.h"
25+
#include "llvm/ADT/SmallVector.h"
26+
#include "llvm/ADT/STLExtras.h"
27+
2228
namespace swift {
29+
class ASTContext;
30+
2331
/// Describes what kind of name is being imported.
2432
///
2533
/// If the enumerators here are changed, make sure to update all diagnostics
@@ -35,6 +43,291 @@ enum class ImportKind : uint8_t {
3543
Func
3644
};
3745

46+
namespace detail {
47+
using ImportPathElement = Located<Identifier>;
48+
using ImportPathRaw = llvm::ArrayRef<ImportPathElement>;
49+
50+
template<typename Subclass>
51+
class ImportPathBase {
52+
public:
53+
using Element = ImportPathElement;
54+
using Raw = ImportPathRaw;
55+
56+
protected:
57+
Raw raw;
58+
59+
ImportPathBase(Raw raw) : raw(raw) { }
60+
61+
public:
62+
const Raw &getRaw() const { return raw; }
63+
64+
Raw::iterator begin() const {
65+
return raw.begin();
66+
}
67+
68+
Raw::iterator end() const {
69+
return raw.end();
70+
}
71+
72+
const Element &operator[](size_t i) const { return raw[i]; }
73+
bool empty() const { return raw.empty(); }
74+
size_t size() const { return raw.size(); }
75+
76+
const Element &front() const { return raw.front(); }
77+
const Element &back() const { return raw.back(); }
78+
79+
/// True if \c this and \c other are precisely equal, including SourceLocs.
80+
bool operator==(const Subclass &other) const {
81+
return raw == other.raw;
82+
}
83+
84+
/// True if \c this and \c other contain the same identifiers in the same
85+
/// order, ignoring SourceLocs.
86+
bool isSameAs(const Subclass &other) const {
87+
return size() == other.size()
88+
&& std::equal(this->begin(), this->end(), other.begin(),
89+
[](const Element &l, const Element &r) -> bool {
90+
return l.Item == r.Item;
91+
}
92+
);
93+
}
94+
95+
Subclass getTopLevelPath() const {
96+
assert(size() >= 1 && "nothing to take");
97+
return Subclass(raw.take_front());
98+
}
99+
100+
Subclass getParentPath() const {
101+
assert(size() >= 0 && "nothing to take");
102+
return Subclass(raw.drop_back());
103+
}
104+
105+
SourceRange getSourceRange() const {
106+
if (empty()) return SourceRange();
107+
return SourceRange(raw.front().Loc, raw.back().Loc);
108+
}
109+
};
110+
111+
ImportPathRaw ImportPathBuilder_copyToImpl(ASTContext &ctx,
112+
ImportPathRaw raw);
113+
114+
template<typename Subclass>
115+
class ImportPathBuilder {
116+
llvm::SmallVector<ImportPathElement, 4> scratch;
117+
118+
public:
119+
Subclass get() const {
120+
return Subclass(scratch);
121+
}
122+
123+
Subclass copyTo(ASTContext &ctx) const {
124+
return Subclass(ImportPathBuilder_copyToImpl(ctx, scratch));
125+
}
126+
127+
ImportPathBuilder() : scratch() { }
128+
ImportPathBuilder(const ImportPathElement &elem) : scratch() {
129+
scratch = { elem };
130+
}
131+
ImportPathBuilder(Identifier name, SourceLoc loc = SourceLoc())
132+
: ImportPathBuilder(ImportPathElement(name, loc)) { }
133+
134+
template<typename Iterator>
135+
ImportPathBuilder(Iterator begin, Iterator end) : scratch(begin, end) { }
136+
137+
template<typename Range>
138+
ImportPathBuilder(Range collection)
139+
: scratch(collection.begin(), collection.end()) { }
140+
141+
void push_back(const ImportPathElement &elem) { scratch.push_back(elem); }
142+
void push_back(Identifier name, SourceLoc loc = SourceLoc()) {
143+
scratch.push_back({ name, loc });
144+
}
145+
146+
void pop_back() { scratch.pop_back(); }
147+
148+
bool empty() const { return scratch.empty(); }
149+
size_t size() const { return scratch.size(); }
150+
151+
llvm::SmallVector<ImportPathElement, 4>::iterator begin() {
152+
return scratch.begin();
153+
}
154+
llvm::SmallVector<ImportPathElement, 4>::iterator end() {
155+
return scratch.end();
156+
}
157+
158+
const ImportPathElement &front() const { return scratch.front(); }
159+
ImportPathElement &front() { return scratch.front(); }
160+
const ImportPathElement &back() const { return scratch.back(); }
161+
ImportPathElement &back() { return scratch.back(); }
162+
163+
template<typename Iterator>
164+
void append(Iterator begin, Iterator end) {
165+
scratch.append(begin, end);
166+
}
167+
168+
template<typename Range>
169+
void append(Range collection) {
170+
append(collection.begin(), collection.end());
171+
}
172+
};
173+
}
174+
175+
/// An undifferentiated series of dotted identifiers in an \c import statement,
176+
/// like \c Foo.Bar. Each identifier is packaged with its corresponding source
177+
/// location.
178+
///
179+
/// The first element of an \c ImportPath is always a top-level module name. The
180+
/// remaining elements could specify a scope (naming a declaration in the
181+
/// module) or a chain of submodule names. \c ImportPath does not differentiate
182+
/// between these cases; its \c getModule() and \c getAccess() methods take an
183+
/// \c ImportKind parameter to decide how to divvy up these identifiers.
184+
///
185+
/// \c ImportPath is only used when analyzing the parsed representation of code.
186+
/// Most code should use \c ImportPath::Module or \c ImportPath::Access, which
187+
/// have semantic meaning.
188+
///
189+
/// \c ImportPath is essentially a wrapper around \c ArrayRef and does not own
190+
/// its elements, so something else needs to manage their lifetime.
191+
/// \c ImportDecl owns the memory backing \c ImportDecl::getImportPath().
192+
class ImportPath : public detail::ImportPathBase<ImportPath> {
193+
public:
194+
/// A single dotted name from an \c ImportPath, \c ImportPath::Module, or
195+
/// \c ImportPath::Access, with its source location.
196+
using Element = detail::ImportPathBase<ImportPath>::Element;
197+
198+
/// The backing type for \c ImportPath, \c ImportPath::Module, and
199+
/// \c ImportPath::Access; namely, an \c ArrayRef of \c ImportPath::Elements.
200+
using Raw = detail::ImportPathBase<ImportPath>::Raw;
201+
202+
/// A helper type which encapsulates a temporary vector and can produce an
203+
/// import path from it. In addition to the obvious use in a temporary
204+
/// variable, this type can be used mid-expression to produce an import path
205+
/// that is valid until the end of the expression.
206+
using Builder = detail::ImportPathBuilder<ImportPath>;
207+
208+
/// Represents an access path--the portion of an \c ImportPath which describes
209+
/// the name of a declaration to scope the import to.
210+
///
211+
/// \c ImportPath::Access is used in scoped imports to designate a specific
212+
/// declaration inside the module. The import will only* cover this
213+
/// declaration, and will import it with a higher "priority" than usual, so
214+
/// name lookup will prefer it over identically-named declarations visible
215+
/// through other imports.
216+
///
217+
/// (* Not actually only--e.g. extensions will be imported too. The primary
218+
/// use case for scoped imports is actually to resolve name conflicts, not to
219+
/// reduce the set of visible declarations.)
220+
///
221+
/// When \c ImportPath::Access is empty, this means the import covers all
222+
/// declarations in the module.
223+
///
224+
/// Although in theory Swift could support scoped imports of nested
225+
/// declarations, in practice it currently only supports scoped imports of
226+
/// top-level declarations. Reflecting this, \c ImportPath::Access is backed
227+
/// by an \c ArrayRef, but it asserts that the access path has zero or one
228+
/// elements.
229+
///
230+
/// \c ImportPath::Access is essentially a wrapper around \c ArrayRef and does
231+
/// not own its elements, so something else needs to manage their lifetime.
232+
/// \c ImportDecl owns the memory backing \c ImportDecl::getDeclPath().
233+
class Access : public detail::ImportPathBase<Access> {
234+
public:
235+
/// A helper type which encapsulates a temporary vector and can produce a
236+
/// scope path from it. In addition to the obvious use in a temporary
237+
/// variable, this type can be used mid-expression to produce a scope path
238+
/// that is valid until the end of the expression.
239+
using Builder = detail::ImportPathBuilder<Access>;
240+
241+
Access(ImportPath::Raw raw) : ImportPathBase(raw) {
242+
assert(size() <= 1 && "nested scoped imports are not supported");
243+
}
244+
245+
Access() : ImportPathBase({}) { }
246+
247+
/// Returns \c true if the scope of this import includes \c name. An empty
248+
/// scope matches all names.
249+
bool matches(DeclName name) const {
250+
return empty() || DeclName(front().Item).matchesRef(name);
251+
}
252+
};
253+
254+
/// Represents a module path--the portion of an \c ImportPath which describes
255+
/// the name of the module being imported, possibly including submodules.
256+
///
257+
/// \c ImportPath::Module contains one or more identifiers. The first
258+
/// identiifer names a top-level module. The second and subsequent
259+
/// identifiers, if present, chain together to name a specific submodule to
260+
/// import. (Although Swift modules cannot currently contain submodules, Swift
261+
/// can import Clang submodules.)
262+
///
263+
/// \c ImportPath::Module is essentially a wrapper around \c ArrayRef and
264+
/// does not own its elements, so something else needs to manage their
265+
/// lifetime. \c ImportDecl owns the memory backing
266+
/// \c ImportDecl::getModulePath().
267+
class Module : public detail::ImportPathBase<Module> {
268+
public:
269+
/// A helper type which encapsulates a temporary vector and can produce a
270+
/// module path from it. In addition to the obvious use in a temporary
271+
/// variable, this type can be used mid-expression to produce a module path
272+
/// that is valid until the end of the expression.
273+
using Builder = detail::ImportPathBuilder<Module>;
274+
275+
Module(ImportPath::Raw raw) : ImportPathBase(raw) {
276+
assert(size() >= 1 && "must have a top-level module");
277+
}
278+
279+
// Note: This type does not have a constructor which just takes an
280+
// `Identifier` because it would not be able to create a temporary
281+
// `ImportPath::Element` with a long enough lifetime to return. Use
282+
// `ImportPath::Module::Builder` to create a temporary module path.
283+
284+
bool hasSubmodule() const {
285+
return size() != 1;
286+
}
287+
288+
ImportPath::Raw getSubmodulePath() const {
289+
return getRaw().drop_front();
290+
}
291+
};
292+
293+
ImportPath(Raw raw) : ImportPathBase(raw) {
294+
assert(raw.size() >= 1 && "ImportPath must contain a module name");
295+
}
296+
297+
/// Extracts the portion of the \c ImportPath which represents a module name,
298+
/// including submodules if appropriate.
299+
Module getModulePath(bool isScoped) const {
300+
if (isScoped)
301+
return Module(getRaw().drop_back());
302+
303+
return Module(getRaw());
304+
}
305+
306+
/// Extracts the portion of the \c ImportPath which represents a scope for the
307+
/// import.
308+
Access getAccessPath(bool isScoped) const {
309+
if (isScoped) {
310+
assert(size() >= 2 && "scoped ImportPath must contain a decl name");
311+
return Access(getRaw().take_back());
312+
}
313+
314+
return Access();
315+
}
316+
317+
/// Extracts the portion of the \c ImportPath which represents a module name,
318+
/// including submodules, assuming the \c ImportDecl has the indicated
319+
/// \c importKind.
320+
Module getModulePath(ImportKind importKind) const {
321+
return getModulePath(importKind != ImportKind::Module);
322+
}
323+
324+
/// Extracts the portion of the \c ImportPath which represents a scope for the
325+
/// import, assuming the \c ImportDecl has the indicated \c importKind.
326+
Access getAccessPath(ImportKind importKind) const {
327+
return getAccessPath(importKind != ImportKind::Module);
328+
}
329+
};
330+
38331
}
39332

40333
#endif

0 commit comments

Comments
 (0)