Skip to content

Commit 573ae9b

Browse files
authored
Merge pull request #40047 from xedin/rdar-83056143
[Diagnostics] A tailored diagnostic for Double<->CGFloat conversion via optional chaining
2 parents 246896f + ba9f6a2 commit 573ae9b

File tree

8 files changed

+64
-12
lines changed

8 files changed

+64
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5952,6 +5952,13 @@ ERROR(cannot_declare_computed_var_in_result_builder,none,
59525952
"expression shuffles the elements of this tuple; "
59535953
"this behavior is deprecated", ())
59545954

5955+
//------------------------------------------------------------------------------
5956+
// MARK: Implicit conversion diagnostics
5957+
//------------------------------------------------------------------------------
5958+
ERROR(cannot_implicitly_convert_in_optional_context,none,
5959+
"cannot implicitly convert value of type %0 to expected type %1",
5960+
(Type, Type))
5961+
59555962
//------------------------------------------------------------------------------
59565963
// MARK: marker protocol diagnostics
59575964
//------------------------------------------------------------------------------

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
802802

803803
/// Check if this is a CGFloat type from CoreGraphics framework
804804
/// on macOS or Foundation on Linux.
805-
bool isCGFloatType();
805+
bool isCGFloat();
806806

807807
/// Check if this is either an Array, Set or Dictionary collection type defined
808808
/// at the top level of the Swift module

lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ bool TypeBase::isStdlibType() {
813813
return false;
814814
}
815815

