Skip to content

Commit 622d0b2

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents 8c1e33a + a3bb205 commit 622d0b2

13 files changed

+421
-221
lines changed

include/swift/AST/ASTNode.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,19 @@ namespace llvm {
107107
return LHS.getOpaqueValue() == RHS.getOpaqueValue();
108108
}
109109
};
110+
111+
// A ASTNode is "pointer like".
112+
template <>
113+
struct PointerLikeTypeTraits<ASTNode> {
114+
public:
115+
static inline void *getAsVoidPointer(ASTNode N) {
116+
return (void *)N.getOpaqueValue();
117+
}
118+
static inline ASTNode getFromVoidPointer(void *P) {
119+
return ASTNode::getFromOpaqueValue(P);
120+
}
121+
enum { NumLowBitsAvailable = swift::TypeAlignInBits };
122+
};
110123
}
111124

112125
#endif // LLVM_SWIFT_AST_AST_NODE_H

include/swift/IDE/ArgumentCompletion.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
2525
struct Result {
2626
/// The type associated with the code completion expression itself.
2727
Type ExpectedType;
28+
/// The expected return type of the function call.
29+
Type ExpectedCallType;
2830
/// True if this is a subscript rather than a function call.
2931
bool IsSubscript;
3032
/// The FuncDecl or SubscriptDecl associated with the call.
@@ -70,6 +72,11 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
7072

7173
void sawSolutionImpl(const constraints::Solution &solution) override;
7274

75+
/// Populates \p ShadowedDecls with all \c FuncD in \p Results that are
76+
/// defined in protocol extensions but redeclared on a nominal type and thus
77+
/// cannot be accessed
78+
void computeShadowedDecls(SmallPtrSetImpl<ValueDecl *> &ShadowedDecls);
79+
7380
public:
7481
ArgumentTypeCheckCompletionCallback(CodeCompletionExpr *CompletionExpr,
7582
DeclContext *DC)

lib/IDE/ArgumentCompletion.cpp

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ using namespace swift::constraints;
2424
bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
2525
const ArgumentTypeCheckCompletionCallback::Result &Res,
2626
SmallVectorImpl<PossibleParamInfo> &Params, SmallVectorImpl<Type> &Types) {
27-
if (!Res.ParamIdx) {
27+
if (!Res.ParamIdx || !Res.FuncTy) {
2828
// We don't really know much here. Suggest global results without a specific
2929
// expected type.
3030
return true;
@@ -78,6 +78,44 @@ bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
7878
return ShowGlobalCompletions;
7979
}
8080

81+
/// Applies heuristic to determine whether the result type of \p E is
82+
/// unconstrained, that is if the constraint system is satisfiable for any
83+
/// result type of \p E.
84+
static bool isExpressionResultTypeUnconstrained(const Solution &S, Expr *E) {
85+
ConstraintSystem &CS = S.getConstraintSystem();
86+
if (auto ParentExpr = CS.getParentExpr(E)) {
87+
if (auto Assign = dyn_cast<AssignExpr>(ParentExpr)) {
88+
if (isa<DiscardAssignmentExpr>(Assign->getDest())) {
89+
// _ = <expr> is unconstrained
90+
return true;
91+
}
92+
} else if (isa<RebindSelfInConstructorExpr>(ParentExpr)) {
93+
// super.init() is unconstrained (it always produces the correct result
94+
// by definition)
95+
return true;
96+
}
97+
}
98+
auto targetIt = S.solutionApplicationTargets.find(E);
99+
if (targetIt == S.solutionApplicationTargets.end()) {
100+
return false;
101+
}
102+
auto target = targetIt->second;
103+
assert(target.kind == SolutionApplicationTarget::Kind::expression);
104+
switch (target.getExprContextualTypePurpose()) {
105+
case CTP_Unused:
106+
// If we aren't using the contextual type, its unconstrained by definition.
107+
return true;
108+
case CTP_Initialization: {
109+
// let x = <expr> is unconstrained
110+
auto contextualType = target.getExprContextualType();
111+
return !contextualType || contextualType->is<UnresolvedType>();
112+
}
113+
default:
114+
// Assume that it's constrained by default.
115+
return false;
116+
}
117+
}
118+
81119
void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
82120
Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);
83121

@@ -111,10 +149,25 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
111149
}
112150
auto ArgIdx = ArgInfo->completionIdx;
113151

