Revert "[ConstraintSystem] Make it possible to infer subtype bindings through argument conversions"

Reverts apple/swift#30006. It caused a regression that we'd like to address before re-landing:

```swift
struct X {
  var cgf: CGFloat
}

func test(x: X?) {
  let _ = (x?.cgf ?? 0) <= 0.5
}
```

This reverts commit 0a6b444b49.
This reverts commit ed255596a6.
This reverts commit 3e01160a2f.
This reverts commit 96297b7e39.

Resolves: rdar://problem/60185506
This commit is contained in:
Pavel Yaskevich
2020-03-07 20:16:09 -08:00
parent c825ed8481
commit 0ecedfa5ea
14 changed files with 71 additions and 104 deletions

View File

@@ -30,17 +30,14 @@ void ConstraintSystem::inferTransitiveSupertypeBindings(
llvm::SmallVector<Constraint *, 4> subtypeOf; llvm::SmallVector<Constraint *, 4> subtypeOf;
// First, let's collect all of the `subtype` constraints associated // First, let's collect all of the `subtype` constraints associated
// with this type variable. // with this type variable.
llvm::copy_if( llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf),
bindings.Sources, std::back_inserter(subtypeOf), [&](const Constraint *constraint) -> bool {
[&](const Constraint *constraint) -> bool { if (constraint->getKind() != ConstraintKind::Subtype)
if (constraint->getKind() != ConstraintKind::Subtype && return false;
constraint->getKind() != ConstraintKind::ArgumentConversion &&
constraint->getKind() != ConstraintKind::OperatorArgumentConversion)
return false;
auto rhs = simplifyType(constraint->getSecondType()); auto rhs = simplifyType(constraint->getSecondType());
return rhs->getAs<TypeVariableType>() == typeVar; return rhs->getAs<TypeVariableType>() == typeVar;
}); });
if (subtypeOf.empty()) if (subtypeOf.empty())
return; return;
@@ -635,7 +632,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
continue; continue;
literalBindings.push_back( literalBindings.push_back(
{defaultType, AllowedBindingKind::Exact, constraint}); {defaultType, AllowedBindingKind::Subtypes, constraint});
continue; continue;
} }
@@ -661,7 +658,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
if (!matched) { if (!matched) {
exactTypes.insert(defaultType->getCanonicalType()); exactTypes.insert(defaultType->getCanonicalType());
literalBindings.push_back( literalBindings.push_back(
{defaultType, AllowedBindingKind::Exact, constraint}); {defaultType, AllowedBindingKind::Subtypes, constraint});
} }
break; break;

View File

@@ -9221,8 +9221,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
// subscript, which requires changes to declaration to become mutable. // subscript, which requires changes to declaration to become mutable.
if (auto last = locator.last()) { if (auto last = locator.last()) {
impact += (last->is<LocatorPathElt::FunctionResult>() || impact += (last->is<LocatorPathElt::FunctionResult>() ||
last->is<LocatorPathElt::SubscriptMember>() || last->is<LocatorPathElt::SubscriptMember>())
last->is<LocatorPathElt::KeyPathDynamicMember>())
? 1 ? 1
: 0; : 0;
} }

View File

