mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #85933 from slavapestov/fix-ben-regression
Sema: Disambiguate some more bidirectional conversions
This commit is contained in:
@@ -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)
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
@@ -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<unsigned>
|
||||
|
||||
@@ -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<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 {}
|
||||
@@ -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 {}
|
||||
@@ -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
test/Constraints/bidirectional_conversions_objc.swift
Normal file
79
test/Constraints/bidirectional_conversions_objc.swift
Normal file
@@ -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))
|
||||
}
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user