Skip to content

Commit d181336

Browse files
Merge pull request #38884 from LucianoPAlmeida/SR-15038-array-element
[SR-15038][Sema] Use locator to propagate information of array, set, dictonary element on check cast constraint
2 parents 1d2d15a + 3c60270 commit d181336

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6600,7 +6600,8 @@ static ConstraintFix *maybeWarnAboutExtraneousCast(
66006600
SmallVector<Type, 4> toOptionals, ConstraintSystem::TypeMatchOptions flags,
66016601
ConstraintLocatorBuilder locator) {
66026602

6603-
if (flags.contains(ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix))
6603+
auto last = locator.last();
6604+
if (last && last->is<LocatorPathElt::GenericArgument>())
66046605
return nullptr;
66056606

66066607
// Both types have to be fixed.
@@ -6777,9 +6778,11 @@ ConstraintSystem::simplifyCheckedCastConstraint(
67776778
case CheckedCastKind::ArrayDowncast: {
67786779
auto fromBaseType = *isArrayType(fromType);
67796780
auto toBaseType = *isArrayType(toType);
6780-
6781-
auto result = simplifyCheckedCastConstraint(
6782-
fromBaseType, toBaseType, subflags | TMF_ApplyingFix, locator);
6781+
6782+
auto elementLocator =
6783+
locator.withPathElement(LocatorPathElt::GenericArgument(0));
6784+
auto result = simplifyCheckedCastConstraint(fromBaseType, toBaseType,
6785+
subflags, elementLocator);
67836786
attemptRecordCastFixIfSolved(result);
67846787
return result;
67856788
}
@@ -6791,22 +6794,28 @@ ConstraintSystem::simplifyCheckedCastConstraint(
67916794
Type toKeyType, toValueType;
67926795
std::tie(toKeyType, toValueType) = *isDictionaryType(toType);
67936796

6794-
if (simplifyCheckedCastConstraint(fromKeyType, toKeyType,
6795-
subflags | TMF_ApplyingFix,
6796-
locator) == SolutionKind::Error)
6797+
auto keyLocator =
6798+
locator.withPathElement(LocatorPathElt::GenericArgument(0));
6799+
if (simplifyCheckedCastConstraint(fromKeyType, toKeyType, subflags,
6800+
keyLocator) == SolutionKind::Error)
67976801
return SolutionKind::Error;
67986802

6799-
auto result = simplifyCheckedCastConstraint(
6800-
fromValueType, toValueType, subflags | TMF_ApplyingFix, locator);
6803+
auto valueLocator =
6804+
locator.withPathElement(LocatorPathElt::GenericArgument(1));
6805+
auto result = simplifyCheckedCastConstraint(fromValueType, toValueType,
6806+
subflags, valueLocator);
68016807
attemptRecordCastFixIfSolved(result);
68026808
return result;
68036809
}
68046810

68056811
case CheckedCastKind::SetDowncast: {
68066812
auto fromBaseType = *isSetType(fromType);
68076813
auto toBaseType = *isSetType(toType);
6808-
auto result = simplifyCheckedCastConstraint(
6809-
fromBaseType, toBaseType, subflags | TMF_ApplyingFix, locator);
6814+
6815+
auto elementLocator =
6816+
locator.withPathElement(LocatorPathElt::GenericArgument(0));
6817+
auto result = simplifyCheckedCastConstraint(fromBaseType, toBaseType,
6818+
subflags, elementLocator);
68106819
attemptRecordCastFixIfSolved(result);
68116820
return result;
68126821
}

test/Constraints/casts.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,3 +549,67 @@ extension ChangeType where T == String? {
549549
var foo: String? { return self.delta?.previous as? String } // OK
550550
var bar: String? { self.delta?.next }
551551
}
552+
553+
// SR-15038
554+
protocol ExperimentDeserializable {
555+
static func deserializeExperiment(_ value: Any) -> Self?
556+
}
557+
558+
extension String: ExperimentDeserializable {
559+
static func deserializeExperiment(_ value: Any) -> String? { value as? String }
560+
}
561+
562+
extension Int: ExperimentDeserializable {
563+
static func deserializeExperiment(_ value: Any) -> Int? { value as? Int }
564+
}
565+
566+
class Constant<T> {
567+
private init(getUnderlyingValue: @escaping () -> T) {
568+
print(getUnderlyingValue())
569+
}
570+
}
571+
572+
struct Thing {
573+
let storage: [String: Any]
574+
}
575+
576+
extension Constant where T: Sequence, T.Element: ExperimentDeserializable {
577+
static func foo<U>(thing: Thing, defaultValue: T) -> T where T == [U] {
578+
guard let array = thing.storage["foo"] as? [Any] else {
579+
fatalError()
580+
}
581+
582+
let value = array.map(T.Element.deserializeExperiment) as? [T.Element] ?? defaultValue // OK
583+
return value
584+
}
585+
}
586+
587+
// Array
588+
func decodeStringOrInt<T: FixedWidthInteger>() -> [T] {
589+
let stringWrapped = [String]()
590+
if let values = stringWrapped.map({ $0.isEmpty ? 0 : T($0) }) as? [T] { // OK
591+
return values
592+
} else {
593+
fatalError()
594+
}
595+
}
596+
597+
// Set
598+
func decodeStringOrIntSet<T: FixedWidthInteger>() -> Set<T> {
599+
let stringWrapped = [String]()
600+
if let values = Set(stringWrapped.map({ $0.isEmpty ? 0 : T($0) })) as? Set<T> { // OK
601+
return values
602+
} else {
603+
fatalError()
604+
}
605+
}
606+
607+
// Dictionary
608+
func decodeStringOrIntDictionary<T: FixedWidthInteger>() -> [Int: T] {
609+
let stringWrapped = [String]()
610+
if let values = Dictionary(uniqueKeysWithValues: stringWrapped.map({ $0.isEmpty ? (0, 0) : (0, T($0)) })) as? [Int: T] { // OK
611+
return values
612+
} else {
613+
fatalError()
614+
}
615+
}

0 commit comments

Comments
 (0)