Skip to content

Commit bd4ee46

Browse files
authored
Merge pull request #70007 from xedin/keypath-application-improvements
[ConstraintSystem] Modernization of key path application handling
2 parents 126022f + cceef44 commit bd4ee46

14 files changed

+169
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,10 @@ ERROR(expr_swift_keypath_anyobject_root,none,
704704
"the root type of a Swift key path cannot be 'AnyObject'", ())
705705
ERROR(expr_keypath_multiparam_func_conversion, none,
706706
"cannot convert key path into a multi-argument function type %0", (Type))
707+
ERROR(cannot_convert_type_to_keypath_subscript_index,none,
708+
"cannot use value of type %0 as a key path subscript index; argument must be"
709+
" a key path",
710+
(Type))
707711
WARNING(expr_deprecated_writable_keypath,Deprecation,
708712
"forming a writable keypath to property %0 that is read-only in this context "
709713
"is deprecated and will be removed in a future release",

include/swift/Sema/CSFix.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,10 @@ enum class FixKind : uint8_t {
463463
/// Ignore situations when provided number of generic arguments didn't match
464464
/// expected number of parameters.
465465
IgnoreGenericSpecializationArityMismatch,
466+
467+
/// Ignore situations when key path subscript index gets passed an invalid
468+
/// type as an argument (something that is not a key path).
469+
IgnoreKeyPathSubscriptIndexMismatch,
466470
};
467471

468472
class ConstraintFix {
@@ -3708,6 +3712,30 @@ class IgnoreGenericSpecializationArityMismatch final : public ConstraintFix {
37083712
}
37093713
};
37103714

3715+
class IgnoreKeyPathSubscriptIndexMismatch final : public ConstraintFix {
3716+
Type ArgType;
3717+
3718+
IgnoreKeyPathSubscriptIndexMismatch(ConstraintSystem &cs, Type argTy,
3719+
ConstraintLocator *locator)
3720+
: ConstraintFix(cs, FixKind::IgnoreKeyPathSubscriptIndexMismatch,
3721+
locator),
3722+
ArgType(argTy) {}
3723+
3724+
public:
3725+
std::string getName() const override {
3726+
return "ignore invalid key path subscript index";
3727+
}
3728+
3729+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3730+
3731+
static IgnoreKeyPathSubscriptIndexMismatch *
3732+
create(ConstraintSystem &cs, Type argType, ConstraintLocator *locator);
3733+
3734+
static bool classof(const ConstraintFix *fix) {
3735+
return fix->getKind() == FixKind::IgnoreKeyPathSubscriptIndexMismatch;
3736+
}
3737+
};
3738+
37113739
} // end namespace constraints
37123740
} // end namespace swift
37133741

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ SIMPLE_LOCATOR_PATH_ELT(KeyPathType)
131131
/// The value of a key path.
132132
SIMPLE_LOCATOR_PATH_ELT(KeyPathValue)
133133

134+
/// The index parameter of a special `subscript(keyPath: KeyPath<...>)`.
135+
SIMPLE_LOCATOR_PATH_ELT(KeyPathSubscriptIndex)
136+
134137
/// An implicit @lvalue-to-inout conversion; only valid for operator
135138
/// arguments.
136139
SIMPLE_LOCATOR_PATH_ELT(LValueConversion)

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,10 @@ class TypeVariableType::Implementation {
499499
/// expression.
500500
bool isKeyPathValue() const;
501501

502+
/// Determine whether this type variable represents an index parameter of
503+
/// a special `subscript(keyPath:)` subscript.
504+
bool isKeyPathSubscriptIndex() const;
505+
502506
/// Determine whether this type variable represents a subscript result type.
503507
bool isSubscriptResultType() const;
504508

lib/Sema/CSBindings.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,27 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
14271427
return llvm::None;
14281428
}
14291429

1430+
if (TypeVar->getImpl().isKeyPathSubscriptIndex()) {
1431+
// Key path subscript index can only be a r-value non-optional
1432+
// type that is a subtype of a known KeyPath type.
1433+
type = type->getRValueType()->lookThroughAllOptionalTypes();
1434+
1435+
// If argument to a key path subscript is an existential,
1436+
// we can erase it to superclass (if any) here and solver
1437+
// will perform the opening if supertype turns out to be
1438+
// a valid key path type of its subtype.
1439+
if (kind == AllowedBindingKind::Supertypes) {
1440+
if (type->isExistentialType()) {
1441+
auto layout = type->getExistentialLayout();
1442+
if (auto superclass = layout.explicitSuperclass) {
1443+
type = superclass;
1444+
} else if (!CS.shouldAttemptFixes()) {
1445+
return llvm::None;
1446+
}
1447+
}
1448+
}
1449+
}
1450+
14301451
if (auto *locator = TypeVar->getImpl().getLocator()) {
14311452
// Don't allow a protocol type to get propagated from the base to the result
14321453
// type of a chain, Result should always be a concrete type which conforms

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9302,3 +9302,8 @@ bool InvalidTypeSpecializationArity::diagnoseAsError() {
93029302
/*generic=*/nullptr);
93039303
return true;
93049304
}
9305+
9306+
bool InvalidTypeAsKeyPathSubscriptIndex::diagnoseAsError() {
9307+
emitDiagnostic(diag::cannot_convert_type_to_keypath_subscript_index, ArgType);
9308+
return true;
9309+
}

