Skip to content

Commit cc8e28c

Browse files
authored
Merge pull request #62359 from ahoppen/ahoppen/solver-based-cursor-info-prep-pt-2
[IDE] Two more preparation commits for solver-based cursor info
2 parents 82048bd + 4b62682 commit cc8e28c

File tree

8 files changed

+178
-101
lines changed

8 files changed

+178
-101
lines changed

include/swift/AST/ASTContext.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ class ASTContext final {
288288

289289
ide::TypeCheckCompletionCallback *CompletionCallback = nullptr;
290290

291+
/// A callback that will be called when the constraint system found a
292+
/// solution. Called multiple times if the constraint system has ambiguous
293+
/// solutions.
294+
ide::TypeCheckCompletionCallback *SolutionCallback = nullptr;
295+
291296
/// The request-evaluator that is used to process various requests.
292297
Evaluator evaluator;
293298

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===--- SelectedOverloadInfo.h -------------------------------------------===//
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_SWIFTCOMPLETIONINFO_H
14+
#define SWIFT_IDE_SWIFTCOMPLETIONINFO_H
15+
16+
#include "swift/AST/Decl.h"
17+
#include "swift/Sema/ConstraintSystem.h"
18+
19+
namespace swift {
20+
namespace ide {
21+
22+
using namespace swift::constraints;
23+
24+
/// Information that \c getSelectedOverloadInfo gathered about a
25+
/// \c SelectedOverload.
26+
struct SelectedOverloadInfo {
27+
/// The function that is being called or the value that is being accessed.
28+
ValueDecl *Value = nullptr;
29+
/// For a function, type of the called function itself (not its result type),
30+
/// for an arbitrary value the type of that value.
31+
Type ValueTy;
32+
/// The type on which the overload is being accessed. \c null if it does not
33+
/// have a base type, e.g. for a free function.
34+
Type BaseTy;
35+
};
36+
37+
/// Extract additional information about the overload that is being called by
38+
/// \p CalleeLocator.
39+
SelectedOverloadInfo getSelectedOverloadInfo(const Solution &S,
40+
ConstraintLocator *CalleeLocator);
41+
42+
} // end namespace ide
43+
} // end namespace swift
44+
45+
#endif // SWIFT_IDE_SWIFTCOMPLETIONINFO_H

include/swift/IDE/Utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/DeclNameLoc.h"
1919
#include "swift/AST/Effects.h"
2020
#include "swift/AST/Module.h"
21+
#include "swift/AST/Expr.h"
2122
#include "swift/Basic/LLVM.h"
2223
#include "swift/IDE/SourceEntityWalker.h"
2324
#include "swift/Parse/Token.h"
@@ -740,7 +741,7 @@ bool isDeclOverridable(ValueDecl *D);
740741
/// one in `SomeType`. Contrast that to `type(of: foo).classMethod()` where
741742
/// `classMethod` could be any `classMethod` up or down the hierarchy from the
742743
/// type of the \p Base expression.
743-
bool isDynamicRef(Expr *Base, ValueDecl *D);
744+
bool isDynamicRef(Expr *Base, ValueDecl *D, llvm::function_ref<Type(Expr *)> getType = [](Expr *E) { return E->getType(); });
744745

745746
/// Adds the resolved nominal types of \p Base to \p Types.
746747
void getReceiverType(Expr *Base,

lib/IDE/ArgumentCompletion.cpp

Lines changed: 7 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "swift/IDE/ArgumentCompletion.h"
1414
#include "swift/IDE/CodeCompletion.h"
1515
#include "swift/IDE/CompletionLookup.h"
16+
#include "swift/IDE/SelectedOverloadInfo.h"
1617
#include "swift/Sema/ConstraintSystem.h"
1718
#include "swift/Sema/IDETypeChecking.h"
1819

@@ -78,98 +79,6 @@ bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
7879
return ShowGlobalCompletions;
7980
}
8081

81-
/// Information that \c getSelectedOverloadInfo gathered about a
82-
/// \c SelectedOverload.
83-
struct SelectedOverloadInfo {
84-
/// The function that is being called.
85-
ValueDecl *FuncD = nullptr;
86-
/// The type of the called function itself (not its result type)
87-
Type FuncTy;
88-
/// The type on which the function is being called. \c null if the function is
89-
/// a free function.
90-
Type CallBaseTy;
91-
};
92-
93-
/// Extract additional information about the overload that is being called by
94-
/// \p CalleeLocator.
95-
SelectedOverloadInfo getSelectedOverloadInfo(const Solution &S,
96-
ConstraintLocator *CalleeLocator) {
97-
auto &CS = S.getConstraintSystem();
98-
99-
SelectedOverloadInfo Result;
100-
101-
auto SelectedOverload = S.getOverloadChoiceIfAvailable(CalleeLocator);
102-
if (!SelectedOverload) {
103-
return Result;
104-
}
105-
106-
switch (SelectedOverload->choice.getKind()) {
107-
case OverloadChoiceKind::KeyPathApplication:
108-
case OverloadChoiceKind::Decl:
109-
case OverloadChoiceKind::DeclViaDynamic:
110-
case OverloadChoiceKind::DeclViaBridge:
111-
case OverloadChoiceKind::DeclViaUnwrappedOptional: {
112-
Result.CallBaseTy = SelectedOverload->choice.getBaseType();
113-
if (Result.CallBaseTy) {
114-
Result.CallBaseTy = S.simplifyType(Result.CallBaseTy)->getRValueType();
115-
}
116-
117-
Result.FuncD = SelectedOverload->choice.getDeclOrNull();
118-
Result.FuncTy =
119-
S.simplifyTypeForCodeCompletion(SelectedOverload->adjustedOpenedType);
120-
121-
// For completion as the arg in a call to the implicit [keypath: _]
122-
// subscript the solver can't know what kind of keypath is expected without
123-
// an actual argument (e.g. a KeyPath vs WritableKeyPath) so it ends up as a
124-
// hole. Just assume KeyPath so we show the expected keypath's root type to
125-
// users rather than '_'.
126-
if (SelectedOverload->choice.getKind() ==
127-
OverloadChoiceKind::KeyPathApplication) {
128-
auto Params = Result.FuncTy->getAs<AnyFunctionType>()->getParams();
129-
if (Params.size() == 1 &&
130-
Params[0].getPlainType()->is<UnresolvedType>()) {
131-
auto *KPDecl = CS.getASTContext().getKeyPathDecl();
132-
Type KPTy =
133-
KPDecl->mapTypeIntoContext(KPDecl->getDeclaredInterfaceType());
134-
Type KPValueTy = KPTy->castTo<BoundGenericType>()->getGenericArgs()[1];
135-
KPTy = BoundGenericType::get(KPDecl, Type(),
136-
{Result.CallBaseTy, KPValueTy});
137-
Result.FuncTy =
138-
FunctionType::get({Params[0].withType(KPTy)}, KPValueTy);
139-
}
140-
}
141-
break;
142-
}
143-
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
144-
auto *fnType = SelectedOverload->adjustedOpenedType->castTo<FunctionType>();
145-
assert(fnType->getParams().size() == 1 &&
146-
"subscript always has one argument");
147-
// Parameter type is KeyPath<T, U> where `T` is a root type
148-
// and U is a leaf type (aka member type).
149-
auto keyPathTy =
150-
fnType->getParams()[0].getPlainType()->castTo<BoundGenericType>();
151-
152-
auto *keyPathDecl = keyPathTy->getAnyNominal();
153-
assert(isKnownKeyPathType(keyPathTy) &&
154-
"parameter is supposed to be a keypath");
155-
156-
auto KeyPathDynamicLocator = CS.getConstraintLocator(
157-
CalleeLocator, LocatorPathElt::KeyPathDynamicMember(keyPathDecl));
158-
Result = getSelectedOverloadInfo(S, KeyPathDynamicLocator);
159-
break;
160-
}
161-
case OverloadChoiceKind::DynamicMemberLookup:
162-
case OverloadChoiceKind::TupleIndex:
163-
// If it's DynamicMemberLookup, we don't know which function is being
164-
// called, so we can't extract any information from it.
165-
// TupleIndex isn't a function call and is not relevant for argument
166-
// completion because it doesn't take arguments.
167-
break;
168-
}
169-
170-
return Result;
171-
}
172-
17382
void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
17483
Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);
17584

