Skip to content

Commit f2a6677

Browse files
committed
[CSOptimizer] Infer argument candidates from calls to Double and CGFloat constructors
Helps situations like `1 + {Double, CGFloat}(...)` by inferring a type for the second operand of `+` based on a type being constructed. Currently limited to Double and CGFloat only since we need to support implicit `Double<->CGFloat` conversion. Helps situations like `1 + CGFloat(...)` by inferring a type for the second operand of `+` based on a type being constructed. Currently limited to known integer, floating-point and CGFloat types since we know how they are structured.
1 parent 59109c2 commit f2a6677

File tree

4 files changed

+44
-0
lines changed

4 files changed

+44
-0
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,10 @@ class TypeVariableType::Implementation {
497497
/// literal (represented by `ArrayExpr` and `DictionaryExpr` in AST).
498498
bool isCollectionLiteralType() const;
499499

500+
/// Determine whether this type variable represents a result type of a
501+
/// function call.
502+
bool isFunctionResult() const;
503+
500504
/// Retrieve the representative of the equivalence class to which this
501505
/// type variable belongs.
502506
///

lib/Sema/CSOptimizer.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,23 @@ static Constraint *determineBestChoicesInContext(
250250
{literal.second.getDefaultType(), /*fromLiteral=*/true});
251251
}
252252
}
253+
254+
// Helps situations like `1 + {Double, CGFloat}(...)` by inferring
255+
// a type for the second operand of `+` based on a type being constructed.
256+
//
257+
// Currently limited to Double and CGFloat only since we need to
258+
// support implicit `Double<->CGFloat` conversion.
259+
if (typeVar->getImpl().isFunctionResult() &&
260+
isOperatorDisjunction(disjunction)) {
261+
auto resultLoc = typeVar->getImpl().getLocator();
262+
if (auto *call = getAsExpr<CallExpr>(resultLoc->getAnchor())) {
263+
if (auto *typeExpr = dyn_cast<TypeExpr>(call->getFn())) {
264+
auto instanceTy = cs.getType(typeExpr)->getMetatypeInstanceType();
265+
if (instanceTy->isDouble() || instanceTy->isCGFloat())
266+
types.push_back({instanceTy, /*fromLiteral=*/false});
267+
}
268+
}
269+
}
253270
} else {
254271
types.push_back({argType, /*fromLiteral=*/false});
255272
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ bool TypeVariableType::Implementation::isCollectionLiteralType() const {
204204
locator->directlyAt<DictionaryExpr>());
205205
}
206206

207+
bool TypeVariableType::Implementation::isFunctionResult() const {
208+
return locator && locator->isLastElement<LocatorPathElt::FunctionResult>();
209+
}
210+
207211
void *operator new(size_t bytes, ConstraintSystem& cs,
208212
size_t alignment) {
209213
return cs.getAllocator().Allocate(bytes, alignment);

test/Constraints/implicit_double_cgfloat_conversion.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,22 @@ func test_init_validation() {
342342
}
343343
}
344344
}
345+
346+
do {
347+
struct G<T> {
348+
init(_: T) {}
349+
}
350+
351+
func round(_: Double) -> Double {}
352+
func round<T: FloatingPoint>(_: T) -> T {}
353+
354+
func test_cgfloat_over_double(withColors colors: Int, size: CGSize) -> G<CGFloat> {
355+
let g = G(1.0 / CGFloat(colors))
356+
return g // Ok
357+
}
358+
359+
func test_no_ambiguity(width: Int, height: Int) -> CGFloat {
360+
let v = round(CGFloat(width / height) * 10) / 10.0
361+
return v // Ok
362+
}
363+
}

0 commit comments

Comments
 (0)