Skip to content

Commit 17ac201

Browse files
authored
Merge pull request #39373 from ahoppen/pr/solver-based-arg-completion
[CodeCompletion] Migrate argument position completion to the solver-based implementation
2 parents 7390f7d + f538d33 commit 17ac201

30 files changed

+1540
-181
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- ArgumentCompletion.h -----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 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_ARGUMENTCOMPLETION_H
14+
#define SWIFT_IDE_ARGUMENTCOMPLETION_H
15+
16+
#include "swift/IDE/CodeCompletionConsumer.h"
17+
#include "swift/IDE/CodeCompletionContext.h"
18+
#include "swift/IDE/PossibleParamInfo.h"
19+
#include "swift/Sema/CodeCompletionTypeChecking.h"
20+
21+
namespace swift {
22+
namespace ide {
23+
24+
class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
25+
struct Result {
26+
/// The type associated with the code completion expression itself.
27+
Type ExpectedType;
28+
/// True if this is a subscript rather than a function call.
29+
bool IsSubscript;
30+
/// The FuncDecl or SubscriptDecl associated with the call.
31+
ValueDecl *FuncD;
32+
/// The type of the function being called.
33+
Type FuncTy;
34+
/// The index of the argument containing the completion location
35+
unsigned ArgIdx;
36+
/// The index of the parameter corresponding to the completion argument.
37+
Optional<unsigned> ParamIdx;
38+
/// The indices of all params that were bound to non-synthesized
39+
/// arguments. Used so we don't suggest them even when the args are out of
40+
/// order.
41+
std::set<unsigned> ClaimedParamIndices;
42+
/// True if the completion is a noninitial term in a variadic argument.
43+
bool IsNoninitialVariadic;
44+
/// The base type of the call/subscript (null for free functions).
45+
Type BaseType;
46+
/// True if an argument label precedes the completion location.
47+
bool HasLabel;
48+
};
49+
50+
CodeCompletionExpr *CompletionExpr;
51+
SmallVector<Result, 4> Results;
52+
53+
/// Populates a vector of parameters to suggest along with a vector of types
54+
/// to match the lookup results against.
55+
///
56+
/// \Returns true if global lookup should be performed.
57+
bool addPossibleParams(const ArgumentTypeCheckCompletionCallback::Result &Res,
58+
SmallVectorImpl<PossibleParamInfo> &Params,
59+
SmallVectorImpl<Type> &Types);
60+
61+
public:
62+
ArgumentTypeCheckCompletionCallback(CodeCompletionExpr *CompletionExpr)
63+
: CompletionExpr(CompletionExpr) {}
64+
65+
void sawSolution(const constraints::Solution &solution) override;
66+
67+
/// \param IncludeSignature Whether to include a suggestion for the entire
68+
/// function signature instead of suggesting individual labels. Used when
69+
/// completing after the opening '(' of a function call \param Loc The
70+
/// location of the code completion token
71+
void deliverResults(bool IncludeSignature, SourceLoc Loc, DeclContext *DC,
72+
CodeCompletionContext &CompletionCtx,
73+
CodeCompletionConsumer &Consumer);
74+
};
75+
76+
} // end namespace ide
77+
} // end namespace swift
78+
79+
#endif // SWIFT_IDE_ARGUMENTCOMPLETION_H

include/swift/IDE/CodeCompletion.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ void lookupCodeCompletionResultsFromModule(CodeCompletionResultSink &targetSink,
8484
bool needLeadingDot,
8585
const SourceFile *SF);
8686

87+
void addExprKeywords(CodeCompletionResultSink &Sink, DeclContext *DC);
88+
89+
void addSuperKeyword(CodeCompletionResultSink &Sink, DeclContext *DC);
90+
8791
} // end namespace ide
8892
} // end namespace swift
8993

include/swift/IDE/PossibleParamInfo.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ struct PossibleParamInfo {
3333
assert((Param || !IsRequired) &&
3434
"nullptr with required flag is not allowed");
3535
};
36+
37+
friend bool operator==(const PossibleParamInfo &lhs,
38+
const PossibleParamInfo &rhs) {
39+
bool ParamsMatch;
40+
if (lhs.Param == nullptr && rhs.Param == nullptr) {
41+
ParamsMatch = true;
42+
} else if (lhs.Param == nullptr || rhs.Param == nullptr) {
43+
// One is nullptr but the other is not.
44+
ParamsMatch = false;
45+
} else {
46+
// Both are not nullptr.
47+
ParamsMatch = (*lhs.Param == *rhs.Param);
48+
}
49+
return ParamsMatch && (lhs.IsRequired == rhs.IsRequired);
50+
}
3651
};
3752

3853
} // end namespace ide

