Skip to content

Commit 9e4208b

Browse files
committed
[CS] Remove custom logic from simplifyTypeForCodeCompletion
We ought to be able to just use `simplifyType` with an additional parameter to tell it to produce archetypes.
1 parent 669a2ce commit 9e4208b

File tree

2 files changed

+20
-134
lines changed

2 files changed

+20
-134
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,11 @@ class Solution {
16771677
/// \param wantInterfaceType If true, maps the resulting type out of context,
16781678
/// and replaces type variables for opened generic parameters with the
16791679
/// generic parameter types. Should only be used for diagnostic logic.
1680-
Type simplifyType(Type type, bool wantInterfaceType = false) const;
1680+
/// \param forCompletion If true, will produce archetypes instead of
1681+
/// ErrorTypes for generic parameter originators, which is what completion
1682+
/// currently expects for the code completion token.
1683+
Type simplifyType(Type type, bool wantInterfaceType = false,
1684+
bool forCompletion = false) const;
16811685

16821686
// To aid code completion, we need to attempt to convert type placeholders
16831687
// back into underlying generic parameters if possible, since type

lib/Sema/ConstraintSystem.cpp

Lines changed: 15 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,7 +1892,7 @@ getGenericParamForHoleTypeVar(TypeVariableType *tv, const Solution &S) {
18921892
}
18931893

18941894
static Type replacePlaceholderType(PlaceholderType *placeholder,
1895-
const Solution &S) {
1895+
const Solution &S, bool forCompletion) {
18961896
auto &ctx = S.getConstraintSystem().getASTContext();
18971897
auto origTy = [&]() -> Type {
18981898
auto orig = placeholder->getOriginator();
@@ -1920,13 +1920,23 @@ static Type replacePlaceholderType(PlaceholderType *placeholder,
19201920
if (isa<TypeVariableType>(replacement.getPointer()))
19211921
return ErrorType::get(ctx);
19221922

1923+
// For completion, we want to produce an archetype instead of an ErrorType
1924+
// for a top-level generic parameter.
1925+
// FIXME: This is pretty weird, we're producing a contextual type outside of
1926+
// the context it exists in. We ought to see if we can make the completion
1927+
// logic work with ErrorTypes instead.
1928+
if (forCompletion) {
1929+
if (auto *GP = replacement->getAs<GenericTypeParamType>())
1930+
return GP->getDecl()->getInnermostDeclContext()->mapTypeIntoContext(GP);
1931+
}
19231932
// Return an ErrorType with the replacement as the original type. Note that
19241933
// if we failed to replace a type variable with a generic parameter in a
19251934
// dependent member, `ErrorType::get` will fold it away.
19261935
return ErrorType::get(replacement);
19271936
}
19281937

1929-
Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
1938+
Type Solution::simplifyType(Type type, bool wantInterfaceType,
1939+
bool forCompletion) const {
19301940
// If we've been asked for an interface type, start by mapping any archetypes
19311941
// out of context.
19321942
if (wantInterfaceType)
@@ -1966,7 +1976,7 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
19661976
auto *typePtr = type.getPointer();
19671977

19681978
if (auto *placeholder = dyn_cast<PlaceholderType>(typePtr))
1969-
return replacePlaceholderType(placeholder, *this);
1979+
return replacePlaceholderType(placeholder, *this, forCompletion);
19701980

19711981
if (isa<TypeVariableType>(typePtr))
19721982
return ErrorType::get(ctx);
@@ -1980,136 +1990,8 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
19801990
}
19811991

19821992
Type Solution::simplifyTypeForCodeCompletion(Type Ty) const {
1983-
auto &CS = getConstraintSystem();
1984-
1985-
// First, instantiate all type variables that we know, but don't replace
1986-
// placeholders by unresolved types.
1987-
Ty = CS.simplifyTypeImpl(Ty, [this](TypeVariableType *typeVar) -> Type {
1988-
return getFixedType(typeVar);
1989-
});
1990-
1991-
// Next, replace all placeholders by type variables. We know that all type
1992-
// variables now in the type originate from placeholders.
1993-
Ty = Ty.transformRec([](Type type) -> std::optional<Type> {
1994-
if (auto *placeholder = type->getAs<PlaceholderType>()) {
1995-
if (auto *typeVar =
1996-
placeholder->getOriginator().dyn_cast<TypeVariableType *>()) {
1997-
return Type(typeVar);
1998-
}
1999-
}
2000-
2001-
return std::nullopt;
2002-
});
2003-
2004-
// Replace all type variables (which must come from placeholders) by their
2005-
// generic parameters. Because we call into simplifyTypeImpl
2006-
Ty = CS.simplifyTypeImpl(Ty, [&CS, this](TypeVariableType *typeVar) -> Type {
2007-
// Code completion depends on generic parameter type being represented in
2008-
// terms of `ArchetypeType` since it's easy to extract protocol requirements
2009-
// from it.
2010-
auto getTypeVarAsArchetype = [](TypeVariableType *typeVar) -> Type {
2011-
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
2012-
if (auto *GPD = GP->getDecl()) {
2013-
return GPD->getInnermostDeclContext()->mapTypeIntoContext(GP);
2014-
}
2015-
}
2016-
return Type();
2017-
};
2018-
2019-
if (auto archetype = getTypeVarAsArchetype(typeVar)) {
2020-
return archetype;
2021-
}
2022-
2023-
// Sometimes the type variable itself doesn't have have an originator that
2024-
// can be replaced by an archetype but one of its equivalent type variable
2025-
// does.
2026-
// Search thorough all equivalent type variables, looking for one that can
2027-
// be replaced by a generic parameter.
2028-
std::vector<std::pair<TypeVariableType *, Type>> bindings(
2029-
typeBindings.begin(), typeBindings.end());
2030-
// Make sure we iterate the bindings in a deterministic order.
2031-
llvm::sort(bindings, [](const std::pair<TypeVariableType *, Type> &lhs,
2032-
const std::pair<TypeVariableType *, Type> &rhs) {
2033-
return lhs.first->getID() < rhs.first->getID();
2034-
});
2035-
for (auto binding : bindings) {
2036-
if (auto placeholder = binding.second->getAs<PlaceholderType>()) {
2037-
if (placeholder->getOriginator().dyn_cast<TypeVariableType *>() ==
2038-
typeVar) {
2039-
if (auto archetype = getTypeVarAsArchetype(binding.first)) {
2040-
return archetype;
2041-
}
2042-
}
2043-
}
2044-
}
2045-
2046-
// When applying the logic below to get contextual types inside result
2047-
// builders, the code completion type variable is connected by a one-way
2048-
// constraint to a type variable in the buildBlock call, but that is not the
2049-
// type variable that represents the argument type. We need to find the type
2050-
// variable representing the argument to retrieve protocol requirements from
2051-
// it. Look for a ArgumentConversion constraint that allows us to retrieve
2052-
// the argument type var.
2053-
auto &cg = CS.getConstraintGraph();
2054-
2055-
// FIXME: The type variable is not going to be part of the constraint graph
2056-
// at this point unless it was created at the outermost decision level;
2057-
// otherwise it has already been rolled back! Work around this by creating
2058-
// an empty node if one doesn't exist.
2059-
cg.addTypeVariable(typeVar);
2060-
2061-
for (auto argConstraint : cg[typeVar].getConstraints()) {
2062-
if (argConstraint->getKind() == ConstraintKind::ArgumentConversion &&
2063-
argConstraint->getFirstType()->getRValueType()->isEqual(typeVar)) {
2064-
if (auto argTV =
2065-
argConstraint->getSecondType()->getAs<TypeVariableType>()) {
2066-
if (auto archetype = getTypeVarAsArchetype(argTV)) {
2067-
return archetype;
2068-
}
2069-
}
2070-
}
2071-
}
2072-
2073-
return typeVar;
2074-
});
2075-
2076-
// Logic to determine the contextual type inside buildBlock result builders:
2077-
//
2078-
// When completing inside a result builder, the result builder
2079-
// @ViewBuilder var body: some View {
2080-
// Text("Foo")
2081-
// #^COMPLETE^#
2082-
// }
2083-
// gets rewritten to
2084-
// @ViewBuilder var body: some View {
2085-
// let $__builder2: Text
2086-
// let $__builder0 = Text("Foo")
2087-
// let $__builder1 = #^COMPLETE^#
2088-
// $__builder2 = ViewBuilder.buildBlock($__builder0, $__builder1)
2089-
// return $__builder2
2090-
// }
2091-
// Inside the constraint system
2092-
// let $__builder1 = #^COMPLETE^#
2093-
// gets type checked without context, so we can't know the contextual type for
2094-
// the code completion token. But we know that $__builder1 (and thus the type
2095-
// of #^COMPLETE^#) is used as the second argument to ViewBuilder.buildBlock,
2096-
// so we can extract the contextual type from that call. To do this, figure
2097-
// out the type variable that is used for $__builder1 in the buildBlock call.
2098-
// This type variable is connected to the type variable of $__builder1's
2099-
// definition by a one-way constraint.
2100-
if (auto TV = Ty->getAs<TypeVariableType>()) {
2101-
for (auto constraint : CS.getConstraintGraph()[TV].getConstraints()) {
2102-
if (constraint->getKind() == ConstraintKind::OneWayEqual &&
2103-
constraint->getSecondType()->isEqual(TV)) {
2104-
return simplifyTypeForCodeCompletion(constraint->getFirstType());
2105-
}
2106-
}
2107-
}
2108-
2109-
// Remove any remaining type variables and placeholders
2110-
Ty = simplifyType(Ty);
2111-
2112-
return Ty->getRValueType();
1993+
return simplifyType(Ty, /*wantInterfaceType*/ false, /*forCompletion*/ true)
1994+
->getRValueType();
21131995
}
21141996

21151997
template <typename T>

0 commit comments

Comments
 (0)