Skip to content

[Diagnostics] Special case assignment between nominal types with optional promotion #35072

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2120,7 +2120,9 @@ bool ContextualFailure::diagnoseAsError() {
}

if (isExpr<AssignExpr>(anchor)) {
emitDiagnostic(diag::cannot_convert_assign, getFromType(), getToType());
auto diagnostic = emitDiagnostic(diag::cannot_convert_assign,
getFromType(), getToType());
tryIntegerCastFixIts(diagnostic);
return true;
}

Expand Down Expand Up @@ -2729,6 +2731,15 @@ bool ContextualFailure::tryIntegerCastFixIts(
auto fromType = getFromType();
auto toType = getToType();

auto anchor = getAnchor();
auto exprRange = getSourceRange();

if (auto *assignment = getAsExpr<AssignExpr>(anchor)) {
toType = toType->lookThroughAllOptionalTypes();
anchor = assignment->getSrc();
exprRange = assignment->getSrc()->getSourceRange();
}

if (!isIntegerType(fromType) || !isIntegerType(toType))
return false;

Expand All @@ -2747,8 +2758,8 @@ bool ContextualFailure::tryIntegerCastFixIts(
return parenE->getSubExpr();
};

if (auto *anchor = getAsExpr(getAnchor())) {
if (Expr *innerE = getInnerCastedExpr(anchor)) {
if (auto *expr = getAsExpr(anchor)) {
if (Expr *innerE = getInnerCastedExpr(expr)) {
Type innerTy = getType(innerE);
if (TypeChecker::isConvertibleTo(innerTy, toType, getDC())) {
// Remove the unnecessary cast.
Expand All @@ -2763,7 +2774,6 @@ bool ContextualFailure::tryIntegerCastFixIts(
std::string convWrapBefore = toType.getString();
convWrapBefore += "(";
std::string convWrapAfter = ")";
SourceRange exprRange = getSourceRange();
diagnostic.fixItInsert(exprRange.Start, convWrapBefore);
diagnostic.fixItInsertAfter(exprRange.End, convWrapAfter);
return true;
Expand Down
7 changes: 4 additions & 3 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3722,14 +3722,15 @@ bool ConstraintSystem::repairFailures(
if (lhs->is<FunctionType>() && rhs->is<FunctionType>())
return false;

// If either object type is a bound generic or existential it means
// that follow-up to value-to-optional is going to be:
// If either object type is a generic, nominal or existential type
// it means that follow-up to value-to-optional is going to be:
//
// 1. "deep equality" check, which is handled by generic argument(s)
// mismatch fix, or
// or contextual mismatch fix, or
// 2. "existential" check, which is handled by a missing conformance
// fix.
if ((lhs->is<BoundGenericType>() && rhs->is<BoundGenericType>()) ||
(lhs->is<NominalType>() && rhs->is<NominalType>()) ||
rhs->isAnyExistentialType())
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ var afterMessageCount : Int?
func uintFunc() -> UInt {}
func takeVoidVoidFn(_ a : () -> ()) {}
takeVoidVoidFn { () -> Void in
afterMessageCount = uintFunc() // expected-error {{cannot assign value of type 'UInt' to type 'Int'}}
afterMessageCount = uintFunc() // expected-error {{cannot assign value of type 'UInt' to type 'Int?'}} {{23-23=Int(}} {{33-33=)}}
}

// <rdar://problem/19997471> Swift: Incorrect compile error when calling a function inside a closure
Expand Down
37 changes: 37 additions & 0 deletions test/Constraints/sr13951.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// RUN: %target-typecheck-verify-swift

protocol TheProtocol {}
struct TheType1: TheProtocol {}

enum TheEnum: RawRepresentable {
typealias RawValue = TheProtocol

case case1
case case2

init?(rawValue: TheProtocol) {
self = .case1
}

var rawValue: TheProtocol {
return TheType1()
}
}

func aTransformer(input: Int) -> TheEnum {
if input % 2 == 0 {
return .case1
} else {
return .case2
}
}

func theProblem(input: Int?) {
var enumValue: TheEnum?

if let input = input {
enumValue = aTransformer(input: input) // Ok
}

_ = enumValue // To silence the warning
}
6 changes: 3 additions & 3 deletions test/decl/var/property_wrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1100,12 +1100,12 @@ struct TestComposition {
// expected-error@-2 {{composed wrapper type 'WrapperE<Int>' does not match former 'wrappedValue' type 'WrapperC<Value>'}}

func triggerErrors(d: Double) { // expected-note 6 {{mark method 'mutating' to make 'self' mutable}} {{2-2=mutating }}
p1 = d // expected-error{{cannot assign value of type 'Double' to type 'Int'}} {{8-8=Int(}} {{9-9=)}}
p1 = d // expected-error{{cannot assign value of type 'Double' to type 'Int?'}} {{8-8=Int(}} {{9-9=)}}
// expected-error@-1 {{cannot assign to property: 'self' is immutable}}
p2 = d // expected-error{{cannot assign value of type 'Double' to type 'String'}}
p2 = d // expected-error{{cannot assign value of type 'Double' to type 'String?'}}
// expected-error@-1 {{cannot assign to property: 'self' is immutable}}
// TODO(diagnostics): Looks like source range for 'd' here is reported as starting at 10, but it should be 8
p3 = d // expected-error{{cannot assign value of type 'Double' to type 'Int'}} {{10-10=Int(}} {{11-11=)}}
p3 = d // expected-error{{cannot assign value of type 'Double' to type 'Int?'}} {{10-10=Int(}} {{11-11=)}}
// expected-error@-1 {{cannot assign to property: 'self' is immutable}}

_p1 = d // expected-error{{cannot assign value of type 'Double' to type 'WrapperA<WrapperB<WrapperC<Int>>>'}}
Expand Down