mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Revert "[CSSolver] Use correct locator when matching function result types re…"
This commit is contained in:
@@ -1573,9 +1573,6 @@ class ResultPlanner {
|
|||||||
///
|
///
|
||||||
/// Valid: reabstraction info, InnerResult, OuterResult.
|
/// Valid: reabstraction info, InnerResult, OuterResult.
|
||||||
ReabstractDirectToDirect,
|
ReabstractDirectToDirect,
|
||||||
|
|
||||||
/// Ignore the next direct inner result, since the outer is 'Void'.
|
|
||||||
IgnoreDirectResult,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Operation(Kind kind) : TheKind(kind) {}
|
Operation(Kind kind) : TheKind(kind) {}
|
||||||
@@ -1720,24 +1717,6 @@ private:
|
|||||||
SILResultInfo outerResult,
|
SILResultInfo outerResult,
|
||||||
SILValue optOuterResultAddr);
|
SILValue optOuterResultAddr);
|
||||||
|
|
||||||
void planIgnoredResult(AbstractionPattern innerOrigType,
|
|
||||||
CanType innerSubstType, PlanData &planData) {
|
|
||||||
if (innerOrigType.isTuple()) {
|
|
||||||
auto innerSubstTuple = cast<TupleType>(innerSubstType);
|
|
||||||
for (unsigned i = 0, n = innerSubstTuple->getNumElements(); i != n; ++i)
|
|
||||||
planIgnoredResult(innerOrigType.getTupleElementType(i),
|
|
||||||
innerSubstTuple.getElementType(i), planData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto innerResult = claimNextInnerResult(planData);
|
|
||||||
if (innerResult.isFormalIndirect() &&
|
|
||||||
SGF.silConv.isSILIndirect(innerResult))
|
|
||||||
(void)addInnerIndirectResultTemporary(planData, innerResult);
|
|
||||||
else
|
|
||||||
addIgnoreDirectResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Claim the next inner result from the plan data.
|
/// Claim the next inner result from the plan data.
|
||||||
SILResultInfo claimNextInnerResult(PlanData &data) {
|
SILResultInfo claimNextInnerResult(PlanData &data) {
|
||||||
return claimNext(data.InnerResults);
|
return claimNext(data.InnerResults);
|
||||||
@@ -1887,10 +1866,6 @@ private:
|
|||||||
op.OuterOrigType = outerOrigType;
|
op.OuterOrigType = outerOrigType;
|
||||||
op.OuterSubstType = outerSubstType;
|
op.OuterSubstType = outerSubstType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addIgnoreDirectResult() {
|
|
||||||
(void)addOperation(Operation::IgnoreDirectResult);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
@@ -1901,13 +1876,6 @@ void ResultPlanner::plan(AbstractionPattern innerOrigType,
|
|||||||
AbstractionPattern outerOrigType,
|
AbstractionPattern outerOrigType,
|
||||||
CanType outerSubstType,
|
CanType outerSubstType,
|
||||||
PlanData &planData) {
|
PlanData &planData) {
|
||||||
// Conversion from `() -> T` to `() -> Void` is allowed when
|
|
||||||
// the argument is a closure.
|
|
||||||
if (!innerSubstType->isVoid() && outerSubstType->isVoid()) {
|
|
||||||
planIgnoredResult(innerOrigType, innerSubstType, planData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The substituted types must match up in tuple-ness and arity.
|
// The substituted types must match up in tuple-ness and arity.
|
||||||
assert(
|
assert(
|
||||||
isa<TupleType>(innerSubstType) == isa<TupleType>(outerSubstType) ||
|
isa<TupleType>(innerSubstType) == isa<TupleType>(outerSubstType) ||
|
||||||
@@ -2616,10 +2584,6 @@ void ResultPlanner::execute(ArrayRef<SILValue> innerDirectResults,
|
|||||||
case Operation::InjectOptionalIndirect:
|
case Operation::InjectOptionalIndirect:
|
||||||
SGF.B.createInjectEnumAddr(Loc, op.OuterResultAddr, op.SomeDecl);
|
SGF.B.createInjectEnumAddr(Loc, op.OuterResultAddr, op.SomeDecl);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case Operation::IgnoreDirectResult:
|
|
||||||
(void)claimNext(innerDirectResults);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
llvm_unreachable("bad operation kind");
|
llvm_unreachable("bad operation kind");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1007,32 +1007,14 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
|
|||||||
// Compare the type variable bindings.
|
// Compare the type variable bindings.
|
||||||
auto &tc = cs.getTypeChecker();
|
auto &tc = cs.getTypeChecker();
|
||||||
for (auto &binding : diff.typeBindings) {
|
for (auto &binding : diff.typeBindings) {
|
||||||
auto type1 = binding.bindings[idx1];
|
|
||||||
auto type2 = binding.bindings[idx2];
|
|
||||||
|
|
||||||
auto &impl = binding.typeVar->getImpl();
|
|
||||||
|
|
||||||
if (auto *locator = impl.getLocator()) {
|
|
||||||
auto path = locator->getPath();
|
|
||||||
if (!path.empty() &&
|
|
||||||
path.back().getKind() == ConstraintLocator::ClosureResult) {
|
|
||||||
// Since we support `() -> T` to `() -> Void` and
|
|
||||||
// `() -> Never` to `() -> T` conversions, it's always
|
|
||||||
// preferable to pick `T` rather than `Never` with
|
|
||||||
// all else being equal.
|
|
||||||
if (type2->isUninhabited())
|
|
||||||
++score1;
|
|
||||||
|
|
||||||
if (type1->isUninhabited())
|
|
||||||
++score2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the type variable isn't one for which we should be looking at the
|
// If the type variable isn't one for which we should be looking at the
|
||||||
// bindings, don't.
|
// bindings, don't.
|
||||||
if (!impl.prefersSubtypeBinding())
|
if (!binding.typeVar->getImpl().prefersSubtypeBinding())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
auto type1 = binding.bindings[idx1];
|
||||||
|
auto type2 = binding.bindings[idx2];
|
||||||
|
|
||||||
// If the types are equivalent, there's nothing more to do.
|
// If the types are equivalent, there's nothing more to do.
|
||||||
if (type1->isEqual(type2))
|
if (type1->isEqual(type2))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1212,8 +1212,10 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
// Result type can be covariant (or equal).
|
// Result type can be covariant (or equal).
|
||||||
return matchTypes(func1->getResult(), func2->getResult(), subKind, subflags,
|
return matchTypes(func1->getResult(), func2->getResult(), subKind,
|
||||||
locator.withPathElement(ConstraintLocator::FunctionResult));
|
subflags,
|
||||||
|
locator.withPathElement(
|
||||||
|
ConstraintLocator::FunctionResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstraintSystem::TypeMatchResult
|
ConstraintSystem::TypeMatchResult
|
||||||
@@ -1499,8 +1501,6 @@ ConstraintSystem::TypeMatchResult
|
|||||||
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
||||||
TypeMatchOptions flags,
|
TypeMatchOptions flags,
|
||||||
ConstraintLocatorBuilder locator) {
|
ConstraintLocatorBuilder locator) {
|
||||||
auto origType1 = type1;
|
|
||||||
|
|
||||||
bool isArgumentTupleConversion
|
bool isArgumentTupleConversion
|
||||||
= kind == ConstraintKind::ArgumentTupleConversion ||
|
= kind == ConstraintKind::ArgumentTupleConversion ||
|
||||||
kind == ConstraintKind::OperatorArgumentTupleConversion;
|
kind == ConstraintKind::OperatorArgumentTupleConversion;
|
||||||
@@ -2243,32 +2243,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
|||||||
// Allow '() -> T' to '() -> ()' and '() -> Never' to '() -> T' for closure
|
// Allow '() -> T' to '() -> ()' and '() -> Never' to '() -> T' for closure
|
||||||
// literals.
|
// literals.
|
||||||
if (auto elt = locator.last()) {
|
if (auto elt = locator.last()) {
|
||||||
auto isClosureResult = [&]() {
|
if (elt->getKind() == ConstraintLocator::ClosureResult) {
|
||||||
if (elt->getKind() == ConstraintLocator::ClosureResult)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If constraint is matching function results where
|
|
||||||
// left-hand side is a 'closure result' we need to allow
|
|
||||||
// certain implicit conversions.
|
|
||||||
if (elt->getKind() != ConstraintLocator::FunctionResult)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (auto *typeVar = origType1->getAs<TypeVariableType>()) {
|
|
||||||
auto *locator = typeVar->getImpl().getLocator();
|
|
||||||
if (!locator)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto path = locator->getPath();
|
|
||||||
if (path.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return path.back().getKind() == ConstraintLocator::ClosureResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isClosureResult()) {
|
|
||||||
if (concrete && kind >= ConstraintKind::Subtype &&
|
if (concrete && kind >= ConstraintKind::Subtype &&
|
||||||
(type1->isUninhabited() || type2->isVoid())) {
|
(type1->isUninhabited() || type2->isVoid())) {
|
||||||
increaseScore(SK_FunctionConversion);
|
increaseScore(SK_FunctionConversion);
|
||||||
|
|||||||
@@ -630,6 +630,7 @@ func rdar33429010_2() {
|
|||||||
let iter = I_33429010()
|
let iter = I_33429010()
|
||||||
var acc: Int = 0 // expected-warning {{}}
|
var acc: Int = 0 // expected-warning {{}}
|
||||||
let _: Int = AnySequence { iter }.rdar33429010(into: acc, { $0 + $1 })
|
let _: Int = AnySequence { iter }.rdar33429010(into: acc, { $0 + $1 })
|
||||||
|
// expected-warning@-1 {{result of operator '+' is unused}}
|
||||||
let _: Int = AnySequence { iter }.rdar33429010(into: acc, { $0.rdar33429010_incr($1) })
|
let _: Int = AnySequence { iter }.rdar33429010(into: acc, { $0.rdar33429010_incr($1) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,38 +652,3 @@ func rdar36054961() {
|
|||||||
str.replaceSubrange(range, with: str[range].reversed())
|
str.replaceSubrange(range, with: str[range].reversed())
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol P_37790062 {
|
|
||||||
associatedtype T
|
|
||||||
var elt: T { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
func rdar37790062() {
|
|
||||||
struct S<T> {
|
|
||||||
init(_ a: () -> T, _ b: () -> T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class C1 : P_37790062 {
|
|
||||||
typealias T = Int
|
|
||||||
var elt: T { return 42 }
|
|
||||||
}
|
|
||||||
|
|
||||||
class C2 : P_37790062 {
|
|
||||||
typealias T = (String, Int, Void)
|
|
||||||
var elt: T { return ("question", 42, ()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
func foo() -> Int { return 42 }
|
|
||||||
func bar() -> Void {}
|
|
||||||
func baz() -> (String, Int) { return ("question", 42) }
|
|
||||||
func bzz<T>(_ a: T) -> T { return a }
|
|
||||||
func faz<T: P_37790062>(_ a: T) -> T.T { return a.elt }
|
|
||||||
|
|
||||||
_ = S({ foo() }, { bar() }) // Ok, should infer T to be 'Void'
|
|
||||||
_ = S({ baz() }, { bar() }) // Ok, should infer T to be 'Void'
|
|
||||||
_ = S({ bzz(("question", 42)) }, { bar() }) // Ok
|
|
||||||
_ = S({ bzz(String.self) }, { bar() }) // Ok
|
|
||||||
_ = S({ bzz(((), (()))) }, { bar() }) // Ok
|
|
||||||
_ = S({ bzz(C1()) }, { bar() }) // Ok
|
|
||||||
_ = S({ faz(C2()) }, { bar() }) // Ok
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
// RUN: %target-typecheck-verify-swift
|
|
||||||
|
|
||||||
protocol A {
|
|
||||||
associatedtype V
|
|
||||||
associatedtype E: Error
|
|
||||||
|
|
||||||
init(value: V)
|
|
||||||
init(error: E)
|
|
||||||
|
|
||||||
func foo<U>(value: (V) -> U, error: (E) -> U) -> U
|
|
||||||
}
|
|
||||||
|
|
||||||
enum R<T, E: Error> : A {
|
|
||||||
case foo(T)
|
|
||||||
case bar(E)
|
|
||||||
|
|
||||||
init(value: T) { self = .foo(value) }
|
|
||||||
init(error: E) { self = .bar(error) }
|
|
||||||
|
|
||||||
func foo<R>(value: (T) -> R, error: (E) -> R) -> R {
|
|
||||||
fatalError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol P {
|
|
||||||
associatedtype V
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
func baz(callback: @escaping (V) -> Void) -> Self
|
|
||||||
}
|
|
||||||
|
|
||||||
class C<V> : P {
|
|
||||||
func baz(callback: @escaping (V) -> Void) -> Self { return self }
|
|
||||||
}
|
|
||||||
class D<T, E: Error> : C<R<T, E>> {
|
|
||||||
init(fn: (_ ret: @escaping (V) -> Void) -> Void) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension A where V: P, V.V: A, E == V.V.E {
|
|
||||||
func bar() -> D<V.V.V, V.V.E> {
|
|
||||||
return D { complete in
|
|
||||||
foo(value: { promise in promise.baz { result in } },
|
|
||||||
error: { complete(R(error: $0)) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,15 +24,13 @@ public func test(_ dict: NSDictionary) {
|
|||||||
// popq %rbp ;<== Blocks the handshake from objc_autoreleaseReturnValue
|
// popq %rbp ;<== Blocks the handshake from objc_autoreleaseReturnValue
|
||||||
// jmp 0x01ec20 ; symbol stub for: objc_retainAutoreleasedReturnValue
|
// jmp 0x01ec20 ; symbol stub for: objc_retainAutoreleasedReturnValue
|
||||||
|
|
||||||
// CHECK-LABEL: define {{.*}}swiftcc %TSo12NSEnumeratorC* @"$S34objc_retainAutoreleasedReturnValue4testyySo12NSDictionaryCFSo12NSEnumeratorCADXEfU_"(%TSo12NSDictionaryC*)
|
// CHECK-LABEL: define {{.*}}swiftcc void @"$S34objc_retainAutoreleasedReturnValue4testyySo12NSDictionaryCFyADXEfU_"(%TSo12NSDictionaryC*)
|
||||||
// CHECK: entry:
|
// CHECK: entry:
|
||||||
// CHECK: call {{.*}}@objc_msgSend
|
// CHECK: call {{.*}}@objc_msgSend
|
||||||
// CHECK: notail call i8* @objc_retainAutoreleasedReturnValue
|
// CHECK: notail call i8* @objc_retainAutoreleasedReturnValue
|
||||||
// CHECK: ret %TSo12NSEnumeratorC*
|
// CHECK: ret void
|
||||||
|
|
||||||
// CHECK-LABEL: define {{.*}}swiftcc void @"$SSo12NSDictionaryCSo12NSEnumeratorCIgxo_ABIegx_TR"(%TSo12NSDictionaryC*, i8*, %swift.opaque*)
|
// OPT-LABEL: define {{.*}}swiftcc void @"$S34objc_retainAutoreleasedReturnValue4testyySo12NSDictionaryCFyADXEfU_"(%TSo12NSDictionaryC*)
|
||||||
|
|
||||||
// OPT-LABEL: define {{.*}}swiftcc void @"$S34objc_retainAutoreleasedReturnValue10useClosureyySo12NSDictionaryC_yADXEtF06$SSo12h44CSo12NSEnumeratorCIgxo_ABIegx_TR049$S34objc_bcD42Value4testyySo12a6CFSo12B8CADXEfU_Tf3npf_nTf1nc_nTf4g_n"(%TSo12NSDictionaryC*)
|
|
||||||
// OPT: entry:
|
// OPT: entry:
|
||||||
// OPT: call {{.*}}@objc_msgSend
|
// OPT: call {{.*}}@objc_msgSend
|
||||||
// OPT: notail call i8* @objc_retainAutoreleasedReturnValue
|
// OPT: notail call i8* @objc_retainAutoreleasedReturnValue
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ func rdar19179412() -> (Int) -> Int {
|
|||||||
func takesVoidFunc(_ f: () -> ()) {}
|
func takesVoidFunc(_ f: () -> ()) {}
|
||||||
var i: Int = 1
|
var i: Int = 1
|
||||||
|
|
||||||
|
// expected-warning @+1 {{expression of type 'Int' is unused}}
|
||||||
takesVoidFunc({i})
|
takesVoidFunc({i})
|
||||||
// expected-warning @+1 {{expression of type 'Int' is unused}}
|
// expected-warning @+1 {{expression of type 'Int' is unused}}
|
||||||
var f1: () -> () = {i}
|
var f1: () -> () = {i}
|
||||||
|
|||||||
Reference in New Issue
Block a user