Skip to content

Commit b926250

Browse files
authored
Merge pull request swiftlang#30006 from xedin/rdar-56212087
[ConstraintSystem] Make it possible to infer subtype bindings through argument conversions
2 parents e35ae37 + 96297b7 commit b926250

File tree

14 files changed

+105
-72
lines changed

14 files changed

+105
-72
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ void ConstraintSystem::inferTransitiveSupertypeBindings(
3030
llvm::SmallVector<Constraint *, 4> subtypeOf;
3131
// First, let's collect all of the `subtype` constraints associated
3232
// with this type variable.
33-
llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf),
34-
[&](const Constraint *constraint) -> bool {
35-
if (constraint->getKind() != ConstraintKind::Subtype)
36-
return false;
37-
38-
auto rhs = simplifyType(constraint->getSecondType());
39-
return rhs->getAs<TypeVariableType>() == typeVar;
40-
});
33+
llvm::copy_if(
34+
bindings.Sources, std::back_inserter(subtypeOf),
35+
[&](const Constraint *constraint) -> bool {
36+
if (constraint->getKind() != ConstraintKind::Subtype &&
37+
constraint->getKind() != ConstraintKind::ArgumentConversion &&
38+
constraint->getKind() != ConstraintKind::OperatorArgumentConversion)
39+
return false;
40+
41+
auto rhs = simplifyType(constraint->getSecondType());
42+
return rhs->getAs<TypeVariableType>() == typeVar;
43+
});
4144

4245
if (subtypeOf.empty())
4346
return;
@@ -618,7 +621,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
618621
continue;
619622

620623
literalBindings.push_back(
621-
{defaultType, AllowedBindingKind::Subtypes, constraint});
624+
{defaultType, AllowedBindingKind::Exact, constraint});
622625
continue;
623626
}
624627

@@ -644,7 +647,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
644647
if (!matched) {
645648
exactTypes.insert(defaultType->getCanonicalType());
646649
literalBindings.push_back(
647-
{defaultType, AllowedBindingKind::Subtypes, constraint});
650+
{defaultType, AllowedBindingKind::Exact, constraint});
648651
}
649652

650653
break;

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9103,7 +9103,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
91039103
// subscript, which requires changes to declaration to become mutable.
91049104
if (auto last = locator.last()) {
91059105
impact += (last->is<LocatorPathElt::FunctionResult>() ||
9106-
last->is<LocatorPathElt::SubscriptMember>())
9106+
last->is<LocatorPathElt::SubscriptMember>() ||
9107+
last->is<LocatorPathElt::KeyPathDynamicMember>())
91079108
? 1
91089109
: 0;
91099110
}

