Skip to content

Commit f249498

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 86813c7 commit f249498

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();
@@ -1917,13 +1917,23 @@ static Type replacePlaceholderType(PlaceholderType *placeholder,
19171917

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

1926-
Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
1935+
Type Solution::simplifyType(Type type, bool wantInterfaceType,
1936+
bool forCompletion) const {
19271937
// If we've been asked for an interface type, start by mapping any archetypes
19281938
// out of context.
19291939
if (wantInterfaceType)
@@ -1963,7 +1973,7 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
19631973
auto *typePtr = type.getPointer();
19641974

19651975
if (auto *placeholder = dyn_cast<PlaceholderType>(typePtr))
1966-
return replacePlaceholderType(placeholder, *this);
1976+
return replacePlaceholderType(placeholder, *this, forCompletion);
19671977

19681978
if (isa<TypeVariableType>(typePtr))
19691979
return ErrorType::get(ctx);
@@ -1977,136 +1987,8 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
19771987
}
19781988

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

21121994
template <typename T>

0 commit comments

Comments
 (0)