152+
Type ExpectedCallType;
153+
if (!isExpressionResultTypeUnconstrained(S, ParentCall)) {
154+
ExpectedCallType = getTypeForCompletion(S, ParentCall);
155+
}
156+
114157
auto *CallLocator = CS.getConstraintLocator(ParentCall);
115158
auto *CalleeLocator = S.getCalleeLocator(CallLocator);
116159

117160
auto Info = getSelectedOverloadInfo(S, CalleeLocator);
161+
if (Info.Value && Info.Value->shouldHideFromEditor()) {
162+
return;
163+
}
164+
// Disallow invalid initializer references
165+
for (auto Fix : S.Fixes) {
166+
if (Fix->getLocator() == CalleeLocator &&
167+
Fix->getKind() == FixKind::AllowInvalidInitRef) {
168+
return;
169+
}
170+
}
118171

119172
// Find the parameter the completion was bound to (if any), as well as which
120173
// parameters are already bound (so we don't suggest them even when the args
@@ -179,10 +232,39 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
179232
if (Info.ValueTy) {
180233
FuncTy = Info.ValueTy->lookThroughAllOptionalTypes()->getAs<AnyFunctionType>();
181234
}
182-
Results.push_back({ExpectedTy, isa<SubscriptExpr>(ParentCall), Info.Value,
183-
FuncTy, ArgIdx, ParamIdx, std::move(ClaimedParams),
184-
IsNoninitialVariadic, Info.BaseTy, HasLabel, IsAsync,
185-
SolutionSpecificVarTypes});
235+
Results.push_back({ExpectedTy, ExpectedCallType,
236+
isa<SubscriptExpr>(ParentCall), Info.Value, FuncTy, ArgIdx,
237+
ParamIdx, std::move(ClaimedParams), IsNoninitialVariadic,
238+
Info.BaseTy, HasLabel, IsAsync, SolutionSpecificVarTypes});
239+
}
240+
241+
void ArgumentTypeCheckCompletionCallback::computeShadowedDecls(
242+
SmallPtrSetImpl<ValueDecl *> &ShadowedDecls) {
243+
for (size_t i = 0; i < Results.size(); ++i) {
244+
auto &ResultA = Results[i];
245+
for (size_t j = i + 1; j < Results.size(); ++j) {
246+
auto &ResultB = Results[j];
247+
if (!ResultA.FuncD || !ResultB.FuncD || !ResultA.FuncTy || !ResultB.FuncTy) {
248+
continue;
249+
}
250+
if (ResultA.FuncD->getName() != ResultB.FuncD->getName()) {
251+
continue;
252+
}
253+
if (!ResultA.FuncTy->isEqual(ResultB.FuncTy)) {
254+
continue;
255+
}
256+
ProtocolDecl *inProtocolExtensionA =
257+
ResultA.FuncD->getDeclContext()->getExtendedProtocolDecl();
258+
ProtocolDecl *inProtocolExtensionB =
259+
ResultB.FuncD->getDeclContext()->getExtendedProtocolDecl();
260+
261+
if (inProtocolExtensionA && !inProtocolExtensionB) {
262+
ShadowedDecls.insert(ResultA.FuncD);
263+
} else if (!inProtocolExtensionA && inProtocolExtensionB) {
264+
ShadowedDecls.insert(ResultB.FuncD);
265+
}
266+
}
267+
}
186268
}
187269

