Skip to content

Commit a907a15

Browse files
authored
Merge pull request swiftlang#32821 from xedin/improve-typevar-bindings
[CSBindings] Split type variable binding inference into phases
2 parents a24f5d3 + 7f65620 commit a907a15

15 files changed

+423
-316
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 334 additions & 272 deletions
Large diffs are not rendered by default.

lib/Sema/CSSimplify.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4232,6 +4232,12 @@ bool ConstraintSystem::repairFailures(
42324232
if (hasFixFor(loc, FixKind::ContextualMismatch))
42334233
return true;
42344234

4235+
if (contextualType->isVoid() &&
4236+
getContextualTypePurpose(anchor) == CTP_ReturnStmt) {
4237+
conversionsOrFixes.push_back(RemoveReturn::create(*this, lhs, loc));
4238+
break;
4239+
}
4240+
42354241
conversionsOrFixes.push_back(
42364242
ContextualMismatch::create(*this, lhs, rhs, loc));
42374243
break;

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2380,7 +2380,7 @@ void DisjunctionChoice::propagateConversionInfo(ConstraintSystem &cs) const {
23802380
if (typeVar->getImpl().getFixedType(nullptr))
23812381
return;
23822382

2383-
auto bindings = cs.getPotentialBindings(typeVar);
2383+
auto bindings = cs.inferBindingsFor(typeVar);
23842384
if (bindings.InvolvesTypeVariables || bindings.Bindings.size() != 1)
23852385
return;
23862386

lib/Sema/ConstraintGraph.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ bool ConstraintGraph::contractEdges() {
11161116
// us enough information to decided on l-valueness.
11171117
if (isParamBindingConstraint && tyvar1->getImpl().canBindToInOut()) {
11181118
bool isNotContractable = true;
1119-
if (auto bindings = CS.getPotentialBindings(tyvar1)) {
1119+
if (auto bindings = CS.inferBindingsFor(tyvar1)) {
11201120
// Holes can't be contracted.
11211121
if (bindings.IsHole)
11221122
continue;

lib/Sema/ConstraintSystem.h

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4425,6 +4425,12 @@ class ConstraintSystem {
44254425
/// The set of potential bindings.
44264426
SmallVector<PotentialBinding, 4> Bindings;
44274427

4428+
/// The set of protocol requirements placed on this type variable.
4429+
llvm::TinyPtrVector<Constraint *> Protocols;
4430+
4431+
/// The set of constraints which would be used to infer default types.
4432+
llvm::TinyPtrVector<Constraint *> Defaults;
4433+
44284434
/// Whether these bindings should be delayed until the rest of the
44294435
/// constraint system is considered "fully bound".
44304436
bool FullyBound = false;
@@ -4559,6 +4565,35 @@ class ConstraintSystem {
45594565
/// if it has only concrete types or would resolve a closure.
45604566
bool favoredOverDisjunction(Constraint *disjunction) const;
45614567

4568+
/// Detect `subtype` relationship between two type variables and
4569+
/// attempt to infer supertype bindings transitively e.g.
4570+
///
4571+
/// Given A <: T1 <: T2 transitively A <: T2
4572+
///
4573+
/// Which gives us a new (superclass A) binding for T2 as well as T1.
4574+
///
4575+
/// \param cs The constraint system this type variable is associated with.
4576+
///
4577+
/// \param inferredBindings The set of all bindings inferred for type
4578+
/// variables in the workset.
4579+
void inferTransitiveBindings(
4580+
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes,
4581+
const llvm::SmallDenseMap<TypeVariableType *,
4582+
ConstraintSystem::PotentialBindings>
4583+
&inferredBindings);
4584+
4585+
/// Infer bindings based on any protocol conformances that have default
4586+
/// types.
4587+
void inferDefaultTypes(ConstraintSystem &cs,
4588+
llvm::SmallPtrSetImpl<CanType> &existingTypes);
4589+
4590+
/// Finalize binding computation for this type variable by
4591+
/// inferring bindings from context e.g. transitive bindings.
4592+
void finalize(ConstraintSystem &cs,
4593+
const llvm::SmallDenseMap<TypeVariableType *,
4594+
ConstraintSystem::PotentialBindings>
4595+
&inferredBindings);
4596+
45624597
void dump(llvm::raw_ostream &out,
45634598
unsigned indent = 0) const LLVM_ATTRIBUTE_USED {
45644599
out.indent(indent);
@@ -4619,31 +4654,19 @@ class ConstraintSystem {
46194654

46204655
Optional<Type> checkTypeOfBinding(TypeVariableType *typeVar, Type type) const;
46214656
Optional<PotentialBindings> determineBestBindings();
4657+
4658+
/// Infer bindings for the given type variable based on current
4659+
/// state of the constraint system.
4660+
PotentialBindings inferBindingsFor(TypeVariableType *typeVar);
4661+
4662+
private:
46224663
Optional<ConstraintSystem::PotentialBinding>
46234664
getPotentialBindingForRelationalConstraint(
46244665
PotentialBindings &result, Constraint *constraint,
46254666
bool &hasDependentMemberRelationalConstraints,
4626-
bool &hasNonDependentMemberRelationalConstraints,
4627-
bool &addOptionalSupertypeBindings) const;
4667+
bool &hasNonDependentMemberRelationalConstraints) const;
46284668
PotentialBindings getPotentialBindings(TypeVariableType *typeVar) const;
46294669

4630-
/// Detect `subtype` relationship between two type variables and
4631-
/// attempt to infer supertype bindings transitively e.g.
4632-
///
4633-
/// Given A <: T1 <: T2 transitively A <: T2
4634-
///
4635-
/// Which gives us a new (superclass A) binding for T2 as well as T1.
4636-
///
4637-
/// \param inferredBindings The set of all bindings inferred for type
4638-
/// variables in the workset.
4639-
/// \param bindings The type variable we aim to infer new supertype
4640-
/// bindings for.
4641-
void inferTransitiveSupertypeBindings(
4642-
const llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
4643-
&inferredBindings,
4644-
PotentialBindings &bindings);
4645-
4646-
private:
46474670
/// Add a constraint to the constraint system.
46484671
SolutionKind addConstraintImpl(ConstraintKind kind, Type first, Type second,
46494672
ConstraintLocatorBuilder locator,

test/Constraints/array_literal.swift

Lines changed: 2 additions & 3 deletions
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])
@@ -328,7 +328,6 @@ protocol P { }
328328
struct PArray<T> { }
329329

330330
extension PArray : ExpressibleByArrayLiteral where T: P {
331-
// expected-note@-1 {{requirement from conditional conformance of 'PArray<String>' to 'ExpressibleByArrayLiteral'}}
332331
typealias ArrayLiteralElement = T
333332

334333
init(arrayLiteral elements: T...) { }
@@ -338,7 +337,7 @@ extension Int: P { }
338337

339338
func testConditional(i: Int, s: String) {
340339
let _: PArray<Int> = [i, i, i]
341-
let _: PArray<String> = [s, s, s] // expected-error{{generic struct 'PArray' requires that 'String' conform to 'P'}}
340+
let _: PArray<String> = [s, s, s] // expected-error{{cannot convert value of type '[String]' to specified type 'PArray<String>'}}
342341
}
343342

344343

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/construction.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,14 @@ func sr_10837() {
254254
}
255255
}
256256
}
257+
258+
// To make sure that hack related to type variable bindings works as expected we need to test
259+
// that in the following case result of a call to `reduce` maintains optionality.
260+
func test_that_optionality_of_closure_result_is_preserved() {
261+
struct S {}
262+
263+
let arr: [S?] = []
264+
let _: [S]? = arr.reduce([], { (a: [S]?, s: S?) -> [S]? in
265+
a.flatMap { (group: [S]) -> [S]? in s.map { group + [$0] } } // Ok
266+
})
267+
}

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func r17020197(_ x : Int?, y : Int) {
207207

208208
// <rdar://problem/20714480> QoI: Boolean expr not treated as Bool type when function return type is different
209209
func validateSaveButton(_ text: String) {
210-
return (text.count > 0) ? true : false // expected-error {{unexpected non-void return value in void function}}
210+
return (text.count > 0) ? true : false // expected-error {{unexpected non-void return value in void function}} expected-note {{did you mean to add a return type?}}
211211
}
212212

213213
// <rdar://problem/20201968> QoI: poor diagnostic when calling a class method via a metatype

test/Constraints/generics.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,3 +846,15 @@ func test_dictionary_with_generic_mismatch_in_key_or_value() {
846846
let _: [S<Bool>: Int] = [S<Int>(): 42]
847847
// expected-error@-1 {{cannot convert value of type 'S<Int>' to expected dictionary key type 'S<Bool>'}}
848848
}
849+
850+
851+
// rdar://problem/56212087 - unable to infer type for generic parameter `T`
852+
func rdar56212087() {
853+
func setValue(_: Any?, forKey: String) {}
854+
855+
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
856+
fatalError()
857+
}
858+
859+
setValue(foo("", ""), forKey: "") // Ok (T is inferred as a `String` instead of `Any?`)
860+
}

0 commit comments

Comments
 (0)