Skip to content

Commit bac3b67

Browse files
authored
Merge pull request #40999 from ahoppen/pr/compute-type-relation-in-contextual-result
[SourceKit] Compute code completion type relation when wrapping a ContextFreeCodeCompletionResult in a CodeCompletionResult
2 parents 1665c57 + 6bc0de9 commit bac3b67

File tree

13 files changed

+505
-330
lines changed

13 files changed

+505
-330
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_IDE_CODECOMPLETION_H
1414
#define SWIFT_IDE_CODECOMPLETION_H
1515

16+
#include "CodeCompletionResultType.h"
1617
#include "swift/AST/Identifier.h"
1718
#include "swift/Basic/Debug.h"
1819
#include "swift/Basic/LLVM.h"
@@ -724,6 +725,7 @@ class ContextFreeCodeCompletionResult {
724725
StringRef ModuleName;
725726
StringRef BriefDocComment;
726727
ArrayRef<StringRef> AssociatedUSRs;
728+
CodeCompletionResultType ResultType;
727729

728730
ContextFreeNotRecommendedReason NotRecommended : 3;
729731
static_assert(int(ContextFreeNotRecommendedReason::MAX_VALUE) < 1 << 3, "");
@@ -747,13 +749,15 @@ class ContextFreeCodeCompletionResult {
747749
CodeCompletionOperatorKind KnownOperatorKind, bool IsSystem,
748750
CodeCompletionString *CompletionString, StringRef ModuleName,
749751
StringRef BriefDocComment, ArrayRef<StringRef> AssociatedUSRs,
752+
CodeCompletionResultType ResultType,
750753
ContextFreeNotRecommendedReason NotRecommended,
751754
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
752755
StringRef DiagnosticMessage)
753756
: Kind(Kind), KnownOperatorKind(KnownOperatorKind), IsSystem(IsSystem),
754757
CompletionString(CompletionString), ModuleName(ModuleName),
755758
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
756-
NotRecommended(NotRecommended), DiagnosticSeverity(DiagnosticSeverity),
759+
ResultType(ResultType), NotRecommended(NotRecommended),
760+
DiagnosticSeverity(DiagnosticSeverity),
757761
DiagnosticMessage(DiagnosticMessage) {
758762
this->AssociatedKind.Opaque = AssociatedKind;
759763
assert((NotRecommended == ContextFreeNotRecommendedReason::None) ==
@@ -780,13 +784,14 @@ class ContextFreeCodeCompletionResult {
780784
ContextFreeCodeCompletionResult(
781785
CodeCompletionResultKind Kind, CodeCompletionString *CompletionString,
782786
CodeCompletionOperatorKind KnownOperatorKind, StringRef BriefDocComment,
787+
CodeCompletionResultType ResultType,
783788
ContextFreeNotRecommendedReason NotRecommended,
784789
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
785790
StringRef DiagnosticMessage)
786791
: ContextFreeCodeCompletionResult(
787792
Kind, /*AssociatedKind=*/0, KnownOperatorKind,
788793
/*IsSystem=*/false, CompletionString, /*ModuleName=*/"",
789-
BriefDocComment, /*AssociatedUSRs=*/{}, NotRecommended,
794+
BriefDocComment, /*AssociatedUSRs=*/{}, ResultType, NotRecommended,
790795
DiagnosticSeverity, DiagnosticMessage) {}
791796

792797
/// Constructs a \c Keyword result.
@@ -796,12 +801,14 @@ class ContextFreeCodeCompletionResult {
796801
/// same \c CodeCompletionResultSink as the result itself.
797802
ContextFreeCodeCompletionResult(CodeCompletionKeywordKind Kind,
798803
CodeCompletionString *CompletionString,
799-
StringRef BriefDocComment)
804+
StringRef BriefDocComment,
805+
CodeCompletionResultType ResultType)
800806
: ContextFreeCodeCompletionResult(
801807
CodeCompletionResultKind::Keyword, static_cast<uint8_t>(Kind),
802808
CodeCompletionOperatorKind::None, /*IsSystem=*/false,
803809
CompletionString, /*ModuleName=*/"", BriefDocComment,
804-
/*AssociatedUSRs=*/{}, ContextFreeNotRecommendedReason::None,
810+
/*AssociatedUSRs=*/{}, ResultType,
811+
ContextFreeNotRecommendedReason::None,
805812
CodeCompletionDiagnosticSeverity::None, /*DiagnosticMessage=*/"") {}
806813

807814
/// Constructs a \c Literal result.
@@ -810,13 +817,15 @@ class ContextFreeCodeCompletionResult {
810817
/// result, typically by storing them in the same \c CodeCompletionResultSink
811818
/// as the result itself.
812819
ContextFreeCodeCompletionResult(CodeCompletionLiteralKind LiteralKind,
813-
CodeCompletionString *CompletionString)
820+
CodeCompletionString *CompletionString,
821+
CodeCompletionResultType ResultType)
814822
: ContextFreeCodeCompletionResult(
815823
CodeCompletionResultKind::Literal,
816824
static_cast<uint8_t>(LiteralKind), CodeCompletionOperatorKind::None,
817825
/*IsSystem=*/false, CompletionString, /*ModuleName=*/"",
818826
/*BriefDocComment=*/"",
819-
/*AssociatedUSRs=*/{}, ContextFreeNotRecommendedReason::None,
827+
/*AssociatedUSRs=*/{}, ResultType,
828+
ContextFreeNotRecommendedReason::None,
820829
CodeCompletionDiagnosticSeverity::None, /*DiagnosticMessage=*/"") {}
821830

822831
/// Constructs a \c Declaration result.
@@ -827,7 +836,7 @@ class ContextFreeCodeCompletionResult {
827836
ContextFreeCodeCompletionResult(
828837
CodeCompletionString *CompletionString, const Decl *AssociatedDecl,
829838
StringRef ModuleName, StringRef BriefDocComment,
830-
ArrayRef<StringRef> AssociatedUSRs,
839+
ArrayRef<StringRef> AssociatedUSRs, CodeCompletionResultType ResultType,
831840
ContextFreeNotRecommendedReason NotRecommended,
832841
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
833842
StringRef DiagnosticMessage)
@@ -836,7 +845,7 @@ class ContextFreeCodeCompletionResult {
836845
static_cast<uint8_t>(getCodeCompletionDeclKind(AssociatedDecl)),
837846
CodeCompletionOperatorKind::None, getDeclIsSystem(AssociatedDecl),
838847
CompletionString, ModuleName, BriefDocComment, AssociatedUSRs,
839-
NotRecommended, DiagnosticSeverity, DiagnosticMessage) {
848+
ResultType, NotRecommended, DiagnosticSeverity, DiagnosticMessage) {
840849
assert(AssociatedDecl && "should have a decl");
841850
}
842851

@@ -874,6 +883,8 @@ class ContextFreeCodeCompletionResult {
874883

875884
ArrayRef<StringRef> getAssociatedUSRs() const { return AssociatedUSRs; }
876885

886+
const CodeCompletionResultType &getResultType() const { return ResultType; }
887+
877888
ContextFreeNotRecommendedReason getNotRecommendedReason() const {
878889
return NotRecommended;
879890
}
@@ -909,34 +920,6 @@ class ContextFreeCodeCompletionResult {
909920
/// A single code completion result enriched with information that depend on
910921
/// the completion's usage context.
911922
class CodeCompletionResult {
912-
public:
913-
/// Describes the relationship between the type of the completion results and
914-
/// the expected type at the code completion position.
915-
enum class ExpectedTypeRelation : uint8_t {
916-
/// The result does not have a type (e.g. keyword).
917-
NotApplicable,
918-
919-
/// The type relation have not been calculated.
920-
Unknown,
921-
922-
/// The relationship of the result's type to the expected type is not
923-
/// invalid, not convertible, and not identical.
924-
Unrelated,
925-
926-
/// The result's type is invalid at the expected position.
927-
Invalid,
928-
929-
/// The result's type is convertible to the type of the expected.
930-
Convertible,
931-
932-
/// The result's type is identical to the type of the expected.
933-
Identical,
934-
935-
MAX_VALUE = Identical
936-
};
937-
938-
939-
private:
940923
const ContextFreeCodeCompletionResult &ContextFree;
941924
SemanticContextKind SemanticContext : 3;
942925
static_assert(int(SemanticContextKind::MAX_VALUE) < 1 << 3, "");
@@ -962,17 +945,17 @@ class CodeCompletionResult {
962945
static const unsigned MaxNumBytesToErase = 127;
963946

964947
private:
965-
ExpectedTypeRelation TypeDistance : 3;
966-
public:
967-
/// Enrich a \c ContextFreeCodeCompletionResult with the following contextual
968-
/// information.
948+
CodeCompletionResultTypeRelation TypeDistance : 3;
949+
static_assert(int(CodeCompletionResultTypeRelation::MAX_VALUE) < 1 << 3, "");
950+
951+
/// Memberwise initializer
969952
/// The \c ContextFree result must outlive this result. Typically, this is
970953
/// done by allocating the two in the same sink or adopting the context free
971954
/// sink in the sink that allocates this result.
972955
CodeCompletionResult(const ContextFreeCodeCompletionResult &ContextFree,
973956
SemanticContextKind SemanticContext,
974957
CodeCompletionFlair Flair, uint8_t NumBytesToErase,
975-
ExpectedTypeRelation TypeDistance,
958+
CodeCompletionResultTypeRelation TypeDistance,
976959
ContextualNotRecommendedReason NotRecommended,
977960
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
978961
StringRef DiagnosticMessage)
@@ -982,6 +965,23 @@ class CodeCompletionResult {
982965
DiagnosticMessage(DiagnosticMessage), NumBytesToErase(NumBytesToErase),
983966
TypeDistance(TypeDistance) {}
984967

968+
public:
969+
/// Enrich a \c ContextFreeCodeCompletionResult with the following contextual
970+
/// information.
971+
/// This computes the type relation between the completion item and its
972+
/// expected type context.
973+
/// The \c ContextFree result must outlive this result. Typically, this is
974+
/// done by allocating the two in the same sink or adopting the context free
975+
/// sink in the sink that allocates this result.
976+
CodeCompletionResult(const ContextFreeCodeCompletionResult &ContextFree,
977+
SemanticContextKind SemanticContext,
978+
CodeCompletionFlair Flair, uint8_t NumBytesToErase,
979+
const ExpectedTypeContext *TypeContext,
980+
const DeclContext *DC,
981+
ContextualNotRecommendedReason NotRecommended,
982+
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
983+
StringRef DiagnosticMessage);
984+
985985
const ContextFreeCodeCompletionResult &getContextFreeResult() const {
986986
return ContextFree;
987987
}
@@ -998,7 +998,16 @@ class CodeCompletionResult {
998998
/// context free result outlives the result the result returned by this
999999
/// method.
10001000
CodeCompletionResult *withFlair(CodeCompletionFlair newFlair,
1001-
CodeCompletionResultSink &Sink);
1001+
CodeCompletionResultSink &Sink) const;
1002+
1003+
/// Copy this result to \p Sink with \p newFlair . Note that this does NOT
1004+
/// copy the context free result. Thus the caller needs to ensure that the
1005+
/// context free result outlives the result the result returned by this
1006+
/// method.
1007+
CodeCompletionResult *withContextFreeResultSemanticContextAndFlair(
1008+
const ContextFreeCodeCompletionResult &NewContextFree,
1009+
SemanticContextKind NewSemanticContext, CodeCompletionFlair NewFlair,
1010+
CodeCompletionResultSink &Sink) const;
10021011

10031012
CodeCompletionResultKind getKind() const {
10041013
return getContextFreeResult().getKind();
@@ -1024,7 +1033,9 @@ class CodeCompletionResult {
10241033

10251034
bool isSystem() const { return getContextFreeResult().isSystem(); }
10261035

1027-
ExpectedTypeRelation getExpectedTypeRelation() const { return TypeDistance; }
1036+
CodeCompletionResultTypeRelation getExpectedTypeRelation() const {
1037+
return TypeDistance;
1038+
}
10281039

10291040
/// Get the contextual not-recommended reason. This disregards context-free
10301041
/// not recommended reasons.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//===--- CodeCompletionResultType.h -----------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_IDE_CODECOMPLETIONRESULTTYPE_H
14+
#define SWIFT_IDE_CODECOMPLETIONRESULTTYPE_H
15+
16+
#include "swift/AST/Types.h"
17+
#include "swift/Basic/LLVM.h"
18+
19+
namespace swift {
20+
namespace ide {
21+
22+
/// The expected contextual type(s) for code-completion.
23+
class ExpectedTypeContext {
24+
/// Possible types of the code completion expression.
25+
llvm::SmallVector<Type, 4> PossibleTypes;
26+
27+
/// Pre typechecked type of the expression at the completion position.
28+
Type IdealType;
29+
30+
/// Whether the `ExpectedTypes` comes from a single-expression body, e.g.
31+
/// `foo({ here })`.
32+
///
33+
/// Since the input may be incomplete, we take into account that the types are
34+
/// only a hint.
35+
bool IsImplicitSingleExpressionReturn = false;
36+
bool PreferNonVoid = false;
37+
38+
public:
39+
ExpectedTypeContext() = default;
40+
41+
bool empty() const { return PossibleTypes.empty(); }
42+
43+
ArrayRef<Type> getPossibleTypes() const { return PossibleTypes; }
44+
45+
void setPossibleTypes(ArrayRef<Type> Types) {
46+
PossibleTypes.clear();
47+
PossibleTypes.reserve(Types.size());
48+
for (auto T : Types) {
49+
if (T) {
50+
PossibleTypes.push_back(T);
51+
}
52+
}
53+
}
54+
55+
Type getIdealType() const { return IdealType; }
56+
57+
void setIdealType(Type IdealType) { this->IdealType = IdealType; }
58+
59+
bool requiresNonVoid() const {
60+
if (IsImplicitSingleExpressionReturn)
61+
return false;
62+
if (PreferNonVoid)
63+
return true;
64+
if (PossibleTypes.empty())
65+
return false;
66+
return llvm::all_of(PossibleTypes, [](Type Ty) { return !Ty->isVoid(); });
67+
}
68+
69+
bool isImplicitSingleExpressionReturn() const {
70+
return IsImplicitSingleExpressionReturn;
71+
}
72+
73+
void
74+
setIsImplicitSingleExpressionReturn(bool IsImplicitSingleExpressionReturn) {
75+
this->IsImplicitSingleExpressionReturn = IsImplicitSingleExpressionReturn;
76+
}
77+
78+
bool getPreferNonVoid() const { return PreferNonVoid; }
79+
80+
void setPreferNonVoid(bool PreferNonVoid) {
81+
this->PreferNonVoid = PreferNonVoid;
82+
}
83+
};
84+
85+
/// Describes the relationship between the type of the completion results and
86+
/// the expected type at the code completion position.
87+
enum class CodeCompletionResultTypeRelation : uint8_t {
88+
/// The result does not have a type (e.g. keyword).
89+
NotApplicable,
90+
91+
/// The type relation have not been calculated.
92+
Unknown,
93+
94+
/// The relationship of the result's type to the expected type is not
95+
/// invalid, not convertible, and not identical.
96+
Unrelated,
97+
98+
/// The result's type is invalid at the expected position.
99+
Invalid,
100+
101+
/// The result's type is convertible to the type of the expected.
102+
Convertible,
103+
104+
/// The result's type is identical to the type of the expected.
105+
Identical,
106+
107+
MAX_VALUE = Identical
108+
};
109+
110+
/// The type returned by a \c ContextFreeCodeCompletionResult. Can be either of
111+
/// the following:
112+
/// - Have the NotApplicable flag set: The completion result doesn't produce
113+
/// something that's valid inside an expression like a keyword
114+
/// - An null type if the completion result produces something that's
115+
/// valid inside an expression but the result type isn't known
116+
/// - A proper type if the type produced by this completion result is known
117+
class CodeCompletionResultType {
118+
public:
119+
enum class Flags : unsigned {
120+
IsNotApplicable = 1 << 0,
121+
/// If \p AlsoConsiderMetatype is set the code completion item will be
122+
/// considered as producing the declared interface type (which is passed as
123+
/// \p ResultTypes ) as well as the corresponding metatype.
124+
/// This allows us to suggest 'Int' as 'Identical' for both of the following
125+
/// functions
126+
///
127+
/// func receiveInstance(_: Int) {}
128+
/// func receiveMetatype(_: Int.Type) {}
129+
AlsoConsiderMetatype = 1 << 1
130+
};
131+
132+
private:
133+
llvm::PointerIntPair<Type, 2, OptionSet<Flags>> TypeAndFlags;
134+
135+
CodeCompletionResultType(Type Ty, OptionSet<Flags> Flag)
136+
: TypeAndFlags(Ty, Flag) {}
137+
138+
public:
139+
static CodeCompletionResultType notApplicable() {
140+
return CodeCompletionResultType(Type(), Flags::IsNotApplicable);
141+
}
142+
static CodeCompletionResultType unknown() {
143+
return CodeCompletionResultType(Type(), /*Flags=*/0);
144+
}
145+
CodeCompletionResultType(Type Ty, bool AlsoConsiderMetatype = false)
146+
: CodeCompletionResultType(Ty, AlsoConsiderMetatype
147+
? Flags::AlsoConsiderMetatype
148+
: OptionSet<Flags>()) {}
149+
150+
bool isNotApplicable() const {
151+
return TypeAndFlags.getInt().contains(Flags::IsNotApplicable);
152+
}
153+
154+
/// Calculates the type realtion of this type to the given
155+
CodeCompletionResultTypeRelation
156+
calculateTypeRelation(const ExpectedTypeContext *TypeContext,
157+
const DeclContext *DC) const;
158+
};
159+
} // namespace ide
160+
} // namespace swift
161+
162+
#endif // SWIFT_IDE_CODECOMPLETIONRESULTTYPE_H

lib/IDE/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_swift_host_library(swiftIDE STATIC
44
CodeCompletionCache.cpp
55
CodeCompletionDiagnostics.cpp
66
CodeCompletionResultPrinter.cpp
7+
CodeCompletionResultType.cpp
78
CommentConversion.cpp
89
CompileInstance.cpp
910
CompletionInstance.cpp

0 commit comments

Comments
 (0)