Skip to content

Commit edc86bd

Browse files
committed
[CodeCompletion] Mark types that can’t be used as attributes as having an invalid type relation when used after '@'
When completing after `@`, record what kind of attributes are applicable here (property wrapper, result builder, global actor), mark types that are marked as property wrapper etc. as having a 'Convertible' type relation and mark all other types as having an invalid type relation. rdar://78239501
1 parent 1cf0345 commit edc86bd

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
@@ -174,6 +197,9 @@ class USRBasedTypeContext {
174197

175198
SmallVector<ContextualType, 4> ContextualTypes;
176199

200+
/// See \c ExpectedTypeContext::ExpectedAttributeKinds.
201+
OptionSet<CustomAttributeKind> ExpectedCustomAttributeKinds;
202+
177203
public:
178204
/// Create a USR-based equivalent of the \p TypeContext.
179205
USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
@@ -203,10 +229,15 @@ class USRBasedType {
203229
/// declared in the same module that the type was defined.
204230
ArrayRef<const USRBasedType *> Supertypes;
205231

232+
/// The kinds of attributes this type can be used as.
233+
OptionSet<CustomAttributeKind> CustomAttributeKinds;
234+
206235
/// Memberwise initializer. \p USR and \p Supertypes need to be allocated in
207236
/// the same arena as this \c USRBasedType.
208-
USRBasedType(StringRef USR, ArrayRef<const USRBasedType *> Supertypes)
209-
: USR(USR), Supertypes(Supertypes) {}
237+
USRBasedType(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
238+
OptionSet<CustomAttributeKind> CustomAttributeKinds)
239+
: USR(USR), Supertypes(Supertypes),
240+
CustomAttributeKinds(CustomAttributeKinds) {}
210241

211242
/// Implementation of \c typeRelation. \p VisistedTypes keeps track which
212243
/// types have already been visited.
@@ -225,13 +256,18 @@ class USRBasedType {
225256

226257
/// Construct as \c USRBasedType from a USR and its supertypes. This method
227258
/// takes care of copying \p USR and \p Supertypes to \p Arena.
228-
static const USRBasedType *fromUSR(StringRef USR,
229-
ArrayRef<const USRBasedType *> Supertypes,
230-
USRBasedTypeArena &Arena);
259+
static const USRBasedType *
260+
fromUSR(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
261+
OptionSet<CustomAttributeKind> CustomAttributeKinds,
262+
USRBasedTypeArena &Arena);
231263

232264
StringRef getUSR() const { return USR; }
233265
ArrayRef<const USRBasedType *> getSupertypes() const { return Supertypes; }
234266

267+
OptionSet<CustomAttributeKind> getCustomAttributeKinds() const {
268+
return CustomAttributeKinds;
269+
}
270+
235271
/// Compute the relation of \c ResultType when to this contextual type.
236272
CodeCompletionResultTypeRelation
237273
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
@@ -1701,6 +1701,35 @@ void CodeCompletionCallbacksImpl::doneParsing() {
17011701

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

17051734
// TypeName at attribute position after '@'.
17061735
// - 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),
@@ -65,6 +86,11 @@ USRBasedTypeContext::USRBasedTypeContext(const ExpectedTypeContext *TypeContext,
6586

6687
TypeRelation
6788
USRBasedTypeContext::typeRelation(const USRBasedType *ResultType) const {
89+
if (ExpectedCustomAttributeKinds) {
90+
return ResultType->getCustomAttributeKinds() & ExpectedCustomAttributeKinds
91+
? TypeRelation::Convertible
92+
: TypeRelation::Unrelated;
93+
}
6894
const USRBasedType *VoidType = Arena.getVoidType();
6995
if (ResultType == VoidType) {
7096
// Void is not convertible to anything and we don't report Void <-> Void
@@ -84,7 +110,7 @@ USRBasedTypeContext::typeRelation(const USRBasedType *ResultType) const {
84110

85111
USRBasedTypeArena::USRBasedTypeArena() {
86112
// '$sytD' is the USR of the Void type.
87-
VoidType = USRBasedType::fromUSR("$sytD", {}, *this);
113+
VoidType = USRBasedType::fromUSR("$sytD", {}, {}, *this);
88114
}
89115

90116
const USRBasedType *USRBasedTypeArena::getVoidType() const { return VoidType; }
@@ -124,11 +150,12 @@ TypeRelation USRBasedType::typeRelationImpl(
124150
}
125151

126152
const USRBasedType *USRBasedType::null(USRBasedTypeArena &Arena) {
127-
return USRBasedType::fromUSR(/*USR=*/"", /*Supertypes=*/{}, Arena);
153+
return USRBasedType::fromUSR(/*USR=*/"", /*Supertypes=*/{}, {}, Arena);
128154
}
129155

130156
const USRBasedType *
131157
USRBasedType::fromUSR(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
158+
OptionSet<CustomAttributeKind> CustomAttributeKinds,
132159
USRBasedTypeArena &Arena) {
133160
auto ExistingTypeIt = Arena.CanonicalTypes.find(USR);
134161
if (ExistingTypeIt != Arena.CanonicalTypes.end()) {
@@ -141,7 +168,7 @@ USRBasedType::fromUSR(StringRef USR, ArrayRef<const USRBasedType *> Supertypes,
141168
Supertypes = Supertypes.copy(Arena.Allocator);
142169

143170
const USRBasedType *Result =
144-
new (Arena.Allocator) USRBasedType(USR, Supertypes);
171+
new (Arena.Allocator) USRBasedType(USR, Supertypes, CustomAttributeKinds);
145172
Arena.CanonicalTypes[USR] = Result;
146173
return Result;
147174
}
@@ -222,7 +249,8 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
222249
return ImpliedSupertypes.contains(Ty);
223250
});
224251

225-
return USRBasedType::fromUSR(USR, Supertypes, Arena);
252+
return USRBasedType::fromUSR(USR, Supertypes, ::getCustomAttributeKinds(Ty),
253+
Arena);
226254
}
227255

228256
TypeRelation USRBasedType::typeRelation(const USRBasedType *ResultType,
@@ -284,6 +312,12 @@ calculateMaxTypeRelation(Type Ty, const ExpectedTypeContext &typeContext,
284312
const DeclContext &DC) {
285313
if (Ty->isVoid() && typeContext.requiresNonVoid())
286314
return TypeRelation::Invalid;
315+
if (typeContext.getExpectedCustomAttributeKinds()) {
316+
return (getCustomAttributeKinds(Ty) &
317+
typeContext.getExpectedCustomAttributeKinds())
318+
? TypeRelation::Convertible
319+
: TypeRelation::Unrelated;
320+
}
287321
if (typeContext.empty())
288322
return TypeRelation::Unknown;
289323

0 commit comments

Comments
 (0)