Skip to content

Commit df605d4

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 2f0ae44 commit df605d4

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
@@ -1695,6 +1695,35 @@ void CodeCompletionCallbacksImpl::doneParsing() {
16951695

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

16991728
// TypeName at attribute position after '@'.
17001729
// - 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
}
@@ -223,7 +250,8 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
223250
return ImpliedSupertypes.contains(Ty);
224251
});
225252

226-
return USRBasedType::fromUSR(USR, Supertypes, Arena);
253+
return USRBasedType::fromUSR(USR, Supertypes, ::getCustomAttributeKinds(Ty),
254+
Arena);
227255
}
228256

229257
TypeRelation USRBasedType::typeRelation(const USRBasedType *ResultType,
@@ -281,6 +309,12 @@ calculateMaxTypeRelation(Type Ty, const ExpectedTypeContext &typeContext,
281309
const DeclContext &DC) {
282310
if (Ty->isVoid() && typeContext.requiresNonVoid())
283311
return TypeRelation::Invalid;
312+
if (typeContext.getExpectedCustomAttributeKinds()) {
313+
return (getCustomAttributeKinds(Ty) &
314+
typeContext.getExpectedCustomAttributeKinds())
315+
? TypeRelation::Convertible
316+
: TypeRelation::Unrelated;
317+
}
284318
if (typeContext.empty())
285319
return TypeRelation::Unknown;
286320

0 commit comments

Comments
 (0)