Skip to content

Commit 6488548

Browse files
committed
[CodeCompletion] Allow references to top-level functions with error parameters
During normal type-checking we ignore functions that contain an error. During code completion, we want to consider them and replace all error types by placeholders so we can match up the known types. We already do this for member types (see `getTypeOfMemberReference`). We should also do it for top-level functions. Fixes rdar://81425383 [SR-14992] # Conflicts: # test/IDE/complete_call_arg.swift
1 parent 882edde commit 6488548

File tree

3 files changed

+54
-33
lines changed

3 files changed

+54
-33
lines changed

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,11 @@ namespace {
13461346

13471347
// If declaration is invalid, let's turn it into a potential hole
13481348
// and keep generating constraints.
1349-
if (!knownType && E->getDecl()->isInvalid()) {
1349+
// For code completion, we still resolve the overload and replace error
1350+
// types inside the function decl with placeholders
1351+
// (in getTypeOfReference) so we can match non-error param types.
1352+
if (!knownType && E->getDecl()->isInvalid() &&
1353+
!CS.isForCodeCompletion()) {
13501354
auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole);
13511355
(void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator));
13521356
CS.setType(E, hole);

lib/Sema/ConstraintSystem.cpp

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,38 @@ AnyFunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
13971397
fnType, decl, dc, numApplies, isMainDispatchQueue, GetClosureType{*this});
13981398
}
13991399

1400+
/// For every parameter in \p type that has an error type, replace that
1401+
/// parameter's type by a placeholder type, where \p value is the declaration
1402+
/// that declared \p type. This is useful for code completion so we can match
1403+
/// the types we do know instead of bailing out completely because \p type
1404+
/// contains an error type.
1405+
static Type replaceParamErrorTypeByPlaceholder(Type type, ValueDecl *value) {
1406+
if (!type->is<AnyFunctionType>() || !isa<AbstractFunctionDecl>(value)) {
1407+
return type;
1408+
}
1409+
auto funcType = type->castTo<AnyFunctionType>();
1410+
auto funcDecl = cast<AbstractFunctionDecl>(value);
1411+
1412+
auto declParams = funcDecl->getParameters();
1413+
auto typeParams = funcType->getParams();
1414+
assert(declParams->size() == typeParams.size());
1415+
SmallVector<AnyFunctionType::Param, 4> newParams;
1416+
newParams.reserve(declParams->size());
1417+
for (auto i : indices(typeParams)) {
1418+
AnyFunctionType::Param param = typeParams[i];
1419+
if (param.getPlainType()->is<ErrorType>()) {
1420+
auto paramDecl = declParams->get(i);
1421+
auto placeholder =
1422+
PlaceholderType::get(paramDecl->getASTContext(), paramDecl);
1423+
newParams.push_back(param.withType(placeholder));
1424+
} else {
1425+
newParams.push_back(param);
1426+
}
1427+
}
1428+
assert(newParams.size() == declParams->size());
1429+
return FunctionType::get(newParams, funcType->getResult());
1430+
}
1431+
14001432
std::pair<Type, Type>
14011433
ConstraintSystem::getTypeOfReference(ValueDecl *value,
14021434
FunctionRefKind functionRefKind,
@@ -1458,6 +1490,12 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
14581490
openedType->getAs<FunctionType>(),
14591491
locator);
14601492

1493+
if (isForCodeCompletion() && openedType->hasError()) {
1494+
// In code completion, replace error types by placeholder types so we can
1495+
// match the types we know instead of bailing out completely.
1496+
openedType = replaceParamErrorTypeByPlaceholder(openedType, value);
1497+
}
1498+
14611499
// If we opened up any type variables, record the replacements.
14621500
recordOpenedTypes(locator, replacements);
14631501

@@ -1950,38 +1988,6 @@ Type constraints::typeEraseOpenedExistentialReference(
19501988
});
19511989
}
19521990

1953-
/// For every parameter in \p type that has an error type, replace that
1954-
/// parameter's type by a placeholder type, where \p value is the declaration
1955-
/// that declared \p type. This is useful for code completion so we can match
1956-
/// the types we do know instead of bailing out completely because \p type
1957-
/// contains an error type.
1958-
static Type replaceParamErrorTypeByPlaceholder(Type type, ValueDecl *value) {
1959-
if (!type->is<AnyFunctionType>() || !isa<AbstractFunctionDecl>(value)) {
1960-
return type;
1961-
}
1962-
auto funcType = type->castTo<AnyFunctionType>();
1963-
auto funcDecl = cast<AbstractFunctionDecl>(value);
1964-
1965-
auto declParams = funcDecl->getParameters();
1966-
auto typeParams = funcType->getParams();
1967-
assert(declParams->size() == typeParams.size());
1968-
SmallVector<AnyFunctionType::Param, 4> newParams;
1969-
newParams.reserve(declParams->size());
1970-
for (auto i : indices(typeParams)) {
1971-
AnyFunctionType::Param param = typeParams[i];
1972-
if (param.getPlainType()->is<ErrorType>()) {
1973-
auto paramDecl = declParams->get(i);
1974-
auto placeholder =
1975-
PlaceholderType::get(paramDecl->getASTContext(), paramDecl);
1976-
newParams.push_back(param.withType(placeholder));
1977-
} else {
1978-
newParams.push_back(param);
1979-
}
1980-
}
1981-
assert(newParams.size() == declParams->size());
1982-
return FunctionType::get(newParams, funcType->getResult());
1983-
}
1984-
19851991
std::pair<Type, Type>
19861992
ConstraintSystem::getTypeOfMemberReference(
19871993
Type baseTy, ValueDecl *value, DeclContext *useDC,

test/IDE/complete_call_arg.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,3 +1371,14 @@ func testDynamicMemberSubscriptLookup() {
13711371
// DYNAMIC_MEMBER_SUBSCRIPT_LOOKUP-DAG: Decl[LocalVar]/Local/TypeRelation[Identical]: index[#Int#]; name=index
13721372
// DYNAMIC_MEMBER_SUBSCRIPT_LOOKUP-DAG: Pattern/CurrNominal/Flair[ArgLabels]: ['[']{#keyPath: KeyPath<Binding<MyStruct>, Value>#}[']'][#Value#]; name=keyPath:
13731373
// DYNAMIC_MEMBER_SUBSCRIPT_LOOKUP: End completions
1374+
1375+
func testTopLevelFuncWithErrorParam() {
1376+
enum A { case a }
1377+
func foo(x: A, b: Undefined) {}
1378+
1379+
foo(x: .#^TOP_LEVEL_FUNC_WITH_ERROR_PARAM^#)
1380+
// TOP_LEVEL_FUNC_WITH_ERROR_PARAM: Begin completions, 2 items
1381+
// TOP_LEVEL_FUNC_WITH_ERROR_PARAM-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: a[#A#]; name=a
1382+
// TOP_LEVEL_FUNC_WITH_ERROR_PARAM-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): A#})[#(into: inout Hasher) -> Void#]; name=hash(:)
1383+
// TOP_LEVEL_FUNC_WITH_ERROR_PARAM: End completions
1384+
}

0 commit comments

Comments
 (0)