188270
void ArgumentTypeCheckCompletionCallback::deliverResults(
@@ -193,12 +275,23 @@ void ArgumentTypeCheckCompletionCallback::deliverResults(
193275
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
194276
&CompletionCtx);
195277

278+
SmallPtrSet<ValueDecl *, 4> ShadowedDecls;
279+
computeShadowedDecls(ShadowedDecls);
280+
196281
// Perform global completion as a fallback if we don't have any results.
197282
bool shouldPerformGlobalCompletion = Results.empty();
283+
SmallVector<Type, 4> ExpectedCallTypes;
284+
for (auto &Result : Results) {
285+
ExpectedCallTypes.push_back(Result.ExpectedCallType);
286+
}
287+
198288
SmallVector<Type, 8> ExpectedTypes;
199289

200290
if (IncludeSignature && !Results.empty()) {
201291
Lookup.setHaveLParen(true);
292+
Lookup.setExpectedTypes(ExpectedCallTypes,
293+
/*isImplicitSingleExpressionReturn=*/false);
294+
202295
for (auto &Result : Results) {
203296
auto SemanticContext = SemanticContextKind::None;
204297
NominalTypeDecl *BaseNominal = nullptr;
@@ -229,13 +322,17 @@ void ArgumentTypeCheckCompletionCallback::deliverResults(
229322
}
230323
if (Result.FuncTy) {
231324
if (auto FuncTy = Result.FuncTy) {
232-
if (Result.IsSubscript) {
233-
assert(SemanticContext != SemanticContextKind::None);
234-
auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.FuncD);
235-
Lookup.addSubscriptCallPattern(FuncTy, SD, SemanticContext);
236-
} else {
237-
auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(Result.FuncD);
238-
Lookup.addFunctionCallPattern(FuncTy, FD, SemanticContext);
325+
if (ShadowedDecls.count(Result.FuncD) == 0) {
326+
// Don't show call pattern completions if the function is
327+
// overridden.
328+
if (Result.IsSubscript) {
329+
assert(SemanticContext != SemanticContextKind::None);
330+
auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.FuncD);
331+
Lookup.addSubscriptCallPattern(FuncTy, SD, SemanticContext);
332+
} else {
333+
auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(Result.FuncD);
334+
Lookup.addFunctionCallPattern(FuncTy, FD, SemanticContext);
335+
}
239336
}
240337
}
241338
}

lib/IDE/CodeCompletion.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,8 +1441,12 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
14411441
// switch case where there control expression is invalid). Having normal
14421442
// typechecking still resolve even these cases would be beneficial for
14431443
// tooling in general though.
1444-
if (!Lookup.gotCallback())
1444+
if (!Lookup.gotCallback()) {
1445+
if (Context.TypeCheckerOpts.DebugConstraintSolver) {
1446+
llvm::errs() << "--- Fallback typecheck for code completion ---\n";
1447+
}
14451448
Lookup.fallbackTypeCheck(CurDeclContext);
1449+
}
14461450
};
14471451

14481452
switch (Kind) {

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9179,12 +9179,17 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
91799179

91809180
// Only try and favor monomorphic unary initializers.
91819181
if (!ctor->isGenericContext()) {
9182-
auto args = ctor->getMethodInterfaceType()
9183-
->castTo<FunctionType>()->getParams();
9184-
if (args.size() == 1 && !args[0].hasLabel() &&
9185-
args[0].getPlainType()->isEqual(favoredType)) {
9186-
if (!isDeclUnavailable(decl, memberLocator))
9187-
result.FavoredChoice = result.ViableCandidates.size();
9182+
if (!ctor->getMethodInterfaceType()->hasError()) {
9183+
// The constructor might have an error type because we don't skip
9184+
// invalid decls for code completion
9185+
auto args = ctor->getMethodInterfaceType()
9186+
->castTo<FunctionType>()
9187+
->getParams();
9188+
if (args.size() == 1 && !args[0].hasLabel() &&
9189+
args[0].getPlainType()->isEqual(favoredType)) {
9190+
if (!isDeclUnavailable(decl, memberLocator))
9191+
result.FavoredChoice = result.ViableCandidates.size();
9192+
}
91889193
}
91899194
}
91909195
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,30 +1526,35 @@ AnyFunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
15261526
/// that declared \p type. This is useful for code completion so we can match
15271527
/// the types we do know instead of bailing out completely because \p type
15281528
/// contains an error type.
1529-
static Type replaceParamErrorTypeByPlaceholder(Type type, ValueDecl *value) {
1529+
static Type replaceParamErrorTypeByPlaceholder(Type type, ValueDecl *value, bool hasAppliedSelf) {
15301530
if (!type->is<AnyFunctionType>() || !isa<AbstractFunctionDecl>(value)) {
15311531
return type;
15321532
}
15331533
auto funcType = type->castTo<AnyFunctionType>();
15341534
auto funcDecl = cast<AbstractFunctionDecl>(value);
15351535

1536-
auto declParams = funcDecl->getParameters();
1536+
SmallVector<ParamDecl *> declParams;
1537+
if (hasAppliedSelf) {
1538+
declParams.append(funcDecl->getParameters()->begin(), funcDecl->getParameters()->end());
1539+
} else {
1540+
declParams.push_back(funcDecl->getImplicitSelfDecl());
1541+
}
15371542
auto typeParams = funcType->getParams();
1538-
assert(declParams->size() == typeParams.size());
1543+
assert(declParams.size() == typeParams.size());
15391544
SmallVector<AnyFunctionType::Param, 4> newParams;
1540-
newParams.reserve(declParams->size());
1545+
newParams.reserve(declParams.size());
15411546
for (auto i : indices(typeParams)) {
15421547
AnyFunctionType::Param param = typeParams[i];
15431548
if (param.getPlainType()->is<ErrorType>()) {
1544-
auto paramDecl = declParams->get(i);
1549+
auto paramDecl = declParams[i];
15451550
auto placeholder =
15461551
PlaceholderType::get(paramDecl->getASTContext(), paramDecl);
15471552
newParams.push_back(param.withType(placeholder));
15481553
} else {
15491554
newParams.push_back(param);
15501555
}
15511556
}
1552-
assert(newParams.size() == declParams->size());
1557+
assert(newParams.size() == declParams.size());
15531558
return FunctionType::get(newParams, funcType->getResult());
15541559
}
15551560

@@ -1620,7 +1625,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
16201625
if (isForCodeCompletion() && openedType->hasError()) {
16211626
// In code completion, replace error types by placeholder types so we can
16221627
// match the types we know instead of bailing out completely.
1623-
openedType = replaceParamErrorTypeByPlaceholder(openedType, value);
1628+
openedType = replaceParamErrorTypeByPlaceholder(openedType, value, /*hasAppliedSelf=*/true);
16241629
}
16251630

16261631
// If we opened up any type variables, record the replacements.
@@ -2288,7 +2293,7 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
22882293
if (isForCodeCompletion() && type->hasError()) {
22892294
// In code completion, replace error types by placeholder types so we can
22902295
// match the types we know instead of bailing out completely.
2291-
type = replaceParamErrorTypeByPlaceholder(type, value);
2296+
type = replaceParamErrorTypeByPlaceholder(type, value, hasAppliedSelf);
22922297
}
22932298

22942299
return type;

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ bool TypeChecker::typeCheckForCodeCompletion(
624624

625625
// If solve failed to generate constraints or with some other
626626
// issue, we need to fallback to type-checking a sub-expression.
627+
cs.setSolutionApplicationTarget(target.getAsExpr(), target);
627628
if (!cs.solveForCodeCompletion(target, solutions))
628629
return CompletionResult::Fallback;
629630

test/IDE/complete_call_arg.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ private extension Sequence {
12311231
func SubstitutableBaseTyOfSubscript<T: Comparable>(by keyPath: KeyPath<Element, T>) -> [Element] {
12321232
return sorted { a, b in a[#^GENERICBASE_SUB^#] }
12331233
// GENERICBASE_SUB: Begin completions, 1 item
1234-
// GENERICBASE_SUB: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<Self.Element, Value>#}[']'][#Value#];
1234+
// GENERICBASE_SUB: Pattern/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['[']{#keyPath: KeyPath<Self.Element, Value>#}[']'][#Value#];
12351235
// GENERICBASE_SUB: End completions
12361236
}
12371237
}

test/IDE/complete_expr_after_paren.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=INITIALIZER | %FileCheck %s --check-prefix=INITIALIZER
2-
// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=METHOD | %FileCheck %s --check-prefix=METHOD
3-
// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=AVAILABILITY | %FileCheck %s --check-prefix=AVAILABILITY
4-
// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC | %FileCheck %s --check-prefix=STATIC
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
53

64
protocol MyProtocol {
75
init(init1: Int)
@@ -89,3 +87,33 @@ func testStaticFunc() {
8987
// STATIC-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#(self): TestStatic#}[')'][#() -> Void#];
9088
// STATIC: End completions
9189
}
90+
91+
protocol TestShadowedProtocol {}
92+
93+
extension TestShadowedProtocol {
94+
func argOverloaded(arg: String) {}
95+
func argOverloaded(arg: Int) {}
96+
97+
func returnTypeOverloaded() -> String {}
98+
func returnTypeOverloaded() -> Int {}
99+
}
100+
101+
struct TestShadowedStruct: TestShadowedProtocol {
102+
func argOverloaded(arg: String) {}
103+
104+
func returnTypeOverloaded() -> String {}
105+
106+
func test() {
107+
self.argOverloaded(#^ARG_OVERLOADED^#)
108+
// ARG_OVERLOADED: Begin completions, 2 items
109+
// ARG_OVERLOADED-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: String#}[')'][#Void#]; name=arg:
110+
// ARG_OVERLOADED-DAG: Decl[InstanceMethod]/Super/Flair[ArgLabels]: ['(']{#arg: Int#}[')'][#Void#]; name=arg:
111+
// ARG_OVERLOADED: End completions
112+
113+
self.returnTypeOverloaded(#^RETURN_OVERLOADED^#)
114+
// RETURN_OVERLOADED: Begin completions, 2 items
115+
// RETURN_OVERLOADED-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['('][')'][#String#]; name=
116+
// RETURN_OVERLOADED-DAG: Decl[InstanceMethod]/Super/Flair[ArgLabels]: ['('][')'][#Int#]; name=
117+
// RETURN_OVERLOADED: End completions
118+
}
119+
}

test/IDE/complete_subscript.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func testSubcscriptTuple(val: (x: Int, String)) {
162162
}
163163

164164
struct HasSettableSub {
165-
subscript(a: String) -> Any {
165+
subscript(a: String) -> Int {
166166
get { return 1 }
167167
set { }
168168
}
@@ -174,6 +174,6 @@ func testSettableSub(x: inout HasSettableSub) {
174174
}
175175
// SETTABLE_SUBSCRIPT: Begin completions
176176
// SETTABLE_SUBSCRIPT-DAG: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<HasSettableSub, Value>#}[']'][#Value#];
177-
// SETTABLE_SUBSCRIPT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]: ['[']{#(a): String#}[']'][#@lvalue Any#];
177+
// SETTABLE_SUBSCRIPT-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['[']{#(a): String#}[']'][#@lvalue Int#];
178178
// SETTABLE_SUBSCRIPT-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: local[#String#]; name=local
179179
// SETTABLE_SUBSCRIPT: End completions

0 commit comments

Comments
 (0)