lib/Sema/CSDiagnostics.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3128,6 +3128,24 @@ class InvalidTypeSpecializationArity final : public FailureDiagnostic {
31283128
bool diagnoseAsError() override;
31293129
};
31303130

3131+
/// Diagnose attempts to pass non-keypath as an argument to key path subscript:
3132+
///
3133+
/// \code
3134+
/// func test(data: Int) {
3135+
/// data[keyPath: 42] // error `42` is not a key path
3136+
/// }
3137+
/// \endcode
3138+
class InvalidTypeAsKeyPathSubscriptIndex final : public FailureDiagnostic {
3139+
Type ArgType;
3140+
3141+
public:
3142+
InvalidTypeAsKeyPathSubscriptIndex(const Solution &solution, Type argType,
3143+
ConstraintLocator *locator)
3144+
: FailureDiagnostic(solution, locator), ArgType(resolveType(argType)) {}
3145+
3146+
bool diagnoseAsError() override;
3147+
};
3148+
31313149
} // end namespace constraints
31323150
} // end namespace swift
31333151

lib/Sema/CSFix.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2627,3 +2627,16 @@ IgnoreGenericSpecializationArityMismatch::create(ConstraintSystem &cs,
26272627
return new (cs.getAllocator()) IgnoreGenericSpecializationArityMismatch(
26282628
cs, decl, numParams, numArgs, hasParameterPack, locator);
26292629
}
2630+
2631+
bool IgnoreKeyPathSubscriptIndexMismatch::diagnose(const Solution &solution,
2632+
bool asNote) const {
2633+
InvalidTypeAsKeyPathSubscriptIndex failure(solution, ArgType, getLocator());
2634+
return failure.diagnose(asNote);
2635+
}
2636+
2637+
IgnoreKeyPathSubscriptIndexMismatch *
2638+
IgnoreKeyPathSubscriptIndexMismatch::create(ConstraintSystem &cs, Type argType,
2639+
ConstraintLocator *locator) {
2640+
return new (cs.getAllocator())
2641+
IgnoreKeyPathSubscriptIndexMismatch(cs, argType, locator);
2642+
}

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12414,9 +12414,18 @@ ConstraintSystem::simplifyKeyPathApplicationConstraint(
1241412414
// Otherwise, we don't have a key path type at all.
1241512415
return SolutionKind::Error;
1241612416
}
12417-
if (!keyPathTy->isTypeVariableOrMember())
12417+
12418+
if (!keyPathTy->isTypeVariableOrMember()) {
12419+
if (shouldAttemptFixes()) {
12420+
auto *fix = IgnoreKeyPathSubscriptIndexMismatch::create(
12421+
*this, keyPathTy, getConstraintLocator(locator));
12422+
recordAnyTypeVarAsPotentialHole(valueTy);
12423+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
12424+
}
12425+
1241812426
return SolutionKind::Error;
12419-
12427+
}
12428+
1242012429
return unsolved();
1242112430
}
1242212431

@@ -14886,7 +14895,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1488614895
case FixKind::AllowAssociatedValueMismatch:
1488714896
case FixKind::GenericArgumentsMismatch:
1488814897
case FixKind::AllowConcreteTypeSpecialization:
14889-
case FixKind::IgnoreGenericSpecializationArityMismatch: {
14898+
case FixKind::IgnoreGenericSpecializationArityMismatch:
14899+
case FixKind::IgnoreKeyPathSubscriptIndexMismatch: {
1489014900
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1489114901
}
1489214902
case FixKind::IgnoreThrownErrorMismatch: {

lib/Sema/ConstraintLocator.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
111111
case ConstraintLocator::PackExpansionType:
112112
case ConstraintLocator::ThrownErrorType:
113113
case ConstraintLocator::FallbackType:
114+
case ConstraintLocator::KeyPathSubscriptIndex:
114115
return 0;
115116

116117
case ConstraintLocator::FunctionArgument:
@@ -528,6 +529,10 @@ void LocatorPathElt::dump(raw_ostream &out) const {
528529
case ConstraintLocator::FallbackType: {
529530
out << "fallback type";
530531
break;
532+
533+
case ConstraintLocator::KeyPathSubscriptIndex:
534+
out << "key path subscript index parameter";
535+
break;
531536
}
532537
}
533538
}

0 commit comments

Comments
 (0)