mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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.
This commit is contained in:
@@ -1892,7 +1892,7 @@ getGenericParamForHoleTypeVar(TypeVariableType *tv, const Solution &S) {
|
||||
}
|
||||
|
||||
static Type replacePlaceholderType(PlaceholderType *placeholder,
|
||||
const Solution &S) {
|
||||
const Solution &S, bool forCompletion) {
|
||||
auto &ctx = S.getConstraintSystem().getASTContext();
|
||||
auto origTy = [&]() -> Type {
|
||||
auto orig = placeholder->getOriginator();
|
||||
@@ -1920,13 +1920,23 @@ static Type replacePlaceholderType(PlaceholderType *placeholder,
|
||||
if (isa<TypeVariableType>(replacement.getPointer()))
|
||||
return ErrorType::get(ctx);
|
||||
|
||||
// For completion, we want to produce an archetype instead of an ErrorType
|
||||
// for a top-level generic parameter.
|
||||
// FIXME: This is pretty weird, we're producing a contextual type outside of
|
||||
// the context it exists in. We ought to see if we can make the completion
|
||||
// logic work with ErrorTypes instead.
|
||||
if (forCompletion) {
|
||||
if (auto *GP = replacement->getAs<GenericTypeParamType>())
|
||||
return GP->getDecl()->getInnermostDeclContext()->mapTypeIntoContext(GP);
|
||||
}
|
||||
// Return an ErrorType with the replacement as the original type. Note that
|
||||
// if we failed to replace a type variable with a generic parameter in a
|
||||
// dependent member, `ErrorType::get` will fold it away.
|
||||
return ErrorType::get(replacement);
|
||||
}
|
||||
|
||||
Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
|
||||
Type Solution::simplifyType(Type type, bool wantInterfaceType,
|
||||
bool forCompletion) const {
|
||||
// If we've been asked for an interface type, start by mapping any archetypes
|
||||
// out of context.
|
||||
if (wantInterfaceType)
|
||||
@@ -1966,7 +1976,7 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
|
||||
auto *typePtr = type.getPointer();
|
||||
|
||||
if (auto *placeholder = dyn_cast<PlaceholderType>(typePtr))
|
||||
return replacePlaceholderType(placeholder, *this);
|
||||
return replacePlaceholderType(placeholder, *this, forCompletion);
|
||||
|
||||
if (isa<TypeVariableType>(typePtr))
|
||||
return ErrorType::get(ctx);
|
||||
@@ -1980,136 +1990,8 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
|
||||
}
|
||||
|
||||
Type Solution::simplifyTypeForCodeCompletion(Type Ty) const {
|
||||
auto &CS = getConstraintSystem();
|
||||
|
||||
// First, instantiate all type variables that we know, but don't replace
|
||||
// placeholders by unresolved types.
|
||||
Ty = CS.simplifyTypeImpl(Ty, [this](TypeVariableType *typeVar) -> Type {
|
||||
return getFixedType(typeVar);
|
||||
});
|
||||
|
||||
// Next, replace all placeholders by type variables. We know that all type
|
||||
// variables now in the type originate from placeholders.
|
||||
Ty = Ty.transformRec([](Type type) -> std::optional<Type> {
|
||||
if (auto *placeholder = type->getAs<PlaceholderType>()) {
|
||||
if (auto *typeVar =
|
||||
placeholder->getOriginator().dyn_cast<TypeVariableType *>()) {
|
||||
return Type(typeVar);
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
// Replace all type variables (which must come from placeholders) by their
|
||||
// generic parameters. Because we call into simplifyTypeImpl
|
||||
Ty = CS.simplifyTypeImpl(Ty, [&CS, this](TypeVariableType *typeVar) -> Type {
|
||||
// Code completion depends on generic parameter type being represented in
|
||||
// terms of `ArchetypeType` since it's easy to extract protocol requirements
|
||||
// from it.
|
||||
auto getTypeVarAsArchetype = [](TypeVariableType *typeVar) -> Type {
|
||||
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
|
||||
if (auto *GPD = GP->getDecl()) {
|
||||
return GPD->getInnermostDeclContext()->mapTypeIntoContext(GP);
|
||||
}
|
||||
}
|
||||
return Type();
|
||||
};
|
||||
|
||||
if (auto archetype = getTypeVarAsArchetype(typeVar)) {
|
||||
return archetype;
|
||||
}
|
||||
|
||||
// Sometimes the type variable itself doesn't have have an originator that
|
||||
// can be replaced by an archetype but one of its equivalent type variable
|
||||
// does.
|
||||
// Search thorough all equivalent type variables, looking for one that can
|
||||
// be replaced by a generic parameter.
|
||||
std::vector<std::pair<TypeVariableType *, Type>> bindings(
|
||||
typeBindings.begin(), typeBindings.end());
|
||||
// Make sure we iterate the bindings in a deterministic order.
|
||||
llvm::sort(bindings, [](const std::pair<TypeVariableType *, Type> &lhs,
|
||||
const std::pair<TypeVariableType *, Type> &rhs) {
|
||||
return lhs.first->getID() < rhs.first->getID();
|
||||
});
|
||||
for (auto binding : bindings) {
|
||||
if (auto placeholder = binding.second->getAs<PlaceholderType>()) {
|
||||
if (placeholder->getOriginator().dyn_cast<TypeVariableType *>() ==
|
||||
typeVar) {
|
||||
if (auto archetype = getTypeVarAsArchetype(binding.first)) {
|
||||
return archetype;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When applying the logic below to get contextual types inside result
|
||||
// builders, the code completion type variable is connected by a one-way
|
||||
// constraint to a type variable in the buildBlock call, but that is not the
|
||||
// type variable that represents the argument type. We need to find the type
|
||||
// variable representing the argument to retrieve protocol requirements from
|
||||
// it. Look for a ArgumentConversion constraint that allows us to retrieve
|
||||
// the argument type var.
|
||||
auto &cg = CS.getConstraintGraph();
|
||||
|
||||
// FIXME: The type variable is not going to be part of the constraint graph
|
||||
// at this point unless it was created at the outermost decision level;
|
||||
// otherwise it has already been rolled back! Work around this by creating
|
||||
// an empty node if one doesn't exist.
|
||||
cg.addTypeVariable(typeVar);
|
||||
|
||||
for (auto argConstraint : cg[typeVar].getConstraints()) {
|
||||
if (argConstraint->getKind() == ConstraintKind::ArgumentConversion &&
|
||||
argConstraint->getFirstType()->getRValueType()->isEqual(typeVar)) {
|
||||
if (auto argTV =
|
||||
argConstraint->getSecondType()->getAs<TypeVariableType>()) {
|
||||
if (auto archetype = getTypeVarAsArchetype(argTV)) {
|
||||
return archetype;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return typeVar;
|
||||
});
|
||||
|
||||
// Logic to determine the contextual type inside buildBlock result builders:
|
||||
//
|
||||
// When completing inside a result builder, the result builder
|
||||
// @ViewBuilder var body: some View {
|
||||
// Text("Foo")
|
||||
// #^COMPLETE^#
|
||||
// }
|
||||
// gets rewritten to
|
||||
// @ViewBuilder var body: some View {
|
||||
// let $__builder2: Text
|
||||
// let $__builder0 = Text("Foo")
|
||||
// let $__builder1 = #^COMPLETE^#
|
||||
// $__builder2 = ViewBuilder.buildBlock($__builder0, $__builder1)
|
||||
// return $__builder2
|
||||
// }
|
||||
// Inside the constraint system
|
||||
// let $__builder1 = #^COMPLETE^#
|
||||
// gets type checked without context, so we can't know the contextual type for
|
||||
// the code completion token. But we know that $__builder1 (and thus the type
|
||||
// of #^COMPLETE^#) is used as the second argument to ViewBuilder.buildBlock,
|
||||
// so we can extract the contextual type from that call. To do this, figure
|
||||
// out the type variable that is used for $__builder1 in the buildBlock call.
|
||||
// This type variable is connected to the type variable of $__builder1's
|
||||
// definition by a one-way constraint.
|
||||
if (auto TV = Ty->getAs<TypeVariableType>()) {
|
||||
for (auto constraint : CS.getConstraintGraph()[TV].getConstraints()) {
|
||||
if (constraint->getKind() == ConstraintKind::OneWayEqual &&
|
||||
constraint->getSecondType()->isEqual(TV)) {
|
||||
return simplifyTypeForCodeCompletion(constraint->getFirstType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any remaining type variables and placeholders
|
||||
Ty = simplifyType(Ty);
|
||||
|
||||
return Ty->getRValueType();
|
||||
return simplifyType(Ty, /*wantInterfaceType*/ false, /*forCompletion*/ true)
|
||||
->getRValueType();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
Reference in New Issue
Block a user