Skip to content
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
82 changes: 70 additions & 12 deletions lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ Comparison TypeChecker::compareDeclarations(DeclContext *dc,
return decl1Better ? Comparison::Better : Comparison::Worse;
}

static Type getUnlabeledType(Type type, ASTContext &ctx) {
static Type getStrippedType(Type type, ASTContext &ctx) {
return type.transformRec([&](TypeBase *type) -> std::optional<Type> {
if (auto *tupleType = dyn_cast<TupleType>(type)) {
if (tupleType->getNumElements() == 1)
Expand All @@ -866,6 +866,31 @@ static Type getUnlabeledType(Type type, ASTContext &ctx) {
return TupleType::get(elts, ctx);
}

if (auto *funcType = dyn_cast<FunctionType>(type)) {
auto params = funcType->getParams();
SmallVector<AnyFunctionType::Param, 4> newParams;
for (auto param : params) {
auto newParam = param;
switch (param.getParameterFlags().getOwnershipSpecifier()) {
case ParamSpecifier::Borrowing:
case ParamSpecifier::Consuming: {
auto flags = param.getParameterFlags()
.withOwnershipSpecifier(ParamSpecifier::Default);
newParams.push_back(param.withFlags(flags));
break;
}
default:
newParams.push_back(newParam);
break;
}
}
auto newExtInfo = funcType->getExtInfo().withRepresentation(
AnyFunctionType::Representation::Swift);
return FunctionType::get(newParams,
funcType->getResult(),
newExtInfo);
}

return std::nullopt;
});
}
Expand Down Expand Up @@ -1060,8 +1085,14 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
// In this case solver would produce 2 solutions: one where `count`
// is a property reference on `[Int]` and another one is tuple access
// for a `count:` element.
if (choice1.isDecl() != choice2.isDecl())
if (choice1.isDecl() != choice2.isDecl()) {
if (cs.isDebugMode()) {
llvm::errs().indent(cs.solverState->getCurrentIndent())
<< "- incomparable\n";
}

return SolutionCompareResult::Incomparable;
}

auto decl1 = choice1.getDecl();
auto dc1 = decl1->getDeclContext();
Expand Down Expand Up @@ -1438,15 +1469,16 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
if (type2Better)
++score2;

// Prefer the unlabeled form of a type.
auto unlabeled1 = getUnlabeledType(type1, cs.getASTContext());
auto unlabeled2 = getUnlabeledType(type2, cs.getASTContext());
if (unlabeled1->isEqual(unlabeled2)) {
if (type1->isEqual(unlabeled1) && !types.Type1WasLabeled) {
// Prefer the "stripped" form of a type. See getStrippedType()
// for the definition.
auto stripped1 = getStrippedType(type1, cs.getASTContext());
auto stripped2 = getStrippedType(type2, cs.getASTContext());
if (stripped1->isEqual(stripped2)) {
if (type1->isEqual(stripped1) && !types.Type1WasLabeled) {
++score1;
continue;
}
if (type2->isEqual(unlabeled2) && !types.Type2WasLabeled) {
if (type2->isEqual(stripped2) && !types.Type2WasLabeled) {
++score2;
continue;
}
Expand Down Expand Up @@ -1527,13 +1559,39 @@ SolutionCompareResult ConstraintSystem::compareSolutions(

// If the scores are different, we have a winner.
if (score1 != score2) {
return score1 > score2? SolutionCompareResult::Better
: SolutionCompareResult::Worse;
if (score1 > score2) {
if (cs.isDebugMode()) {
llvm::errs().indent(cs.solverState->getCurrentIndent())
<< "- better\n";
}

return SolutionCompareResult::Better;
} else {
if (cs.isDebugMode()) {
llvm::errs().indent(cs.solverState->getCurrentIndent())
<< "- worse\n";
}

return SolutionCompareResult::Worse;
}
}

// Neither system wins; report whether they were identical or not.
return identical? SolutionCompareResult::Identical
: SolutionCompareResult::Incomparable;
if (identical) {
if (cs.isDebugMode()) {
llvm::errs().indent(cs.solverState->getCurrentIndent())
<< "- identical\n";
}

return SolutionCompareResult::Identical;
} else {
if (cs.isDebugMode()) {
llvm::errs().indent(cs.solverState->getCurrentIndent())
<< "- incomparable\n";
}

return SolutionCompareResult::Incomparable;
}
}

std::optional<unsigned>
Expand Down
83 changes: 25 additions & 58 deletions test/Constraints/bidirectional_conversions.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
// RUN: %target-typecheck-verify-swift
// REQUIRES: objc_interop

import Foundation
import CoreGraphics

/////////////

Expand All @@ -20,26 +16,6 @@ func foo2(x: (Int, Int)?, y: (x: Int, y: Int)) -> G<(Int, Int)> {
return g
}

func foo3(x: (@convention(block) () -> ())?, y: @escaping () -> ()) -> G<@convention(block) () -> ()> {
let g = G(t: x ?? y)
return g
}

func foo4(x: (() -> ())?, y: @escaping @convention(block) () -> ()) -> G<() -> ()> {
let g = G(t: x ?? y)
return g
}

func foo5(x: CGFloat?, y: Double) -> G<CGFloat> {
let g = G(t: x ?? y)
return g
}

func foo6(x: Double?, y: CGFloat) -> G<Double> {
let g = G(t: x ?? y)
return g
}

/////////////

func id<T>(_: T) -> T {}
Expand All @@ -54,28 +30,6 @@ func bar2(x: (Int, Int)) {
f(id(x))
}

func bar3(x: @escaping () -> ()) {
func f(_: @escaping @convention(block) () -> ()) {}
// FIXME
f(id(x)) // expected-error {{conflicting arguments to generic parameter 'T' ('@convention(block) () -> ()' vs. '() -> ()')}}
}

func bar4(x: @escaping @convention(block) () -> ()) {
func f(_: @escaping () -> ()) {}
// FIXME
f(id(x)) // expected-error {{conflicting arguments to generic parameter 'T' ('() -> ()' vs. '@convention(block) () -> ()')}}
}

func bar5(x: Double) {
func f(_: CGFloat) {}
f(id(x))
}

func bar6(x: CGFloat) {
func f(_: Double) {}
f(id(x))
}

/////////////

func unwrap<T>(_: T?) -> T {}
Expand All @@ -90,23 +44,36 @@ func baz2(x: (Int, Int)?) {
f(unwrap(x))
}

func baz3(x: (() -> ())?) {
func f(_: @escaping @convention(block) () -> ()) {}
f(unwrap(x))
/////////////

func borrowingFn(fn: @escaping (borrowing AnyObject) -> ()) -> (AnyObject) -> () {
return id(id(fn))
}

func baz4(x: (@convention(block) () -> ())?) {
func f(_: @escaping () -> ()) {}
f(unwrap(x))
/////////////

infix operator <+
infix operator >+

protocol P {
static func <+ (lhs: borrowing Self, rhs: borrowing Self)
static func >+ (lhs: borrowing Self, rhs: borrowing Self)
}

func baz5(x: Double?) {
func f(_: CGFloat) {}
f(unwrap(x))
extension P {
static func >+ (lhs: borrowing Self, rhs: borrowing Self) {}
}

func baz6(x: CGFloat?) {
func f(_: Double) {}
f(unwrap(x))
struct S: P {
static func <+ (lhs: Self, rhs: Self) {}
}

let _: (S, S) -> () = false ? (<+) : (>+)

/////////////

struct MyString: Comparable {
static func < (lhs: Self, rhs: Self) -> Bool { fatalError() }
}

let _: (MyString, MyString) -> Bool = false ? (<) : (>)
79 changes: 79 additions & 0 deletions test/Constraints/bidirectional_conversions_objc.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// RUN: %target-typecheck-verify-swift
// REQUIRES: objc_interop

import Foundation
import CoreGraphics

/////////////

struct G<T> {
var t: T
}

func foo3(x: (@convention(block) () -> ())?, y: @escaping () -> ()) -> G<@convention(block) () -> ()> {
let g = G(t: x ?? y)
return g
}

func foo4(x: (() -> ())?, y: @escaping @convention(block) () -> ()) -> G<() -> ()> {
let g = G(t: x ?? y)
return g
}

func foo5(x: CGFloat?, y: Double) -> G<CGFloat> {
let g = G(t: x ?? y)
return g
}

func foo6(x: Double?, y: CGFloat) -> G<Double> {
let g = G(t: x ?? y)
return g
}

/////////////

func id<T>(_: T) -> T {}

func bar3(x: @escaping () -> ()) {
func f(_: @escaping @convention(block) () -> ()) {}
f(id(x))
}

func bar4(x: @escaping @convention(block) () -> ()) {
func f(_: @escaping () -> ()) {}
f(id(x))
}

func bar5(x: Double) {
func f(_: CGFloat) {}
f(id(x))
}

func bar6(x: CGFloat) {
func f(_: Double) {}
f(id(x))
}

/////////////

func unwrap<T>(_: T?) -> T {}

func baz3(x: (() -> ())?) {
func f(_: @escaping @convention(block) () -> ()) {}
f(unwrap(x))
}

func baz4(x: (@convention(block) () -> ())?) {
func f(_: @escaping () -> ()) {}
f(unwrap(x))
}

func baz5(x: Double?) {
func f(_: CGFloat) {}
f(unwrap(x))
}

func baz6(x: CGFloat?) {
func f(_: Double) {}
f(unwrap(x))
}
2 changes: 1 addition & 1 deletion test/expr/closure/closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ do {
let qux: () -> Void

f(qux)
f(id(qux)) // expected-error {{conflicting arguments to generic parameter 'T' ('() -> Void' vs. '@convention(block) () -> Void')}}
f(id(qux))

func forceUnwrap<T>(_: T?) -> T {}

Expand Down