[CS] Simplify Solution::resolveInterfaceType

Rather than attempting to re-implement `simplifyType`,
tweak `Solution::simplifyType` such that it can
map the resulting type out of context, and can
turn type variables into their opened generic
parameters.
This commit is contained in:
Hamish Knight
2024-12-31 18:39:19 +00:00
parent 55189bae8e
commit 9fe4abc6fd
3 changed files with 36 additions and 27 deletions

View File

@@ -1652,7 +1652,11 @@ public:
/// Simplify the given type by substituting all occurrences of
/// type variables for their fixed types.
Type simplifyType(Type type) const;
///
/// \param wantInterfaceType If true, maps the resulting type out of context,
/// and replaces type variables for opened generic parameters with the
/// generic parameter types. Should only be used for diagnostic logic.
Type simplifyType(Type type, bool wantInterfaceType = false) const;
// To aid code completion, we need to attempt to convert type placeholders
// back into underlying generic parameters if possible, since type

View File

@@ -1721,14 +1721,29 @@ void Solution::recordSingleArgMatchingChoice(ConstraintLocator *locator) {
MatchCallArgumentResult::forArity(1)});
}
Type Solution::simplifyType(Type type) const {
Type Solution::simplifyType(Type type, bool wantInterfaceType) const {
// If we've been asked for an interface type, start by mapping any archetypes
// out of context.
if (wantInterfaceType)
type = type->mapTypeOutOfContext();
if (!(type->hasTypeVariable() || type->hasPlaceholder()))
return type;
// Map type variables to fixed types from bindings.
auto &cs = getConstraintSystem();
auto resolvedType = cs.simplifyTypeImpl(
type, [&](TypeVariableType *tvt) -> Type { return getFixedType(tvt); });
auto resolvedType =
cs.simplifyTypeImpl(type, [&](TypeVariableType *tvt) -> Type {
// If we want the interface type, use the generic parameter if we
// have one, otherwise map the fixed type out of context.
if (wantInterfaceType) {
if (auto *gp = tvt->getImpl().getGenericParameter())
return gp;
return getFixedType(tvt)->mapTypeOutOfContext();
}
return getFixedType(tvt);
});
ASSERT(!(wantInterfaceType && resolvedType->hasPrimaryArchetype()));
// Placeholders shouldn't be reachable through a solution, they are only
// useful to determine what went wrong exactly.
@@ -4008,29 +4023,7 @@ ASTNode ConstraintSystem::includingParentApply(ASTNode node) {
}
Type Solution::resolveInterfaceType(Type type) const {
auto resolvedType = type.transformRec([&](Type type) -> std::optional<Type> {
if (auto *tvt = type->getAs<TypeVariableType>()) {
// If this type variable is for a generic parameter, return that.
if (auto *gp = tvt->getImpl().getGenericParameter())
return gp;
// Otherwise resolve its fixed type, mapped out of context.
auto fixed = simplifyType(tvt);
return resolveInterfaceType(fixed->mapTypeOutOfContext());
}
if (auto *dmt = type->getAs<DependentMemberType>()) {
// For a dependent member, first resolve the base.
auto newBase = resolveInterfaceType(dmt->getBase());
// Then reconstruct using its associated type.
assert(dmt->getAssocType());
return DependentMemberType::get(newBase, dmt->getAssocType());
}
return std::nullopt;
});
assert(!resolvedType->hasArchetype());
return resolvedType;
return simplifyType(type, /*wantInterfaceType*/ true);
}
std::optional<FunctionArgApplyInfo>

View File

@@ -0,0 +1,12 @@
// RUN: %target-typecheck-verify-swift
// https://github.com/swiftlang/swift/issues/77924
func foo<T>(_ x: (T) -> Void) {
(a: 0, b: x).b(0) // expected-error {{cannot convert value of type 'Int' to expected argument type 'T'}}
}
func bar<T>(_ x: T) {} // expected-note {{generic parameters are always considered '@escaping'}}
func baz(_ fn: () -> Void) {
(a: 0, b: bar).b(fn) // expected-error {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}}
}