lib/Sema/CSStep.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,15 @@ class TypeVariableStep final : public BindingStep<TypeVarBindingProducer> {
620620
/// Check whether attempting type variable binding choices should
621621
/// be stopped, because optimal solution has already been found.
622622
bool shouldStopAt(const TypeVariableBinding &choice) const override {
623+
if (CS.shouldAttemptFixes()) {
624+
// Let's always attempt default types inferred from literals
625+
// in diagnostic mode because that could lead to better
626+
// diagnostics if the problem is contextual like argument/parameter
627+
// conversion or collection element mismatch.
628+
if (choice.hasDefaultedProtocol())
629+
return false;
630+
}
631+
623632
// If we were able to solve this without considering
624633
// default literals, don't bother looking at default literals.
625634
return AnySolved && choice.hasDefaultedProtocol() &&

lib/Sema/ConstraintSystem.cpp

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,45 +2778,61 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
27782778

27792779
auto &DE = cs.getASTContext().Diags;
27802780

2781-
llvm::SmallDenseMap<TypeVariableType *, SmallVector<Type, 4>> conflicts;
2781+
llvm::SmallDenseMap<TypeVariableType *,
2782+
std::pair<GenericTypeParamType *, SourceLoc>, 4>
2783+
genericParams;
2784+
// Consider only representative type variables shared across
2785+
// all of the solutions.
2786+
for (auto *typeVar : cs.getTypeVariables()) {
2787+
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
2788+
auto *locator = typeVar->getImpl().getLocator();
2789+
auto *repr = cs.getRepresentative(typeVar);
2790+
// If representative is another generic parameter let's
2791+
// use its generic parameter type instead of originator's,
2792+
// but it's possible that generic parameter is equated to
2793+
// some other type e.g.
2794+
//
2795+
// func foo<T>(_: T) -> T {}
2796+
//
2797+
// In this case when reference to function `foo` is "opened"
2798+
// type variable representing `T` would be equated to
2799+
// type variable representing a result type of the reference.
2800+
if (auto *reprGP = repr->getImpl().getGenericParameter())
2801+
GP = reprGP;
2802+
2803+
genericParams[repr] = {GP, locator->getAnchor()->getLoc()};
2804+
}
2805+
}
27822806

2783-
for (const auto &binding : solutions[0].typeBindings) {
2784-
auto *typeVar = binding.first;
2807+
llvm::SmallDenseMap<std::pair<GenericTypeParamType *, SourceLoc>,
2808+
SmallVector<Type, 4>>
2809+
conflicts;
27852810

2786-
if (!typeVar->getImpl().getGenericParameter())
2787-
continue;
2811+
for (const auto &entry : genericParams) {
2812+
auto *typeVar = entry.first;
2813+
auto GP = entry.second;
27882814

27892815
llvm::SmallSetVector<Type, 4> arguments;
2790-
arguments.insert(binding.second);
2791-
2792-
if (!llvm::all_of(solutions.slice(1), [&](const Solution &solution) {
2793-
auto binding = solution.typeBindings.find(typeVar);
2794-
if (binding == solution.typeBindings.end())
2795-
return false;
2796-
2797-
// Contextual opaque result type is uniquely identified by
2798-
// declaration it's associated with, so we have to compare
2799-
// declarations instead of using pointer equality on such types.
2800-
if (auto *opaque =
2801-
binding->second->getAs<OpaqueTypeArchetypeType>()) {
2802-
auto *decl = opaque->getDecl();
2803-
arguments.remove_if([&](Type argType) -> bool {
2804-
if (auto *otherOpaque =
2805-
argType->getAs<OpaqueTypeArchetypeType>()) {
2806-
return decl == otherOpaque->getDecl();
2807-
}
2808-
return false;
2809-
});
2816+
for (const auto &solution : solutions) {
2817+
auto type = solution.typeBindings.lookup(typeVar);
2818+
// Contextual opaque result type is uniquely identified by
2819+
// declaration it's associated with, so we have to compare
2820+
// declarations instead of using pointer equality on such types.
2821+
if (auto *opaque = type->getAs<OpaqueTypeArchetypeType>()) {
2822+
auto *decl = opaque->getDecl();
2823+
arguments.remove_if([&](Type argType) -> bool {
2824+
if (auto *otherOpaque = argType->getAs<OpaqueTypeArchetypeType>()) {
2825+
return decl == otherOpaque->getDecl();
28102826
}
2827+
return false;
2828+
});
2829+
}
28112830

2812-
arguments.insert(binding->second);
2813-
return true;
2814-
}))
2815-
continue;
2816-
2817-
if (arguments.size() > 1) {
2818-
conflicts[typeVar].append(arguments.begin(), arguments.end());
2831+
arguments.insert(type);
28192832
}
2833+
2834+
if (arguments.size() > 1)
2835+
conflicts[GP].append(arguments.begin(), arguments.end());
28202836
}
28212837

28222838
auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * {
@@ -2833,8 +2849,10 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
28332849

28342850
bool diagnosed = false;
28352851
for (auto &conflict : conflicts) {
2836-
auto *typeVar = conflict.first;
2837-
auto *locator = typeVar->getImpl().getLocator();
2852+
SourceLoc loc;
2853+
GenericTypeParamType *GP;
2854+
2855+
std::tie(GP, loc) = conflict.first;
28382856
auto conflictingArguments = conflict.second;
28392857

28402858
llvm::SmallString<64> arguments;
@@ -2859,10 +2877,8 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
28592877
},
28602878
[&OS] { OS << " vs. "; });
28612879

2862-
auto *anchor = locator->getAnchor();
2863-
DE.diagnose(anchor->getLoc(),
2864-
diag::conflicting_arguments_for_generic_parameter,
2865-
typeVar->getImpl().getGenericParameter(), OS.str());
2880+
DE.diagnose(loc, diag::conflicting_arguments_for_generic_parameter, GP,
2881+
OS.str());
28662882
diagnosed = true;
28672883
}
28682884

test/Constraints/array_literal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ useDoubleList([1.0,2,3])
5050
useDoubleList([1.0,2.0,3.0])
5151

5252
useIntDict(["Niners" => 31, "Ravens" => 34])
53-
useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Int'}}
53+
useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected element type 'Int'}}
5454
// <rdar://problem/22333090> QoI: Propagate contextual information in a call to operands
5555
useDoubleDict(["Niners" => 31, "Ravens" => 34.0])
5656
useDoubleDict(["Niners" => 31.0, "Ravens" => 34])

test/Constraints/closures.swift

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

test/Constraints/default_literals.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,14 @@ extension Int {
4242

4343

4444
var (div, mod) = (9 / 4, 9 % 4)
45+
46+
// rdar://problem/56212087 - solver fails to infer correct type for a generic parameter (Any vs. String)
47+
func test_transitive_inference_of_default_literal_types() {
48+
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
49+
fatalError()
50+
}
51+
52+
func bar(_: Any?) {}
53+
54+
bar(foo("", "")) // Ok
55+
}

test/Generics/deduction.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,9 @@ func foo() {
318318
let j = min(Int(3), Float(2.5)) // expected-error{{conflicting arguments to generic parameter 'T' ('Int' vs. 'Float')}}
319319
let k = min(A(), A()) // expected-error{{global function 'min' requires that 'A' conform to 'Comparable'}}
320320
let oi : Int? = 5
321-
let l = min(3, oi) // expected-error{{global function 'min' requires that 'Int?' conform to 'Comparable'}}
322-
// expected-note@-1{{wrapped type 'Int' satisfies this requirement}}
321+
let l = min(3, oi) // expected-error{{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
322+
// expected-note@-1 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
323+
// expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
323324
}
324325

325326
infix operator +&

test/Parse/omit_return.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ var fvs_stubMyOwnFatalError: () {
10051005
var fvs_forceTryExplicit: String {
10061006
get { "ok" }
10071007
set {
1008-
return try! failableIdentity("shucks") // expected-error {{cannot convert value of type 'String' to expected argument type '()'}}
1008+
return try! failableIdentity("shucks") // expected-error {{unexpected non-void return value in void function}}
10091009
}
10101010
}
10111011

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -600,10 +600,7 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>,
600600

601601
func keypath_with_incorrect_return_type(_ arr: Lens<Array<Int>>) {
602602
for idx in 0..<arr.count {
603-
// expected-error@-1 {{protocol 'Sequence' requires that 'Lens<Int>' conform to 'Strideable'}}
604-
// expected-error@-2 {{protocol 'Sequence' requires that 'Lens<Int>.Stride' conform to 'SignedInteger'}}
605-
// expected-error@-3 {{cannot convert value of type 'Int' to expected argument type 'Lens<Int>'}}
606-
// expected-error@-4 {{referencing operator function '..<' on 'Comparable' requires that 'Lens<Int>' conform to 'Comparable'}}
603+
// expected-error@-1 {{cannot convert value of type 'Lens<Int>' to expected argument type 'Int'}}
607604
let _ = arr[idx]
608605
}
609606
}

0 commit comments

Comments
 (0)