Skip to content

Commit f7800fd

Browse files
committed
Propagate parsed type attributes to TypeAttributes.
Propagate parsed type attributes to the TypeAttributes structure, so they persist in the AST and can be processed by the type checker. Move the "unknown attribute" diagnostic for custom attributes on types into the type checker.
1 parent 7f6b681 commit f7800fd

File tree

3 files changed

+185
-140
lines changed

3 files changed

+185
-140
lines changed

include/swift/AST/Attr.h

Lines changed: 167 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "swift/AST/Requirement.h"
3838
#include "swift/AST/StorageImpl.h"
3939
#include "swift/AST/TrailingCallArguments.h"
40+
#include "llvm/ADT/iterator_range.h"
4041
#include "llvm/ADT/SmallVector.h"
4142
#include "llvm/ADT/StringRef.h"
4243
#include "llvm/Support/ErrorHandling.h"
@@ -47,6 +48,7 @@ namespace swift {
4748
class ASTPrinter;
4849
class ASTContext;
4950
struct PrintOptions;
51+
class CustomAttr;
5052
class Decl;
5153
class AbstractFunctionDecl;
5254
class FuncDecl;
@@ -58,133 +60,6 @@ class PatternBindingInitializer;
5860
class TrailingWhereClause;
5961
class TypeExpr;
6062

61-
/// TypeAttributes - These are attributes that may be applied to types.
62-
class TypeAttributes {
63-
// Get a SourceLoc for every possible attribute that can be parsed in source.
64-
// the presence of the attribute is indicated by its location being set.
65-
SourceLoc AttrLocs[TAK_Count];
66-
public:
67-
/// AtLoc - This is the location of the first '@' in the attribute specifier.
68-
/// If this is an empty attribute specifier, then this will be an invalid loc.
69-
SourceLoc AtLoc;
70-
71-
struct Convention {
72-
StringRef Name = {};
73-
DeclNameRef WitnessMethodProtocol = {};
74-
Located<StringRef> ClangType = Located<StringRef>(StringRef(), {});
75-
/// Convenience factory function to create a Swift convention.
76-
///
77-
/// Don't use this function if you are creating a C convention as you
78-
/// probably need a ClangType field as well.
79-
static Convention makeSwiftConvention(StringRef name) {
80-
return {name, DeclNameRef(), Located<StringRef>("", {})};
81-
}
82-
};
83-
84-
Optional<Convention> ConventionArguments;
85-
86-
// Indicates whether the type's '@differentiable' attribute has a 'linear'
87-
// argument.
88-
DifferentiabilityKind differentiabilityKind =
89-
DifferentiabilityKind::NonDifferentiable;
90-
91-
// For an opened existential type, the known ID.
92-
Optional<UUID> OpenedID;
93-
94-
// For a reference to an opaque return type, the mangled name and argument
95-
// index into the generic signature.
96-
struct OpaqueReturnTypeRef {
97-
StringRef mangledName;
98-
unsigned index;
99-
};
100-
Optional<OpaqueReturnTypeRef> OpaqueReturnTypeOf;
101-
102-
TypeAttributes() {}
103-
104-
bool isValid() const { return AtLoc.isValid(); }
105-
106-
void clearAttribute(TypeAttrKind A) {
107-
AttrLocs[A] = SourceLoc();
108-
}
109-
110-
bool has(TypeAttrKind A) const {
111-
return getLoc(A).isValid();
112-
}
113-
114-
SourceLoc getLoc(TypeAttrKind A) const {
115-
return AttrLocs[A];
116-
}
117-
118-
void setOpaqueReturnTypeOf(StringRef mangling, unsigned index) {
119-
OpaqueReturnTypeOf = OpaqueReturnTypeRef{mangling, index};
120-
}
121-
122-
void setAttr(TypeAttrKind A, SourceLoc L) {
123-
assert(!L.isInvalid() && "Cannot clear attribute with this method");
124-
AttrLocs[A] = L;
125-
}
126-
127-
void getAttrLocs(SmallVectorImpl<SourceLoc> &Locs) const {
128-
for (auto Loc : AttrLocs) {
129-
if (Loc.isValid())
130-
Locs.push_back(Loc);
131-
}
132-
}
133-
134-
// This attribute list is empty if no attributes are specified. Note that
135-
// the presence of the leading @ is not enough to tell, because we want
136-
// clients to be able to remove attributes they process until they get to
137-
// an empty list.
138-
bool empty() const {
139-
for (SourceLoc elt : AttrLocs)
140-
if (elt.isValid())
141-
return false;
142-
143-
return true;
144-
}
145-
146-
bool hasConvention() const { return ConventionArguments.hasValue(); }
147-
148-
/// Returns the primary calling convention string.
149-
///
150-
/// Note: For C conventions, this may not represent the full convention.
151-
StringRef getConventionName() const {
152-
return ConventionArguments.getValue().Name;
153-
}
154-
155-
/// Show the string enclosed between @convention(..)'s parentheses.
156-
///
157-
/// For example, @convention(foo, bar) will give the string "foo, bar".
158-
void getConventionArguments(SmallVectorImpl<char> &buffer) const;
159-
160-
bool hasOwnership() const {
161-
return getOwnership() != ReferenceOwnership::Strong;
162-
}
163-
ReferenceOwnership getOwnership() const {
164-
#define REF_STORAGE(Name, name, ...) \
165-
if (has(TAK_sil_##name)) return ReferenceOwnership::Name;
166-
#include "swift/AST/ReferenceStorage.def"
167-
return ReferenceOwnership::Strong;
168-
}
169-
170-
void clearOwnership() {
171-
#define REF_STORAGE(Name, name, ...) \
172-
clearAttribute(TAK_sil_##name);
173-
#include "swift/AST/ReferenceStorage.def"
174-
}
175-
176-
bool hasOpenedID() const { return OpenedID.hasValue(); }
177-
UUID getOpenedID() const { return *OpenedID; }
178-
179-
/// Given a name like "autoclosure", return the type attribute ID that
180-
/// corresponds to it. This returns TAK_Count on failure.
181-
///
182-
static TypeAttrKind getAttrKindFromString(StringRef Str);
183-
184-
/// Return the name (like "autoclosure") for an attribute ID.
185-
static const char *getAttrName(TypeAttrKind kind);
186-
};
187-
18863
class alignas(1 << AttrAlignInBits) AttributeBase {
18964
public:
19065
/// The location of the '@'.
@@ -229,6 +104,7 @@ enum class DeclKind : uint8_t;
229104
/// Represents one declaration attribute.
230105
class DeclAttribute : public AttributeBase {
231106
friend class DeclAttributes;
107+
friend class TypeAttributes;
232108

233109
protected:
234110
union {
@@ -2409,6 +2285,170 @@ class DeclAttributes {
24092285
SourceLoc getStartLoc(bool forModifiers = false) const;
24102286
};
24112287

2288+
/// TypeAttributes - These are attributes that may be applied to types.
2289+
class TypeAttributes {
2290+
// Get a SourceLoc for every possible attribute that can be parsed in source.
2291+
// the presence of the attribute is indicated by its location being set.
2292+
SourceLoc AttrLocs[TAK_Count];
2293+
2294+
/// The custom attributes, in a linked list.
2295+
CustomAttr *CustomAttrs = nullptr;
2296+
2297+
public:
2298+
/// AtLoc - This is the location of the first '@' in the attribute specifier.
2299+
/// If this is an empty attribute specifier, then this will be an invalid loc.
2300+
SourceLoc AtLoc;
2301+
2302+
struct Convention {
2303+
StringRef Name = {};
2304+
DeclNameRef WitnessMethodProtocol = {};
2305+
Located<StringRef> ClangType = Located<StringRef>(StringRef(), {});
2306+
/// Convenience factory function to create a Swift convention.
2307+
///
2308+
/// Don't use this function if you are creating a C convention as you
2309+
/// probably need a ClangType field as well.
2310+
static Convention makeSwiftConvention(StringRef name) {
2311+
return {name, DeclNameRef(), Located<StringRef>("", {})};
2312+
}
2313+
};
2314+
2315+
Optional<Convention> ConventionArguments;
2316+
2317+
// Indicates whether the type's '@differentiable' attribute has a 'linear'
2318+
// argument.
2319+
DifferentiabilityKind differentiabilityKind =
2320+
DifferentiabilityKind::NonDifferentiable;
2321+
2322+
// For an opened existential type, the known ID.
2323+
Optional<UUID> OpenedID;
2324+
2325+
// For a reference to an opaque return type, the mangled name and argument
2326+
// index into the generic signature.
2327+
struct OpaqueReturnTypeRef {
2328+
StringRef mangledName;
2329+
unsigned index;
2330+
};
2331+
Optional<OpaqueReturnTypeRef> OpaqueReturnTypeOf;
2332+
2333+
TypeAttributes() {}
2334+
2335+
bool isValid() const { return AtLoc.isValid(); }
2336+
2337+
void clearAttribute(TypeAttrKind A) {
2338+
AttrLocs[A] = SourceLoc();
2339+
}
2340+
2341+
bool has(TypeAttrKind A) const {
2342+
return getLoc(A).isValid();
2343+
}
2344+
2345+
SourceLoc getLoc(TypeAttrKind A) const {
2346+
return AttrLocs[A];
2347+
}
2348+
2349+
void setOpaqueReturnTypeOf(StringRef mangling, unsigned index) {
2350+
OpaqueReturnTypeOf = OpaqueReturnTypeRef{mangling, index};
2351+
}
2352+
2353+
void setAttr(TypeAttrKind A, SourceLoc L) {
2354+
assert(!L.isInvalid() && "Cannot clear attribute with this method");
2355+
AttrLocs[A] = L;
2356+
}
2357+
2358+
void getAttrLocs(SmallVectorImpl<SourceLoc> &Locs) const {
2359+
for (auto Loc : AttrLocs) {
2360+
if (Loc.isValid())
2361+
Locs.push_back(Loc);
2362+
}
2363+
}
2364+
2365+
// This attribute list is empty if no attributes are specified. Note that
2366+
// the presence of the leading @ is not enough to tell, because we want
2367+
// clients to be able to remove attributes they process until they get to
2368+
// an empty list.
2369+
bool empty() const {
2370+
if (CustomAttrs)
2371+
return false;
2372+
2373+
for (SourceLoc elt : AttrLocs)
2374+
if (elt.isValid())
2375+
return false;
2376+
2377+
return true;
2378+
}
2379+
2380+
bool hasConvention() const { return ConventionArguments.hasValue(); }
2381+
2382+
/// Returns the primary calling convention string.
2383+
///
2384+
/// Note: For C conventions, this may not represent the full convention.
2385+
StringRef getConventionName() const {
2386+
return ConventionArguments.getValue().Name;
2387+
}
2388+
2389+
/// Show the string enclosed between @convention(..)'s parentheses.
2390+
///
2391+
/// For example, @convention(foo, bar) will give the string "foo, bar".
2392+
void getConventionArguments(SmallVectorImpl<char> &buffer) const;
2393+
2394+
bool hasOwnership() const {
2395+
return getOwnership() != ReferenceOwnership::Strong;
2396+
}
2397+
ReferenceOwnership getOwnership() const {
2398+
#define REF_STORAGE(Name, name, ...) \
2399+
if (has(TAK_sil_##name)) return ReferenceOwnership::Name;
2400+
#include "swift/AST/ReferenceStorage.def"
2401+
return ReferenceOwnership::Strong;
2402+
}
2403+
2404+
void clearOwnership() {
2405+
#define REF_STORAGE(Name, name, ...) \
2406+
clearAttribute(TAK_sil_##name);
2407+
#include "swift/AST/ReferenceStorage.def"
2408+
}
2409+
2410+
bool hasOpenedID() const { return OpenedID.hasValue(); }
2411+
UUID getOpenedID() const { return *OpenedID; }
2412+
2413+
/// Given a name like "autoclosure", return the type attribute ID that
2414+
/// corresponds to it. This returns TAK_Count on failure.
2415+
///
2416+
static TypeAttrKind getAttrKindFromString(StringRef Str);
2417+
2418+
/// Return the name (like "autoclosure") for an attribute ID.
2419+
static const char *getAttrName(TypeAttrKind kind);
2420+
2421+
void addCustomAttr(CustomAttr *attr) {
2422+
attr->Next = CustomAttrs;
2423+
CustomAttrs = attr;
2424+
}
2425+
2426+
// Iterator for the custom type attributes.
2427+
class iterator
2428+
: public std::iterator<std::forward_iterator_tag, CustomAttr *> {
2429+
CustomAttr *attr;
2430+
2431+
public:
2432+
iterator() : attr(nullptr) { }
2433+
explicit iterator(CustomAttr *attr) : attr(attr) { }
2434+
2435+
iterator &operator++() {
2436+
attr = static_cast<CustomAttr *>(attr->Next);
2437+
return *this;
2438+
}
2439+
2440+
bool operator==(iterator x) const { return x.attr == attr; }
2441+
bool operator!=(iterator x) const { return x.attr != attr; }
2442+
2443+
CustomAttr *operator*() const { return attr; }
2444+
CustomAttr &operator->() const { return *attr; }
2445+
};
2446+
2447+
llvm::iterator_range<iterator> getCustomAttrs() const {
2448+
return llvm::make_range(iterator(CustomAttrs), iterator());
2449+
}
2450+
};
2451+
24122452
void simple_display(llvm::raw_ostream &out, const DeclAttribute *attr);
24132453

24142454
inline SourceLoc extractNearestSourceLoc(const DeclAttribute *attr) {

lib/Parse/ParseDecl.cpp

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3305,19 +3305,9 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33053305
if (customAttrResult.isParseErrorOrHasCompletion())
33063306
return true;
33073307

3308-
// Diagnose the attribute, because we don't yet handle custom type
3309-
// attributes.
3310-
std::string typeName;
3311-
auto customAttr = customAttrResult.get();
3312-
if (auto typeRepr = customAttr->getTypeRepr()) {
3313-
llvm::raw_string_ostream out(typeName);
3314-
typeRepr->print(out);
3315-
} else {
3316-
typeName = customAttr->getType().getString();
3317-
}
3318-
3319-
diagnose(customAttr->getLocation(), diag::unknown_attribute, typeName);
3320-
return true;
3308+
if (auto attr = customAttrResult.get())
3309+
Attributes.addCustomAttr(attr);
3310+
return false;
33213311
}
33223312

33233313
// Ok, it is a valid attribute, eat it, and then process it.

lib/Sema/TypeCheckType.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,21 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
20892089
options.is(TypeResolverContext::VariadicFunctionInput) &&
20902090
!options.hasBase(TypeResolverContext::EnumElementDecl);
20912091

2092+
// Diagnose custom attributes.
2093+
for (auto customAttr : attrs.getCustomAttrs()) {
2094+
// Diagnose the attribute, because we don't yet handle custom type
2095+
// attributes.
2096+
std::string typeName;
2097+
if (auto typeRepr = customAttr->getTypeRepr()) {
2098+
llvm::raw_string_ostream out(typeName);
2099+
typeRepr->print(out);
2100+
} else {
2101+
typeName = customAttr->getType().getString();
2102+
}
2103+
2104+
diagnose(customAttr->getLocation(), diag::unknown_attribute, typeName);
2105+
}
2106+
20922107
// The type we're working with, in case we want to build it differently
20932108
// based on the attributes we see.
20942109
Type ty;

0 commit comments

Comments
 (0)