Skip to content

Commit

Permalink
Sema: Generalize heuristic in favoredOverDisjunction()
Browse files Browse the repository at this point in the history
  • Loading branch information
slavapestov committed Sep 9, 2024
1 parent b0b5b2a commit 73aa029
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 22 deletions.
52 changes: 31 additions & 21 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,36 @@ bool BindingSet::isViable(PotentialBinding &binding, bool isTransitive) {
return true;
}

static bool hasConversions(Type type) {
if (type->isAnyHashable() || type->isDouble() || type->isCGFloat())
return true;

if (type->getAnyPointerElementType())
return true;

if (auto *structTy = type->getAs<BoundGenericStructType>()) {
if (auto eltTy = structTy->isArrayType()) {
return hasConversions(eltTy);
} else if (auto pair = ConstraintSystem::isDictionaryType(structTy)) {
return hasConversions(pair->second);
} else if (auto eltTy = ConstraintSystem::isSetType(structTy)) {
return hasConversions(*eltTy);
}

return false;
}

if (auto *enumTy = type->getAs<BoundGenericEnumType>()) {
if (enumTy->getOptionalObjectType())
return true;

return false;
}

return !(type->is<StructType>() || type->is<EnumType>() ||
type->is<BuiltinType>() || type->is<ArchetypeType>());
}

bool BindingSet::favoredOverDisjunction(Constraint *disjunction) const {
if (isHole())
return false;
Expand All @@ -1240,30 +1270,10 @@ bool BindingSet::favoredOverDisjunction(Constraint *disjunction) const {
if (binding.Kind == AllowedBindingKind::Supertypes)
return false;

auto type = binding.BindingType;

if (CS.shouldAttemptFixes())
return false;

if (type->isAnyHashable() || type->isDouble() || type->isCGFloat())
return false;

{
PointerTypeKind pointerKind;
if (type->getAnyPointerElementType(pointerKind)) {
switch (pointerKind) {
case PTK_UnsafeRawPointer:
case PTK_UnsafeMutableRawPointer:
return false;

default:
break;
}
}
}

return type->is<StructType>() || type->is<EnumType>() ||
type->is<BuiltinType>();
return !hasConversions(binding.BindingType);
})) {
// Result type of subscript could be l-value so we can't bind it early.
if (!TypeVar->getImpl().isSubscriptResultType() &&
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %target-typecheck-verify-swift -solver-disable-shrink

// Self-contained test case
protocol P1 {}; func f<T: P1>(_: T, _: T) -> T { fatalError() }
protocol P2 {}; func f<T: P2>(_: T, _: T) -> T { fatalError() }
protocol P3 {}; func f<T: P3>(_: T, _: T) -> T { fatalError() }
protocol P4 {}; func f<T: P4>(_: T, _: T) -> T { fatalError() }

func f<T>(_: Array<T>, _: Array<T>) -> Array<T> { fatalError() }

let fn1: (_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) -> Array<Int> = {
f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f($0, $1), $2), $3), $4), $5), $6), $7), $8), $9), $10), $11), $12), $13), $14), $15), $16), $17), $18), $19)
}

let fn2: (_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) -> Array<Int> = {
f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f([$0], [$1]), [$2]), [$3]), [$4]), [$5]), [$6]), [$7]), [$8]), [$9]), [$10]), [$11]), [$12]), [$13]), [$14]), [$15]), [$16]), [$17]), [$18]), [$19])
}

let x1: Array<Int> = f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f([0], [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0]), [0])

// Same setup with standard library operator
let fn3: (_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) -> Array<Int> = {
$0 + $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10 + $11 + $12 + $13 + $14 + $15 + $16 + $17 + $18 + $19
}

let fn4: (_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) -> Array<Int> = {
[$0] + [$1] + [$2] + [$3] + [$4] + [$5] + [$6] + [$7] + [$8] + [$9] + [$10] + [$11] + [$12] + [$13] + [$14] + [$15] + [$16] + [$17] + [$18] + [$19]
}

let x2: Array<Int> = [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0] + [0]
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
func method(_ arg: String, body: () -> [String]) {}

func test(str: String, properties: [String]) {
// expected-error@+1 {{the compiler is unable to type-check this expression in reasonable time}}
method(str + "" + str + "") {
properties.map { param in
"" + param + "" + param + "" + param + ""
Expand Down

0 comments on commit 73aa029

Please sign in to comment.