Skip to content

Commit f538d33

Browse files
ahoppennathawes
andcommitted
[CodeCompletion][Sema] Migrate CallArgurment position completion to the solver-based implementation
This hooks up call argument position completion to the typeCheckForCodeCompletion API to generate completions from all the solutions the constraint solver produces (even those requiring fixes), rather than relying on a single solution being applied to the AST (if any). Co-authored-by: Nathan Hawes <nathan.john.hawes@gmail.com>
1 parent ca9056a commit f538d33

29 files changed

+1532
-181
lines changed
+79
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

+4
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

+15
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

+57-2
Original file line numberDiff line numberDiff line change
@@ -2406,6 +2406,10 @@ class ConstraintSystem {
24062406
/// diagnostics when result builder has multiple overloads.
24072407
llvm::SmallDenseSet<AnyFunctionRef> InvalidResultBuilderBodies;
24082408

2409+
/// Arguments after the code completion token that were thus ignored (i.e.
2410+
/// assigned fresh type variables) for type checking.
2411+
llvm::SetVector<ConstraintLocator *> IgnoredArguments;
2412+
24092413
/// Maps node types used within all portions of the constraint
24102414
/// system, instead of directly using the types on the
24112415
/// nodes themselves. This allows us to typecheck and
@@ -3171,9 +3175,24 @@ class ConstraintSystem {
31713175
return TypeVariables.count(typeVar) > 0;
31723176
}
31733177

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

31783197
void setClosureType(const ClosureExpr *closure, FunctionType *type) {
31793198
assert(closure);
@@ -5534,8 +5553,44 @@ class MatchCallArgumentListener {
55345553
/// \returns true to indicate that this should cause a failure, false
55355554
/// otherwise.
55365555
virtual bool relabelArguments(ArrayRef<Identifier> newNames);
5556+
5557+
/// \returns true if matchCallArguments should try to claim the argument at
5558+
/// \p argIndex while recovering from a failure. This is used to prevent
5559+
/// claiming of arguments after the code completion token.
5560+
virtual bool shouldClaimArgDuringRecovery(unsigned argIdx);
5561+
5562+
/// \returns true if \p arg can be claimed even though its argument label
5563+
/// doesn't match. This is the case for arguments representing the code
5564+
/// completion token if they don't contain a label. In these cases completion
5565+
/// will suggest the label.
5566+
virtual bool
5567+
canClaimArgIgnoringNameMismatch(const AnyFunctionType::Param &arg);
5568+
};
5569+
5570+
/// For a callsite containing a code completion expression, stores the index of
5571+
/// the arg containing it along with the index of the first trailing closure and
5572+
/// how many arguments were passed in total.
5573+
struct CompletionArgInfo {
5574+
unsigned completionIdx;
5575+
Optional<unsigned> firstTrailingIdx;
5576+
unsigned argCount;
5577+
5578+
/// \returns true if the given argument index is possibly about to be written
5579+
/// by the user (given the completion index) so shouldn't be penalised as
5580+
/// missing when ranking solutions.
5581+
bool allowsMissingArgAt(unsigned argInsertIdx, AnyFunctionType::Param param);
5582+
5583+
/// \returns true if the argument containing the completion location is before
5584+
/// the argument with the given index.
5585+
bool isBefore(unsigned argIdx) { return completionIdx < argIdx; }
55375586
};
55385587

5588+
/// Extracts the index of the argument containing the code completion location
5589+
/// from the provided anchor if it's a \c CallExpr, \c SubscriptExpr, or
5590+
/// \c ObjectLiteralExpr.
5591+
Optional<CompletionArgInfo> getCompletionArgInfo(ASTNode anchor,
5592+
ConstraintSystem &cs);
5593+
55395594
/// Match the call arguments (as described by the given argument type) to
55405595
/// the parameters (as described by the given parameter type).
55415596
///

0 commit comments

Comments
 (0)