diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index 9830c66dbe91e..8569c77ff39e8 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -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 { if (auto *tupleType = dyn_cast(type)) { if (tupleType->getNumElements() == 1) @@ -866,6 +866,31 @@ static Type getUnlabeledType(Type type, ASTContext &ctx) { return TupleType::get(elts, ctx); } + if (auto *funcType = dyn_cast(type)) { + auto params = funcType->getParams(); + SmallVector 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; }); } @@ -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(); @@ -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; } @@ -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 diff --git a/test/Constraints/bidirectional_conversions.swift b/test/Constraints/bidirectional_conversions.swift index 43620893f9693..18612106a1eb8 100644 --- a/test/Constraints/bidirectional_conversions.swift +++ b/test/Constraints/bidirectional_conversions.swift @@ -1,8 +1,4 @@ // RUN: %target-typecheck-verify-swift -// REQUIRES: objc_interop - -import Foundation -import CoreGraphics ///////////// @@ -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 { - let g = G(t: x ?? y) - return g -} - -func foo6(x: Double?, y: CGFloat) -> G { - let g = G(t: x ?? y) - return g -} - ///////////// func id(_: T) -> T {} @@ -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 {} @@ -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 ? (<) : (>) diff --git a/test/Constraints/bidirectional_conversions_objc.swift b/test/Constraints/bidirectional_conversions_objc.swift new file mode 100644 index 0000000000000..72b4f10aeef90 --- /dev/null +++ b/test/Constraints/bidirectional_conversions_objc.swift @@ -0,0 +1,79 @@ +// RUN: %target-typecheck-verify-swift +// REQUIRES: objc_interop + +import Foundation +import CoreGraphics + +///////////// + +struct G { + 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 { + let g = G(t: x ?? y) + return g +} + +func foo6(x: Double?, y: CGFloat) -> G { + let g = G(t: x ?? y) + return g +} + +///////////// + +func id(_: 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 {} + +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)) +} \ No newline at end of file diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index b8af7e06c653c..e421758544f59 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -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 {}