[CodeCompletion] Support a narrow case for producing trailing closures directly

This adds a narrow special case in code-completion for control-flow-like
methods such as DispatchQueue().sync that are () -> (), to add a new
completion where the trailing closure is immediately expanded rather
than having to invoke placeholder expansion as a second step.

rdar://problem/26628804
This commit is contained in:
Ben Langmuir
2016-07-01 13:53:57 -07:00
parent 20939dd9d0
commit c8f7da4de1
8 changed files with 268 additions and 135 deletions

View File

@@ -72,94 +72,6 @@ static Optional<unsigned> scoreParamAndArgNameTypo(StringRef paramName,
return dist;
}
SmallVector<CallArgParam, 4> constraints::decomposeArgType(Type type) {
return decomposeParamType(type, nullptr, /*level=*/0);
}
SmallVector<CallArgParam, 4>
constraints::decomposeParamType(Type type, ValueDecl *paramOwner,
unsigned level) {
// Find the corresponding parameter list.
ParameterList *paramList = nullptr;
if (paramOwner) {
if (auto func = dyn_cast<AbstractFunctionDecl>(paramOwner)) {
if (level < func->getNumParameterLists())
paramList = func->getParameterList(level);
} else if (auto subscript = dyn_cast<SubscriptDecl>(paramOwner)) {
if (level == 1)
paramList = subscript->getIndices();
}
}
SmallVector<CallArgParam, 4> result;
switch (type->getKind()) {
case TypeKind::Tuple: {
auto tupleTy = cast<TupleType>(type.getPointer());
// FIXME: In the weird case where we have a tuple type that should
// be wrapped in a ParenType but isn't, just... forget it happened.
if (paramList && tupleTy->getNumElements() != paramList->size() &&
paramList->size() == 1)
paramList = nullptr;
for (auto i : range(0, tupleTy->getNumElements())) {
const auto &elt = tupleTy->getElement(i);
CallArgParam argParam;
argParam.Ty = elt.isVararg() ? elt.getVarargBaseTy() : elt.getType();
argParam.Label = elt.getName();
argParam.HasDefaultArgument =
paramList && paramList->get(i)->isDefaultArgument();
argParam.Variadic = elt.isVararg();
result.push_back(argParam);
}
break;
}
case TypeKind::Paren: {
CallArgParam argParam;
argParam.Ty = cast<ParenType>(type.getPointer())->getUnderlyingType();
argParam.HasDefaultArgument =
paramList && paramList->get(0)->isDefaultArgument();
result.push_back(argParam);
break;
}
default: {
CallArgParam argParam;
argParam.Ty = type;
result.push_back(argParam);
break;
}
}
return result;
}
/// Turn a param list into a symbolic and printable representation that does not
/// include the types, something like (_:, b:, c:)
std::string constraints::getParamListAsString(ArrayRef<CallArgParam> params){
std::string result = "(";
bool isFirst = true;
for (auto &param : params) {
if (isFirst)
isFirst = false;
else
result += ", ";
if (param.hasLabel())
result += param.Label.str();
else
result += "_";
result += ":";
}
result += ')';
return result;
}
bool constraints::
areConservativelyCompatibleArgumentLabels(ValueDecl *decl,
unsigned parameterDepth,