Skip to content

Commit b936900

Browse files
committed
[CSOptimizer] Support non-operator generic choices with simple signatures
If there are no-same type requirements and parameters use either concrete types or generic parameter types directly, the optimizer should be able to handle ranking. Currently candidate arguments are considered in isolation which makes it impossible to deal with same-type requirements and complex generic signatures.
1 parent 2646efa commit b936900

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,47 @@ static bool isArithmeticOperator(ValueDecl *decl) {
117117
return decl->isOperator() && decl->getBaseIdentifier().isArithmeticOperator();
118118
}
119119

120+
/// Generic choices are supported only if they are not complex enough
121+
/// that would they'd require solving to figure out whether they are a
122+
/// potential match or not.
123+
static bool isSupportedGenericOverloadChoice(ValueDecl *decl,
124+
GenericFunctionType *choiceType) {
125+
// Same type requirements cannot be handled because each
126+
// candidate-parameter pair is (currently) considered in isolation.
127+
if (llvm::any_of(choiceType->getRequirements(), [](const Requirement &req) {
128+
switch (req.getKind()) {
129+
case RequirementKind::SameType:
130+
case RequirementKind::SameShape:
131+
return true;
132+
133+
case RequirementKind::Conformance:
134+
case RequirementKind::Superclass:
135+
case RequirementKind::Layout:
136+
return false;
137+
}
138+
}))
139+
return false;
140+
141+
// If there are no same-type requirements, allow signatures
142+
// that use only concrete types or generic parameters directly
143+
// in their parameter positions i.e. `(T, Int)`.
144+
145+
auto *paramList = getParameterList(decl);
146+
if (!paramList)
147+
return false;
148+
149+
return llvm::all_of(paramList->getArray(), [](const ParamDecl *P) {
150+
auto paramType = P->getInterfaceType();
151+
return paramType->is<GenericTypeParamType>() ||
152+
!paramType->hasTypeParameter();
153+
});
154+
}
155+
120156
static bool isSupportedDisjunction(Constraint *disjunction) {
121157
auto choices = disjunction->getNestedConstraints();
122158

123-
if (isSupportedOperator(disjunction))
124-
return true;
159+
if (isOperatorDisjunction(disjunction))
160+
return isSupportedOperator(disjunction);
125161

126162
if (auto *ctor = dyn_cast_or_null<ConstructorDecl>(
127163
getOverloadChoiceDecl(choices.front()))) {
@@ -130,7 +166,7 @@ static bool isSupportedDisjunction(Constraint *disjunction) {
130166
}
131167

132168
// Non-operator disjunctions are supported only if they don't
133-
// have any generic choices.
169+
// have any complex generic choices.
134170
return llvm::all_of(choices, [&](Constraint *choice) {
135171
if (choice->isDisabled())
136172
return true;
@@ -144,7 +180,18 @@ static bool isSupportedDisjunction(Constraint *disjunction) {
144180
if (decl->isImplicitlyUnwrappedOptional())
145181
return false;
146182

147-
return decl->getInterfaceType()->is<FunctionType>();
183+
auto choiceType = decl->getInterfaceType()->getAs<AnyFunctionType>();
184+
if (!choiceType || choiceType->hasError())
185+
return false;
186+
187+
// Non-generic choices are always supported.
188+
if (choiceType->is<FunctionType>())
189+
return true;
190+
191+
if (auto *genericFn = choiceType->getAs<GenericFunctionType>())
192+
return isSupportedGenericOverloadChoice(decl, genericFn);
193+
194+
return false;
148195
}
149196

150197
return false;

validation-test/Sema/implicit_cgfloat_double_conversion_correctness.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ func test_atan_ambiguity(points: (CGPoint, CGPoint)) {
4747
test = atan((points.1.y - points.0.y) / (points.1.x - points.0.x)) // Ok
4848
_ = test
4949
}
50+
51+
func test_ambigity_with_generic_funcs(a: CGFloat, b: CGFloat) -> [CGFloat] {
52+
let result = [round(abs(a - b) * 100) / 100.0]
53+
return result
54+
}

0 commit comments

Comments
 (0)