Skip to content

Commit 8c42438

Browse files
[Sema] Account for value to optional restriction when recording runtime cast warnings
1 parent 36d40b1 commit 8c42438

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6709,7 +6709,10 @@ static bool isCastToExpressibleByNilLiteral(ConstraintSystem &cs, Type fromType,
67096709
static ConstraintFix *maybeWarnAboutExtraneousCast(
67106710
ConstraintSystem &cs, Type origFromType, Type origToType, Type fromType,
67116711
Type toType, SmallVector<Type, 4> fromOptionals,
6712-
SmallVector<Type, 4> toOptionals, ConstraintSystem::TypeMatchOptions flags,
6712+
SmallVector<Type, 4> toOptionals,
6713+
const std::vector<std::tuple<Type, Type, ConversionRestrictionKind>>
6714+
&constraintRestrictions,
6715+
ConstraintSystem::TypeMatchOptions flags,
67136716
ConstraintLocatorBuilder locator) {
67146717

67156718
auto last = locator.last();
@@ -6731,6 +6734,22 @@ static ConstraintFix *maybeWarnAboutExtraneousCast(
67316734
// "from" could be less optional than "to" e.g. `0 as Any?`, so
67326735
// we need to store the difference as a signed integer.
67336736
int extraOptionals = fromOptionals.size() - toOptionals.size();
6737+
6738+
// From expression could be a type variable with a value to optional
6739+
// restrictions that we have to account for optionality mismatch.
6740+
const auto subExprType = cs.getType(castExpr->getSubExpr());
6741+
if (llvm::any_of(constraintRestrictions, [&](auto &entry) {
6742+
Type type1, type2;
6743+
ConversionRestrictionKind kind;
6744+
std::tie(type1, type2, kind) = entry;
6745+
if (kind != ConversionRestrictionKind::ValueToOptional)
6746+
return false;
6747+
return fromType->isEqual(type1) && subExprType->isEqual(type2);
6748+
})) {
6749+
extraOptionals++;
6750+
origFromType = OptionalType::get(origFromType);
6751+
}
6752+
67346753
// Removing the optionality from to type when the force cast expr is an IUO.
67356754
const auto *const TR = castExpr->getCastTypeRepr();
67366755
if (isExpr<ForcedCheckedCastExpr>(anchor) && TR &&
@@ -6886,7 +6905,7 @@ ConstraintSystem::simplifyCheckedCastConstraint(
68866905

68876906
if (auto *fix = maybeWarnAboutExtraneousCast(
68886907
*this, origFromType, origToType, fromType, toType, fromOptionals,
6889-
toOptionals, flags, locator)) {
6908+
toOptionals, ConstraintRestrictions, flags, locator)) {
68906909
(void)recordFix(fix);
68916910
}
68926911
};
@@ -6954,7 +6973,7 @@ ConstraintSystem::simplifyCheckedCastConstraint(
69546973
// succeed or fail.
69556974
if (auto *fix = maybeWarnAboutExtraneousCast(
69566975
*this, origFromType, origToType, fromType, toType, fromOptionals,
6957-
toOptionals, flags, locator)) {
6976+
toOptionals, ConstraintRestrictions, flags, locator)) {
69586977
(void)recordFix(fix);
69596978
}
69606979

test/Constraints/casts.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,23 @@ func decodeStringOrIntDictionary<T: FixedWidthInteger>() -> [Int: T] {
613613
fatalError()
614614
}
615615
}
616+
617+
// SR-15281
618+
struct SR15281_A { }
619+
620+
struct SR15281_B {
621+
init(a: SR15281_A) { }
622+
}
623+
624+
struct SR15281_S {
625+
var a: SR15281_A? = SR15281_A()
626+
627+
var b1: SR15281_B {
628+
a.flatMap(SR15281_B.init(a:)) as! SR15281_B
629+
// expected-warning@-1 {{forced cast from 'SR15281_B?' to 'SR15281_B' only unwraps optionals; did you mean to use '!'?}} {{34-34=!}} {{34-48=}}
630+
}
631+
632+
var b: SR15281_B {
633+
a.flatMap(SR15281_B.init(a:)) // expected-error{{cannot convert return expression of type 'SR15281_B?' to return type 'SR15281_B'}} {{34-34= as! SR15281_B}}
634+
}
635+
}

0 commit comments

Comments
 (0)