@@ -619,15 +619,6 @@ protected:
/// Check whether attempting type variable binding choices should /// Check whether attempting type variable binding choices should
/// be stopped, because optimal solution has already been found. /// be stopped, because optimal solution has already been found.
bool shouldStopAt(const TypeVariableBinding &choice) const override { bool shouldStopAt(const TypeVariableBinding &choice) const override {
if (CS.shouldAttemptFixes()) {
// Let's always attempt default types inferred from literals
// in diagnostic mode because that could lead to better
// diagnostics if the problem is contextual like argument/parameter
// conversion or collection element mismatch.
if (choice.hasDefaultedProtocol())
return false;
}
// If we were able to solve this without considering // If we were able to solve this without considering
// default literals, don't bother looking at default literals. // default literals, don't bother looking at default literals.
return AnySolved && choice.hasDefaultedProtocol() && return AnySolved && choice.hasDefaultedProtocol() &&

View File

@@ -2776,61 +2776,45 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
auto &DE = cs.getASTContext().Diags; auto &DE = cs.getASTContext().Diags;
llvm::SmallDenseMap<TypeVariableType *, llvm::SmallDenseMap<TypeVariableType *, SmallVector<Type, 4>> conflicts;
std::pair<GenericTypeParamType *, SourceLoc>, 4>
genericParams;
// Consider only representative type variables shared across
// all of the solutions.
for (auto *typeVar : cs.getTypeVariables()) {
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
auto *locator = typeVar->getImpl().getLocator();
auto *repr = cs.getRepresentative(typeVar);
// If representative is another generic parameter let's
// use its generic parameter type instead of originator's,
// but it's possible that generic parameter is equated to
// some other type e.g.
//
// func foo<T>(_: T) -> T {}
//
// In this case when reference to function `foo` is "opened"
// type variable representing `T` would be equated to
// type variable representing a result type of the reference.
if (auto *reprGP = repr->getImpl().getGenericParameter())
GP = reprGP;
genericParams[repr] = {GP, locator->getAnchor()->getLoc()}; for (const auto &binding : solutions[0].typeBindings) {
} auto *typeVar = binding.first;
}
llvm::SmallDenseMap<std::pair<GenericTypeParamType *, SourceLoc>, if (!typeVar->getImpl().getGenericParameter())
SmallVector<Type, 4>> continue;
conflicts;
for (const auto &entry : genericParams) {
auto *typeVar = entry.first;
auto GP = entry.second;
llvm::SmallSetVector<Type, 4> arguments; llvm::SmallSetVector<Type, 4> arguments;
for (const auto &solution : solutions) { arguments.insert(binding.second);
auto type = solution.typeBindings.lookup(typeVar);
// Contextual opaque result type is uniquely identified by if (!llvm::all_of(solutions.slice(1), [&](const Solution &solution) {
// declaration it's associated with, so we have to compare auto binding = solution.typeBindings.find(typeVar);
// declarations instead of using pointer equality on such types. if (binding == solution.typeBindings.end())
if (auto *opaque = type->getAs<OpaqueTypeArchetypeType>()) { return false;
auto *decl = opaque->getDecl();
arguments.remove_if([&](Type argType) -> bool { // Contextual opaque result type is uniquely identified by
if (auto *otherOpaque = argType->getAs<OpaqueTypeArchetypeType>()) { // declaration it's associated with, so we have to compare
return decl == otherOpaque->getDecl(); // declarations instead of using pointer equality on such types.
if (auto *opaque =
binding->second->getAs<OpaqueTypeArchetypeType>()) {
auto *decl = opaque->getDecl();
arguments.remove_if([&](Type argType) -> bool {
if (auto *otherOpaque =
argType->getAs<OpaqueTypeArchetypeType>()) {
return decl == otherOpaque->getDecl();
}
return false;
});
} }
return false;
});
}
arguments.insert(type); arguments.insert(binding->second);
return true;
}))
continue;
if (arguments.size() > 1) {
conflicts[typeVar].append(arguments.begin(), arguments.end());
} }
if (arguments.size() > 1)
conflicts[GP].append(arguments.begin(), arguments.end());
} }
auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * { auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * {
@@ -2847,10 +2831,8 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
bool diagnosed = false; bool diagnosed = false;
for (auto &conflict : conflicts) { for (auto &conflict : conflicts) {
SourceLoc loc; auto *typeVar = conflict.first;
GenericTypeParamType *GP; auto *locator = typeVar->getImpl().getLocator();
std::tie(GP, loc) = conflict.first;
auto conflictingArguments = conflict.second; auto conflictingArguments = conflict.second;
llvm::SmallString<64> arguments; llvm::SmallString<64> arguments;
@@ -2875,8 +2857,10 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
}, },
[&OS] { OS << " vs. "; }); [&OS] { OS << " vs. "; });
DE.diagnose(loc, diag::conflicting_arguments_for_generic_parameter, GP, auto *anchor = locator->getAnchor();
OS.str()); DE.diagnose(anchor->getLoc(),
diag::conflicting_arguments_for_generic_parameter,
typeVar->getImpl().getGenericParameter(), OS.str());
diagnosed = true; diagnosed = true;
} }