@@ -246,9 +155,9 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
246155

247156
// If this is a duplicate of any other result, ignore this solution.
248157
if (llvm::any_of(Results, [&](const Result &R) {
249-
return R.FuncD == Info.FuncD &&
250-
nullableTypesEqual(R.FuncTy, Info.FuncTy) &&
251-
nullableTypesEqual(R.BaseType, Info.CallBaseTy) &&
158+
return R.FuncD == Info.Value &&
159+
nullableTypesEqual(R.FuncTy, Info.ValueTy) &&
160+
nullableTypesEqual(R.BaseType, Info.BaseTy) &&
252161
R.ParamIdx == ParamIdx &&
253162
R.IsNoninitialVariadic == IsNoninitialVariadic;
254163
})) {
@@ -258,9 +167,9 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
258167
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;
259168
getSolutionSpecificVarTypes(S, SolutionSpecificVarTypes);
260169

261-
Results.push_back({ExpectedTy, isa<SubscriptExpr>(ParentCall), Info.FuncD,
262-
Info.FuncTy, ArgIdx, ParamIdx, std::move(ClaimedParams),
263-
IsNoninitialVariadic, Info.CallBaseTy, HasLabel, IsAsync,
170+
Results.push_back({ExpectedTy, isa<SubscriptExpr>(ParentCall), Info.Value,
171+
Info.ValueTy, ArgIdx, ParamIdx, std::move(ClaimedParams),
172+
IsNoninitialVariadic, Info.BaseTy, HasLabel, IsAsync,
264173
SolutionSpecificVarTypes});
265174
}
266175

lib/IDE/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_swift_host_library(swiftIDE STATIC
2929
ModuleInterfacePrinting.cpp
3030
PostfixCompletion.cpp
3131
REPLCodeCompletion.cpp
32+
SelectedOverloadInfo.cpp
3233
SourceEntityWalker.cpp
3334
SwiftSourceDocInfo.cpp
3435
SyntaxModel.cpp

lib/IDE/SelectedOverloadInfo.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===--- SelectedOverloadInfo.cpp -----------------------------------------===//
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+
#include "swift/IDE/SelectedOverloadInfo.h"
14+
15+
using namespace swift::ide;
16+
17+
SelectedOverloadInfo
18+
swift::ide::getSelectedOverloadInfo(const Solution &S,
19+
ConstraintLocator *CalleeLocator) {
20+
auto &CS = S.getConstraintSystem();
21+
22+
SelectedOverloadInfo Result;
23+
24+
auto SelectedOverload = S.getOverloadChoiceIfAvailable(CalleeLocator);
25+
if (!SelectedOverload) {
26+
return Result;
27+
}
28+
29+
switch (SelectedOverload->choice.getKind()) {
30+
case OverloadChoiceKind::KeyPathApplication:
31+
case OverloadChoiceKind::Decl:
32+
case OverloadChoiceKind::DeclViaDynamic:
33+
case OverloadChoiceKind::DeclViaBridge:
34+
case OverloadChoiceKind::DeclViaUnwrappedOptional: {
35+
Result.BaseTy = SelectedOverload->choice.getBaseType();
36+
if (Result.BaseTy) {
37+
Result.BaseTy = S.simplifyType(Result.BaseTy)->getRValueType();
38+
}
39+
40+
Result.Value = SelectedOverload->choice.getDeclOrNull();
41+
Result.ValueTy =
42+
S.simplifyTypeForCodeCompletion(SelectedOverload->adjustedOpenedType);
43+
44+
// For completion as the arg in a call to the implicit [keypath: _]
45+
// subscript the solver can't know what kind of keypath is expected without
46+
// an actual argument (e.g. a KeyPath vs WritableKeyPath) so it ends up as a
47+
// hole. Just assume KeyPath so we show the expected keypath's root type to
48+
// users rather than '_'.
49+
if (SelectedOverload->choice.getKind() ==
50+
OverloadChoiceKind::KeyPathApplication) {
51+
auto Params = Result.ValueTy->getAs<AnyFunctionType>()->getParams();
52+
if (Params.size() == 1 &&
53+
Params[0].getPlainType()->is<UnresolvedType>()) {
54+
auto *KPDecl = CS.getASTContext().getKeyPathDecl();
55+
Type KPTy =
56+
KPDecl->mapTypeIntoContext(KPDecl->getDeclaredInterfaceType());
57+
Type KPValueTy = KPTy->castTo<BoundGenericType>()->getGenericArgs()[1];
58+
KPTy =
59+
BoundGenericType::get(KPDecl, Type(), {Result.BaseTy, KPValueTy});
60+
Result.ValueTy =
61+
FunctionType::get({Params[0].withType(KPTy)}, KPValueTy);
62+
}
63+
}
64+
break;
65+
}
66+
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
67+
auto *fnType = SelectedOverload->adjustedOpenedType->castTo<FunctionType>();
68+
assert(fnType->getParams().size() == 1 &&
69+
"subscript always has one argument");
70+
// Parameter type is KeyPath<T, U> where `T` is a root type
71+
// and U is a leaf type (aka member type).
72+
auto keyPathTy =
73+
fnType->getParams()[0].getPlainType()->castTo<BoundGenericType>();
74+
75+
auto *keyPathDecl = keyPathTy->getAnyNominal();
76+
assert(isKnownKeyPathType(keyPathTy) &&
77+
"parameter is supposed to be a keypath");
78+
79+
auto KeyPathDynamicLocator = CS.getConstraintLocator(
80+
CalleeLocator, LocatorPathElt::KeyPathDynamicMember(keyPathDecl));
81+
Result = getSelectedOverloadInfo(S, KeyPathDynamicLocator);
82+
break;
83+
}
84+
case OverloadChoiceKind::DynamicMemberLookup:
85+
case OverloadChoiceKind::TupleIndex:
86+
// If it's DynamicMemberLookup, we don't know which function is being
87+
// called, so we can't extract any information from it.
88+
// TupleIndex isn't a function call and is not relevant for argument
89+
// completion because it doesn't take arguments.
90+
break;
91+
}
92+
93+
return Result;
94+
}

lib/IDE/Utils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,7 @@ bool swift::ide::isDeclOverridable(ValueDecl *D) {
921921
return true;
922922
}
923923

924-
bool swift::ide::isDynamicRef(Expr *Base, ValueDecl *D) {
924+
bool swift::ide::isDynamicRef(Expr *Base, ValueDecl *D, llvm::function_ref<Type(Expr *)> getType) {
925925
if (!isDeclOverridable(D))
926926
return false;
927927

@@ -940,7 +940,7 @@ bool swift::ide::isDynamicRef(Expr *Base, ValueDecl *D) {
940940

941941
// `type(of: foo).staticOrClassMethod()`. A static method may be "dynamic"
942942
// here, but not if the instance type is a struct/enum.
943-
if (auto IT = Base->getType()->getAs<MetatypeType>()) {
943+
if (auto IT = getType(Base)->getAs<MetatypeType>()) {
944944
auto InstanceType = IT->getInstanceType();
945945
if (InstanceType->getStructOrBoundGenericStruct() ||
946946
InstanceType->getEnumOrBoundGenericEnum())

lib/Sema/CSSolver.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,24 @@ Optional<std::vector<Solution>> ConstraintSystem::solve(
13531353
}
13541354
};
13551355

1356+
auto reportSolutionsToSolutionCallback = [&](const SolutionResult &result) {
1357+
if (!getASTContext().SolutionCallback) {
1358+
return;
1359+
}
1360+
switch (result.getKind()) {
1361+
case SolutionResult::Success:
1362+
getASTContext().SolutionCallback->sawSolution(result.getSolution());
1363+
break;
1364+
case SolutionResult::Ambiguous:
1365+
for (auto &solution : result.getAmbiguousSolutions()) {
1366+
getASTContext().SolutionCallback->sawSolution(solution);
1367+
}
1368+
break;
1369+
default:
1370+
break;
1371+
}
1372+
};
1373+
13561374
// Take up to two attempts at solving the system. The first attempts to
13571375
// solve a system that is expected to be well-formed, the second kicks in
13581376
// when there is an error and attempts to salvage an ill-formed program.
@@ -1365,6 +1383,7 @@ Optional<std::vector<Solution>> ConstraintSystem::solve(
13651383
case SolutionResult::Success: {
13661384
// Return the successful solution.
13671385
dumpSolutions(solution);
1386+
reportSolutionsToSolutionCallback(solution);
13681387
std::vector<Solution> result;
13691388
result.push_back(std::move(solution).takeSolution());
13701389
return std::move(result);
@@ -1394,6 +1413,7 @@ Optional<std::vector<Solution>> ConstraintSystem::solve(
13941413
// If salvaging produced an ambiguous result, it has already been
13951414
// diagnosed.
13961415
if (stage == 1) {
1416+
reportSolutionsToSolutionCallback(solution);
13971417
solution.markAsDiagnosed();
13981418
return None;
13991419
}
@@ -1412,12 +1432,14 @@ Optional<std::vector<Solution>> ConstraintSystem::solve(
14121432

14131433
case SolutionResult::UndiagnosedError:
14141434
if (shouldSuppressDiagnostics()) {
1435+
reportSolutionsToSolutionCallback(solution);
14151436
solution.markAsDiagnosed();
14161437
return None;
14171438
}
14181439

14191440
if (stage == 1) {
14201441
diagnoseFailureFor(target);
1442+
reportSolutionsToSolutionCallback(solution);
14211443
solution.markAsDiagnosed();
14221444
return None;
14231445
}

0 commit comments

Comments
 (0)