Skip to content

Commit 0042354

Browse files
authored
Merge pull request swiftlang#58690 from ahoppen/pr/attribute-type-relation
[CodeCompletion] Mark types that can’t be used as attributes as having an invalid type relation when used after '@'
2 parents 23aca0e + df605d4 commit 0042354

File tree

7 files changed

+209
-24
lines changed

7 files changed

+209
-24
lines changed

include/swift/IDE/CodeCompletionResultType.h

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@
2121
namespace swift {
2222
namespace ide {
2323

24+
enum class CustomAttributeKind : uint8_t {
25+
/// A type that can be used as a property wrapper.
26+
PropertyWrapper = 1 << 0,
27+
/// A type that can be used as a result builder.
28+
ResultBuilder = 1 << 1,
29+
/// A type that can be used as a global actor.
30+
GlobalActor = 1 << 2,
31+
};
32+
2433
/// The expected contextual type(s) for code-completion.
2534
class ExpectedTypeContext {
2635
/// Possible types of the code completion expression.
@@ -37,6 +46,11 @@ class ExpectedTypeContext {
3746
bool IsImplicitSingleExpressionReturn = false;
3847
bool PreferNonVoid = false;
3948

49+
/// If not empty, \c PossibleTypes are ignored and types that have an
50+
/// attribute kind that is contained in this list will be reported as
51+
/// 'Convertible'. All other types are related as 'Invalid'.
52+
OptionSet<CustomAttributeKind> ExpectedCustomAttributeKinds;
53+
4054
public:
4155
ExpectedTypeContext() = default;
4256

@@ -82,6 +96,15 @@ class ExpectedTypeContext {
8296
void setPreferNonVoid(bool PreferNonVoid) {
8397
this->PreferNonVoid = PreferNonVoid;
8498
}
99+
100+
OptionSet<CustomAttributeKind> getExpectedCustomAttributeKinds() const {
101+
return ExpectedCustomAttributeKinds;
102+
}
103+
104+
void setExpectedCustomAttributeKinds(
105+
OptionSet<CustomAttributeKind> ExpectedAttributeKinds) {
106+
this->ExpectedCustomAttributeKinds = ExpectedAttributeKinds;
107+
}
85108
};
86109

87110
/// Describes the relationship between the type of the completion results and
@@ -162,6 +185,9 @@ class USRBasedTypeContext {
162185

163186
SmallVector<ContextualType, 4> ContextualTypes;
164187

188+
/// See \c ExpectedTypeContext::ExpectedAttributeKinds.
189+
OptionSet<CustomAttributeKind> ExpectedCustomAttributeKinds;
190+
165191
public:
166192
/// Create a USR-based equivalent of the \p TypeContext.
167193
USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
@@ -191,10 +217,15 @@ class USRBasedType {
191217
/// declared in the same module that the type was defined.
192218
ArrayRef<const USRBasedType *> Supertypes;
193219

220+
/// The kinds of attributes this type can be used as.
221+
OptionSet<CustomAttributeKind> CustomAttributeKinds;
222+
194223
/// Memberwise initializer. \p USR and \p Supertypes need to be allocated in
195224
/// the same arena as this \c USRBasedType.
196-
USRBasedType(StringRef USR, ArrayRef<const USRBasedType *> Supertypes)
197-
: USR(USR), Supertypes(Supertypes) {}
225+
USRBasedType(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
226+
OptionSet<CustomAttributeKind> CustomAttributeKinds)
227+
: USR(USR), Supertypes(Supertypes),
228+
CustomAttributeKinds(CustomAttributeKinds) {}
198229

199230
/// Implementation of \c typeRelation. \p VisistedTypes keeps track which
200231
/// types have already been visited.
@@ -213,13 +244,18 @@ class USRBasedType {
213244

214245
/// Construct as \c USRBasedType from a USR and its supertypes. This method
215246
/// takes care of copying \p USR and \p Supertypes to \p Arena.
216-
static const USRBasedType *fromUSR(StringRef USR,
217-
ArrayRef<const USRBasedType *> Supertypes,
218-
USRBasedTypeArena &Arena);
247+
static const USRBasedType *
248+
fromUSR(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
249+
OptionSet<CustomAttributeKind> CustomAttributeKinds,
250+
USRBasedTypeArena &Arena);
219251

220252
StringRef getUSR() const { return USR; }
221253
ArrayRef<const USRBasedType *> getSupertypes() const { return Supertypes; }
222254

255+
OptionSet<CustomAttributeKind> getCustomAttributeKinds() const {
256+
return CustomAttributeKinds;
257+
}
258+
223259
/// Compute the relation of \c ResultType when to this contextual type.
224260
CodeCompletionResultTypeRelation
225261
typeRelation(const USRBasedType *ResultType,

include/swift/IDE/CompletionLookup.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
240240

241241
void setIsStaticMetatype(bool value) { IsStaticMetatype = value; }
242242

243-
void setExpectedTypes(ArrayRef<Type> Types,
244-
bool isImplicitSingleExpressionReturn,
245-
bool preferNonVoid = false) {
243+
void setExpectedTypes(
244+
ArrayRef<Type> Types, bool isImplicitSingleExpressionReturn,
245+
bool preferNonVoid = false,
246+
OptionSet<CustomAttributeKind> expectedCustomAttributeKinds = {}) {
246247
expectedTypeContext.setIsImplicitSingleExpressionReturn(
247248
isImplicitSingleExpressionReturn);
248249
expectedTypeContext.setPreferNonVoid(preferNonVoid);
249250
expectedTypeContext.setPossibleTypes(Types);
251+
expectedTypeContext.setExpectedCustomAttributeKinds(
252+
expectedCustomAttributeKinds);
250253
}
251254

252255
void setIdealExpectedType(Type Ty) { expectedTypeContext.setIdealType(Ty); }

lib/IDE/CodeCompletion.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,6 +1698,35 @@ void CodeCompletionCallbacksImpl::doneParsing() {
16981698

16991699
case CompletionKind::AttributeBegin: {
17001700
Lookup.getAttributeDeclCompletions(IsInSil, AttTargetDK);
1701+
OptionSet<CustomAttributeKind> ExpectedCustomAttributeKinds;
1702+
if (AttTargetDK) {
1703+
switch (*AttTargetDK) {
1704+
case DeclKind::Var:
1705+
ExpectedCustomAttributeKinds |= CustomAttributeKind::GlobalActor;
1706+
LLVM_FALLTHROUGH;
1707+
case DeclKind::Param:
1708+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ResultBuilder;
1709+
ExpectedCustomAttributeKinds |= CustomAttributeKind::PropertyWrapper;
1710+
break;
1711+
case DeclKind::Func:
1712+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ResultBuilder;
1713+
ExpectedCustomAttributeKinds |= CustomAttributeKind::GlobalActor;
1714+
break;
1715+
default:
1716+
break;
1717+
}
1718+
}
1719+
if (!ExpectedCustomAttributeKinds) {
1720+
// If we don't know on which decl kind we are completing, suggest all
1721+
// attribute kinds.
1722+
ExpectedCustomAttributeKinds |= CustomAttributeKind::PropertyWrapper;
1723+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ResultBuilder;
1724+
ExpectedCustomAttributeKinds |= CustomAttributeKind::GlobalActor;
1725+
}
1726+
Lookup.setExpectedTypes(/*Types=*/{},
1727+
/*isImplicitSingleExpressionReturn=*/false,
1728+
/*preferNonVoid=*/false,
1729+
ExpectedCustomAttributeKinds);
17011730

17021731
// TypeName at attribute position after '@'.
17031732
// - VarDecl: Property Wrappers.

lib/IDE/CodeCompletionCache.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ CodeCompletionCache::~CodeCompletionCache() {}
103103
///
104104
/// This should be incremented any time we commit a change to the format of the
105105
/// cached results. This isn't expected to change very often.
106-
static constexpr uint32_t onDiskCompletionCacheVersion = 6; // Store completion item result types in the cache
106+
static constexpr uint32_t onDiskCompletionCacheVersion = 7; // Store whether a type can be used as attribute
107107

108108
/// Deserializes CodeCompletionResults from \p in and stores them in \p V.
109109
/// \see writeCacheModule.
@@ -193,8 +193,9 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
193193
auto supertypeIndex = read32le(p);
194194
supertypes.push_back(getType(supertypeIndex));
195195
}
196-
const USRBasedType *res =
197-
USRBasedType::fromUSR(usr, supertypes, V.USRTypeArena);
196+
auto customAttributeKinds = OptionSet<CustomAttributeKind, uint8_t>(*p++);
197+
const USRBasedType *res = USRBasedType::fromUSR(
198+
usr, supertypes, customAttributeKinds, V.USRTypeArena);
198199
knownTypes[index] = res;
199200
return res;
200201
};
@@ -381,6 +382,9 @@ static void writeCachedModule(llvm::raw_ostream &out,
381382
for (auto supertypeIndex : supertypeIndicies) {
382383
LE.write(static_cast<uint32_t>(supertypeIndex));
383384
}
385+
OptionSet<CustomAttributeKind, uint8_t> customAttributeKinds =
386+
type->getCustomAttributeKinds();
387+
LE.write(static_cast<uint8_t>(customAttributeKinds.toRaw()));
384388
knownTypes[type] = size;
385389
return static_cast<uint32_t>(size);
386390
};

lib/IDE/CodeCompletionResultType.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,32 @@ using namespace swift;
2222
using namespace ide;
2323
using TypeRelation = CodeCompletionResultTypeRelation;
2424

25+
// MARK: - Utilities
26+
27+
/// Returns the kind of attributes \c Ty can be used as.
28+
static OptionSet<CustomAttributeKind> getCustomAttributeKinds(Type Ty) {
29+
OptionSet<CustomAttributeKind> Result;
30+
if (auto NominalTy = Ty->getAs<NominalType>()) {
31+
auto NominalDecl = NominalTy->getDecl();
32+
if (NominalDecl->getAttrs().hasAttribute<PropertyWrapperAttr>()) {
33+
Result |= CustomAttributeKind::PropertyWrapper;
34+
}
35+
if (NominalDecl->getAttrs().hasAttribute<ResultBuilderAttr>()) {
36+
Result |= CustomAttributeKind::ResultBuilder;
37+
}
38+
if (NominalDecl->isGlobalActor()) {
39+
Result |= CustomAttributeKind::GlobalActor;
40+
}
41+
}
42+
return Result;
43+
}
44+
2545
// MARK: - USRBasedTypeContext
2646

2747
USRBasedTypeContext::USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
2848
USRBasedTypeArena &Arena)
29-
: Arena(Arena) {
49+
: Arena(Arena), ExpectedCustomAttributeKinds(
50+
TypeContext->getExpectedCustomAttributeKinds()) {
3051

3152
for (auto possibleTy : TypeContext->getPossibleTypes()) {
3253
ContextualTypes.emplace_back(USRBasedType::fromType(possibleTy, Arena));
@@ -63,6 +84,11 @@ USRBasedTypeContext::USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
6384

6485
TypeRelation
6586
USRBasedTypeContext::typeRelation(const USRBasedType *ResultType) const {
87+
if (ExpectedCustomAttributeKinds) {
88+
return ResultType->getCustomAttributeKinds() & ExpectedCustomAttributeKinds
89+
? TypeRelation::Convertible
90+
: TypeRelation::Unrelated;
91+
}
6692
const USRBasedType *VoidType = Arena.getVoidType();
6793
if (ResultType == VoidType) {
6894
// Void is not convertible to anything and we don't report Void <-> Void
@@ -85,7 +111,7 @@ USRBasedTypeContext::typeRelation(const USRBasedType *ResultType) const {
85111

86112
USRBasedTypeArena::USRBasedTypeArena() {
87113
// '$sytD' is the USR of the Void type.
88-
VoidType = USRBasedType::fromUSR("$sytD", {}, *this);
114+
VoidType = USRBasedType::fromUSR("$sytD", {}, {}, *this);
89115
}
90116

91117
const USRBasedType *USRBasedTypeArena::getVoidType() const { return VoidType; }
@@ -125,11 +151,12 @@ TypeRelation USRBasedType::typeRelationImpl(
125151
}
126152

127153
const USRBasedType *USRBasedType::null(USRBasedTypeArena &Arena) {
128-
return USRBasedType::fromUSR(/*USR=*/"", /*Supertypes=*/{}, Arena);
154+
return USRBasedType::fromUSR(/*USR=*/"", /*Supertypes=*/{}, {}, Arena);
129155
}
130156

131157
const USRBasedType *
132158
USRBasedType::fromUSR(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
159+
OptionSet<CustomAttributeKind> CustomAttributeKinds,
133160
USRBasedTypeArena &Arena) {
134161
auto ExistingTypeIt = Arena.CanonicalTypes.find(USR);
135162
if (ExistingTypeIt != Arena.CanonicalTypes.end()) {
@@ -142,7 +169,7 @@ USRBasedType::fromUSR(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
142169
Supertypes = Supertypes.copy(Arena.Allocator);
143170

144171
const USRBasedType *Result =
145-
new (Arena.Allocator) USRBasedType(USR, Supertypes);
172+
new (Arena.Allocator) USRBasedType(USR, Supertypes, CustomAttributeKinds);
146173
Arena.CanonicalTypes[USR] = Result;
147174
return Result;
148175
}
@@ -251,7 +278,8 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
251278
return ImpliedSupertypes.contains(Ty);
252279
});
253280

254-
return USRBasedType::fromUSR(USR, Supertypes, Arena);
281+
return USRBasedType::fromUSR(USR, Supertypes, ::getCustomAttributeKinds(Ty),
282+
Arena);
255283
}
256284

257285
TypeRelation USRBasedType::typeRelation(const USRBasedType *ResultType,
@@ -309,6 +337,12 @@ calculateMaxTypeRelation(Type Ty, const ExpectedTypeContext &typeContext,
309337
const DeclContext &DC) {
310338
if (Ty->isVoid() && typeContext.requiresNonVoid())
311339
return TypeRelation::Invalid;
340+
if (typeContext.getExpectedCustomAttributeKinds()) {
341+
return (getCustomAttributeKinds(Ty) &
342+
typeContext.getExpectedCustomAttributeKinds())
343+
? TypeRelation::Convertible
344+
: TypeRelation::Unrelated;
345+
}
312346
if (typeContext.empty())
313347
return TypeRelation::Unknown;
314348

0 commit comments

Comments
 (0)