View File

@@ -50,7 +50,7 @@ useDoubleList([1.0,2,3])
useDoubleList([1.0,2.0,3.0]) useDoubleList([1.0,2.0,3.0])
useIntDict(["Niners" => 31, "Ravens" => 34]) useIntDict(["Niners" => 31, "Ravens" => 34])
useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected element type 'Int'}} useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Int'}}
// <rdar://problem/22333090> QoI: Propagate contextual information in a call to operands // <rdar://problem/22333090> QoI: Propagate contextual information in a call to operands
useDoubleDict(["Niners" => 31, "Ravens" => 34.0]) useDoubleDict(["Niners" => 31, "Ravens" => 34.0])
useDoubleDict(["Niners" => 31.0, "Ravens" => 34]) useDoubleDict(["Niners" => 31.0, "Ravens" => 34])

View File

@@ -456,7 +456,13 @@ extension Collection {
} }
} }
func fn_r28909024(n: Int) { func fn_r28909024(n: Int) {
return (0..<10).r28909024 { // expected-error {{unexpected non-void return value in void function}} expected-note {{did you mean to add a return type?}} // FIXME(diagnostics): Unfortunately there is no easy way to fix this diagnostic issue at the moment
// because the problem is related to ordering of the bindings - we'd attempt to bind result of the expression
// to contextual type of `Void` which prevents solver from discovering correct types for range - 0..<10
// (since both arguments are literal they are ranked lower than contextual type).
//
// Good diagnostic for this is - `unexpected non-void return value in void function`
return (0..<10).r28909024 { // expected-error {{type of expression is ambiguous without more context}}
_ in true _ in true
} }
} }

View File

@@ -42,14 +42,3 @@ extension Int {
var (div, mod) = (9 / 4, 9 % 4) var (div, mod) = (9 / 4, 9 % 4)
// rdar://problem/56212087 - solver fails to infer correct type for a generic parameter (Any vs. String)
func test_transitive_inference_of_default_literal_types() {
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
fatalError()
}
func bar(_: Any?) {}
bar(foo("", "")) // Ok
}

View File

@@ -319,9 +319,8 @@ func foo() {
let j = min(Int(3), Float(2.5)) // expected-error{{conflicting arguments to generic parameter 'T' ('Int' vs. 'Float')}} let j = min(Int(3), Float(2.5)) // expected-error{{conflicting arguments to generic parameter 'T' ('Int' vs. 'Float')}}
let k = min(A(), A()) // expected-error{{global function 'min' requires that 'A' conform to 'Comparable'}} let k = min(A(), A()) // expected-error{{global function 'min' requires that 'A' conform to 'Comparable'}}
let oi : Int? = 5 let oi : Int? = 5
let l = min(3, oi) // expected-error{{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}} let l = min(3, oi) // expected-error{{global function 'min' requires that 'Int?' conform to 'Comparable'}}
// expected-note@-1 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} // expected-note@-1{{wrapped type 'Int' satisfies this requirement}}
// expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
} }
infix operator +& infix operator +&

View File