816-
bool TypeBase::isCGFloatType() {
816+
bool TypeBase::isCGFloat() {
817817
auto *NTD = getAnyNominal();
818818
if (!NTD)
819819
return false;

lib/Sema/CSBindings.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ void BindingSet::addBinding(PotentialBinding binding) {
548548
if (!TypeVar->getImpl().isClosureParameterType()) {
549549
auto type = binding.BindingType;
550550

551-
if (type->isCGFloatType() &&
551+
if (type->isCGFloat() &&
552552
llvm::any_of(Bindings, [](const PotentialBinding &binding) {
553553
return binding.BindingType->isDouble();
554554
}))
@@ -557,7 +557,7 @@ void BindingSet::addBinding(PotentialBinding binding) {
557557
if (type->isDouble()) {
558558
auto inferredCGFloat =
559559
llvm::find_if(Bindings, [](const PotentialBinding &binding) {
560-
return binding.BindingType->isCGFloatType();
560+
return binding.BindingType->isCGFloat();
561561
});
562562

563563
if (inferredCGFloat != Bindings.end()) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,22 @@ bool ContextualFailure::diagnoseAsError() {
24182418
break;
24192419
}
24202420

2421+
case ConstraintLocator::OptionalPayload: {
2422+
// If this is an attempt at a Double <-> CGFloat conversion
2423+
// through optional chaining, let's produce a tailored diagnostic.
2424+
if (isExpr<OptionalEvaluationExpr>(getAnchor())) {
2425+
if ((fromType->isDouble() || fromType->isCGFloat()) &&
2426+
(toType->isDouble() || toType->isCGFloat())) {
2427+
fromType = OptionalType::get(fromType);
2428+
toType = OptionalType::get(toType);
2429+
diagnostic = diag::cannot_implicitly_convert_in_optional_context;
2430+
break;
2431+
}
2432+
}
2433+
2434+
return false;
2435+
}
2436+
24212437
default:
24222438
return false;
24232439
}

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ namespace {
383383
return true;
384384

385385
// Don't favor narrowing conversions.
386-
if (argTy->isDouble() && paramTy->isCGFloatType())
386+
if (argTy->isDouble() && paramTy->isCGFloat())
387387
return false;
388388

389389
llvm::SmallSetVector<ProtocolDecl *, 2> literalProtos;
@@ -420,7 +420,7 @@ namespace {
420420
// it is the same as the parameter type.
421421
// Check whether there is a default type to compare against.
422422
if (paramTy->isEqual(defaultType) ||
423-
(defaultType->isDouble() && paramTy->isCGFloatType()))
423+
(defaultType->isDouble() && paramTy->isCGFloat()))
424424
return true;
425425
}
426426
}
@@ -560,7 +560,7 @@ namespace {
560560
// in order to preserve current behavior, let's not favor overloads
561561
// which would result in conversion from CGFloat to Double; otherwise
562562
// it would lead to ambiguities.
563-
if (argTy->isCGFloatType() && paramTy->isDouble())
563+
if (argTy->isCGFloat() && paramTy->isDouble())
564564
return false;
565565

566566
return isFavoredParamAndArg(CS, paramTy, argTy) &&
@@ -719,10 +719,10 @@ namespace {
719719
// Avoid favoring overloads that would require narrowing conversion
720720
// to match the arguments.
721721
{
722-
if (firstArgTy->isDouble() && firstParamTy->isCGFloatType())
722+
if (firstArgTy->isDouble() && firstParamTy->isCGFloat())
723723
return false;
724724

725-
if (secondArgTy->isDouble() && secondParamTy->isCGFloatType())
725+
if (secondArgTy->isDouble() && secondParamTy->isCGFloat())
726726
return false;
727727
}
728728

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5474,7 +5474,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
54745474

54755475
if (kind >= ConstraintKind::Subtype &&
54765476
nominal1->getDecl() != nominal2->getDecl() &&
5477-
((nominal1->isCGFloatType() || nominal2->isCGFloatType()) &&
5477+
((nominal1->isCGFloat() || nominal2->isCGFloat()) &&
54785478
(nominal1->isDouble() || nominal2->isDouble()))) {
54795479
ConstraintLocatorBuilder location{locator};
54805480
// Look through all value-to-optional promotions to allow
@@ -5485,6 +5485,19 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
54855485
SmallVector<LocatorPathElt, 4> path;
54865486
auto anchor = location.getLocatorParts(path);
54875487

5488+
// An attempt at Double/CGFloat conversion through
5489+
// optional chaining. This is not supported at the
5490+
// moment because solution application doesn't know
5491+
// how to map Double to/from CGFloat through optionals.
5492+
if (isExpr<OptionalEvaluationExpr>(anchor)) {
5493+
if (!shouldAttemptFixes())
5494+
return getTypeMatchFailure(locator);
5495+
5496+
conversionsOrFixes.push_back(ContextualMismatch::create(
5497+
*this, nominal1, nominal2, getConstraintLocator(locator)));
5498+
break;
5499+
}
5500+
54885501
// Drop all of the applied `value-to-optional` promotions.
54895502
path.erase(llvm::remove_if(
54905503
path,
@@ -5519,7 +5532,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
55195532
auto isCGFloatInit = [&](ASTNode location) {
55205533
if (auto *call = getAsExpr<CallExpr>(location)) {
55215534
if (auto *typeExpr = dyn_cast<TypeExpr>(call->getFn())) {
5522-
return getInstanceType(typeExpr)->isCGFloatType();
5535+
return getInstanceType(typeExpr)->isCGFloat();
55235536
}
55245537
}
55255538
return false;
@@ -5548,7 +5561,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
55485561
return false;
55495562
})) {
55505563
conversionsOrFixes.push_back(
5551-
desugar1->isCGFloatType()
5564+
desugar1->isCGFloat()
55525565
? ConversionRestrictionKind::CGFloatToDouble
55535566
: ConversionRestrictionKind::DoubleToCGFloat);
55545567
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck -verify
2+
// REQUIRES: objc_interop
3+
4+
import Foundation
5+
6+
struct S {
7+
var test: CGFloat
8+
}
9+
10+
func compute(_: Double?) -> Double? {
11+
return 42
12+
}
13+
14+
func test(s: S?) {
15+
_ = compute(s?.test) // expected-error {{cannot implicitly convert value of type 'CGFloat?' to expected type 'Double?'}}
16+
}

0 commit comments

Comments
 (0)