include/swift/Sema/ConstraintSystem.h

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ class TypeVariableType::Implementation {
386386

387387
bool isTypeSequence() const;
388388

389+
/// Determine whether this type variable represents a code completion
390+
/// expression.
391+
bool isCodeCompletionToken() const;
392+
389393
/// Retrieve the representative of the equivalence class to which this
390394
/// type variable belongs.
391395
///
@@ -2409,6 +2413,10 @@ class ConstraintSystem {
24092413
/// diagnostics when result builder has multiple overloads.
24102414
llvm::SmallDenseSet<AnyFunctionRef> InvalidResultBuilderBodies;
24112415

2416+
/// Arguments after the code completion token that were thus ignored (i.e.
2417+
/// assigned fresh type variables) for type checking.
2418+
llvm::SetVector<ConstraintLocator *> IgnoredArguments;
2419+
24122420
/// Maps node types used within all portions of the constraint
24132421
/// system, instead of directly using the types on the
24142422
/// nodes themselves. This allows us to typecheck and
@@ -3174,9 +3182,24 @@ class ConstraintSystem {
31743182
return TypeVariables.count(typeVar) > 0;
31753183
}
31763184

3177-
/// Whether the given expression's source range contains the code
3185+
/// Whether the given ASTNode's source range contains the code
31783186
/// completion location.
3179-
bool containsCodeCompletionLoc(Expr *expr) const;
3187+
bool containsCodeCompletionLoc(ASTNode node) const;
3188+
bool containsCodeCompletionLoc(const ArgumentList *args) const;
3189+
3190+
/// Marks the argument with the \p ArgLoc locator as being ignored because it
3191+
/// occurs after the code completion token. This assumes that the argument is
3192+
/// not type checked (by assigning it a fresh type variable) and prevents
3193+
/// fixes from being generated for this argument.
3194+
void markArgumentIgnoredForCodeCompletion(ConstraintLocator *ArgLoc) {
3195+
IgnoredArguments.insert(ArgLoc);
3196+
}
3197+
3198+
/// Whether the argument with the \p ArgLoc locator occurs after the code
3199+
/// completion tokena and thus should be ignored and not generate any fixes.
3200+
bool isArgumentIgnoredForCodeCompletion(ConstraintLocator *ArgLoc) {
3201+
return IgnoredArguments.count(ArgLoc) > 0;
3202+
}
31803203

31813204
void setClosureType(const ClosureExpr *closure, FunctionType *type) {
31823205
assert(closure);
@@ -5537,8 +5560,44 @@ class MatchCallArgumentListener {
55375560
/// \returns true to indicate that this should cause a failure, false
55385561
/// otherwise.
55395562
virtual bool relabelArguments(ArrayRef<Identifier> newNames);
5563+
5564+
/// \returns true if matchCallArguments should try to claim the argument at
5565+
/// \p argIndex while recovering from a failure. This is used to prevent
5566+
/// claiming of arguments after the code completion token.
5567+
virtual bool shouldClaimArgDuringRecovery(unsigned argIdx);
5568+
5569+
/// \returns true if \p arg can be claimed even though its argument label
5570+
/// doesn't match. This is the case for arguments representing the code
5571+
/// completion token if they don't contain a label. In these cases completion
5572+
/// will suggest the label.
5573+
virtual bool
5574+
canClaimArgIgnoringNameMismatch(const AnyFunctionType::Param &arg);
55405575
};
55415576

5577+
/// For a callsite containing a code completion expression, stores the index of
5578+
/// the arg containing it along with the index of the first trailing closure and
5579+
/// how many arguments were passed in total.
5580+
struct CompletionArgInfo {
5581+
unsigned completionIdx;
5582+
Optional<unsigned> firstTrailingIdx;
5583+
unsigned argCount;
5584+
5585+
/// \returns true if the given argument index is possibly about to be written
5586+
/// by the user (given the completion index) so shouldn't be penalised as
5587+
/// missing when ranking solutions.
5588+
bool allowsMissingArgAt(unsigned argInsertIdx, AnyFunctionType::Param param);
5589+
5590+
/// \returns true if the argument containing the completion location is before
5591+
/// the argument with the given index.
5592+
bool isBefore(unsigned argIdx) { return completionIdx < argIdx; }
5593+
};
5594+
5595+
/// Extracts the index of the argument containing the code completion location
5596+
/// from the provided anchor if it's a \c CallExpr, \c SubscriptExpr, or
5597+
/// \c ObjectLiteralExpr.
5598+
Optional<CompletionArgInfo> getCompletionArgInfo(ASTNode anchor,
5599+
ConstraintSystem &cs);
5600+
55425601
/// Match the call arguments (as described by the given argument type) to
55435602
/// the parameters (as described by the given parameter type).
55445603
///

0 commit comments

Comments
 (0)