@@ -1005,7 +1005,7 @@ var fvs_stubMyOwnFatalError: () {
var fvs_forceTryExplicit: String { var fvs_forceTryExplicit: String {
get { "ok" } get { "ok" }
set { set {
return try! failableIdentity("shucks") // expected-error {{unexpected non-void return value in void function}} return try! failableIdentity("shucks") // expected-error {{cannot convert value of type 'String' to expected argument type '()'}}
} }
} }

View File

@@ -600,7 +600,10 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>,
func keypath_with_incorrect_return_type(_ arr: Lens<Array<Int>>) { func keypath_with_incorrect_return_type(_ arr: Lens<Array<Int>>) {
for idx in 0..<arr.count { for idx in 0..<arr.count {
// expected-error@-1 {{cannot convert value of type 'Lens<Int>' to expected argument type 'Int'}} // expected-error@-1 {{protocol 'Sequence' requires that 'Lens<Int>' conform to 'Strideable'}}
// expected-error@-2 {{protocol 'Sequence' requires that 'Lens<Int>.Stride' conform to 'SignedInteger'}}
// expected-error@-3 {{cannot convert value of type 'Int' to expected argument type 'Lens<Int>'}}
// expected-error@-4 {{referencing operator function '..<' on 'Comparable' requires that 'Lens<Int>' conform to 'Comparable'}}
let _ = arr[idx] let _ = arr[idx]
} }
} }

View File

@@ -103,7 +103,7 @@ _ = A<String, Int>(a: "foo", // expected-error {{cannot convert value of type 'S
b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
_ = B(a: 12, b: 42) _ = B(a: 12, b: 42)
_ = B(a: 12, b: 42 as Float) _ = B(a: 12, b: 42 as Float)
_ = B(a: "foo", b: 42) // expected-error {{conflicting arguments to generic parameter 'T1' ('String' vs. 'Int')}} _ = B(a: "foo", b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
_ = C(a: "foo", b: 42) _ = C(a: "foo", b: 42)
_ = C(a: 42, // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} _ = C(a: 42, // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
b: 42) b: 42)

View File

@@ -791,9 +791,8 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange<Int>?) {
// ?? should have lower precedence than range and arithmetic operators. // ?? should have lower precedence than range and arithmetic operators.
let r1 = r ?? (0...42) // ok let r1 = r ?? (0...42) // ok
let r2 = (r ?? 0)...42 // not ok let r2 = (r ?? 0)...42 // not ok: expected-error 2 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange<Int>'}}
// expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange<Int>'}} // expected-error@-1 {{referencing operator function '...' on 'Comparable' requires that 'ClosedRange<Int>' conform to 'Comparable'}}
// expected-error@-2 {{cannot convert value of type 'ClosedRange<Int>' to expected argument type 'Int'}}
let r3 = r ?? 0...42 // parses as the first one, not the second. let r3 = r ?? 0...42 // parses as the first one, not the second.

View File

@@ -173,7 +173,7 @@ takesP1AndP2([Swift.AnyObject & P1 & P2]())
takesP1AndP2([AnyObject & protocol_composition.P1 & P2]()) takesP1AndP2([AnyObject & protocol_composition.P1 & P2]())
takesP1AndP2([AnyObject & P1 & protocol_composition.P2]()) takesP1AndP2([AnyObject & P1 & protocol_composition.P2]())
takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}} takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}}
takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}} expected-error {{cannot call value of non-function type 'Array<_>'}} takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}}
typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}} typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}}
typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}} typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}}

View File

@@ -3,13 +3,13 @@
// RUN: %line-directive %t/main.swift -- %target-swift-frontend -typecheck -verify -swift-version 4.2 %t/main.swift // RUN: %line-directive %t/main.swift -- %target-swift-frontend -typecheck -verify -swift-version 4.2 %t/main.swift
func testUnaryMinusInUnsigned() { func testUnaryMinusInUnsigned() {
var a: UInt8 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt8'}} expected-note * {{}} expected-warning * {{}} var a: UInt8 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt8'}} expected-note * {{}} expected-warning * {{}}
var b: UInt16 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt16'}} expected-note * {{}} expected-warning * {{}} var b: UInt16 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt16'}} expected-note * {{}} expected-warning * {{}}
var c: UInt32 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt32'}} expected-note * {{}} expected-warning * {{}} var c: UInt32 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt32'}} expected-note * {{}} expected-warning * {{}}
var d: UInt64 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt64'}} expected-note * {{}} expected-warning * {{}} var d: UInt64 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt64'}} expected-note * {{}} expected-warning * {{}}
} }
// Int and UInt are not identical to any fixed-size integer type // Int and UInt are not identical to any fixed-size integer type