-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[SE-0253] Introduce callables. #24299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
932f108
4cce21f
d4737db
518bda2
9695a26
c744806
e213836
35607ed
8dcd1c6
4cb7ebf
cebbd63
0733cc0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5987,6 +5987,7 @@ ConstraintSystem::simplifyApplicableFnConstraint( | |
Type type2, | ||
TypeMatchOptions flags, | ||
ConstraintLocatorBuilder locator) { | ||
auto &ctx = getASTContext(); | ||
|
||
// By construction, the left hand side is a type that looks like the | ||
// following: $T1 -> $T2. | ||
|
@@ -6011,6 +6012,16 @@ ConstraintSystem::simplifyApplicableFnConstraint( | |
} | ||
} | ||
|
||
// Before stripping lvalue-ness and optional types, save the original second | ||
// type for handling `func callAsFunction` and `@dynamicCallable` | ||
// applications. This supports the following cases: | ||
// - Generating constraints for `mutating func callAsFunction`. The nominal | ||
// type (`type2`) should be an lvalue type. | ||
// - Extending `Optional` itself with `func callAsFunction` or | ||
// `@dynamicCallable` functionality. Optional types are stripped below if | ||
// `shouldAttemptFixes()` is true. | ||
auto origLValueType2 = | ||
getFixedTypeRecursive(type2, flags, /*wantRValue=*/false); | ||
// Drill down to the concrete type on the right hand side. | ||
type2 = getFixedTypeRecursive(type2, flags, /*wantRValue=*/true); | ||
auto desugar2 = type2->getDesugaredType(); | ||
|
@@ -6080,9 +6091,34 @@ ConstraintSystem::simplifyApplicableFnConstraint( | |
ConstraintLocatorBuilder outerLocator = | ||
getConstraintLocator(anchor, parts, locator.getSummaryFlags()); | ||
|
||
// Before stripping optional types, save original type for handling | ||
// @dynamicCallable applications. This supports the fringe case where | ||
// `Optional` itself is extended with @dynamicCallable functionality. | ||
// Handle applications of types with `callAsFunction` methods. | ||
// Do this before stripping optional types below, when `shouldAttemptFixes()` | ||
// is true. | ||
auto hasCallAsFunctionMethods = | ||
desugar2->mayHaveMembers() && | ||
llvm::any_of(lookupMember(desugar2, DeclName(ctx.Id_callAsFunction)), | ||
[](LookupResultEntry entry) { | ||
return isa<FuncDecl>(entry.getValueDecl()); | ||
}); | ||
if (hasCallAsFunctionMethods) { | ||
auto memberLoc = getConstraintLocator( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that usages of @xedin: could you please check these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for Regarding |
||
outerLocator.withPathElement(ConstraintLocator::Member)); | ||
// Add a `callAsFunction` member constraint, binding the member type to a | ||
// type variable. | ||
auto memberTy = createTypeVariable(memberLoc, /*options=*/0); | ||
// TODO: Revisit this if `static func callAsFunction` is to be supported. | ||
// Static member constraint requires `FunctionRefKind::DoubleApply`. | ||
addValueMemberConstraint(origLValueType2, DeclName(ctx.Id_callAsFunction), | ||
memberTy, DC, FunctionRefKind::SingleApply, | ||
/*outerAlternatives*/ {}, locator); | ||
dan-zheng marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Add new applicable function constraint based on the member type | ||
// variable. | ||
addConstraint(ConstraintKind::ApplicableFunction, func1, memberTy, | ||
locator); | ||
return SolutionKind::Solved; | ||
} | ||
|
||
// Record the second type before unwrapping optionals. | ||
auto origType2 = desugar2; | ||
unsigned unwrapCount = 0; | ||
if (shouldAttemptFixes()) { | ||
|
@@ -6305,6 +6341,13 @@ getDynamicCallableMethods(Type type, ConstraintSystem &CS, | |
return result; | ||
} | ||
|
||
// TODO: Refactor/simplify this function. | ||
// - It should perform less duplicate work with its caller | ||
// `ConstraintSystem::simplifyApplicableFnConstraint`. | ||
// - It should generate a member constraint instead of manually forming an | ||
// overload set for `func dynamicallyCall` candidates. | ||
// - It should support `mutating func dynamicallyCall`. This should fall out of | ||
// using member constraints with an lvalue base type. | ||
ConstraintSystem::SolutionKind | ||
ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint( | ||
Type type1, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
public protocol Layer { | ||
func callAsFunction(_ input: Float) -> Float | ||
} | ||
|
||
public struct Dense { | ||
public init() {} | ||
|
||
public func callAsFunction(_ input: Float) -> Float { | ||
return input * 2 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// RUN: %empty-directory(%t) | ||
// RUN: %target-swift-frontend -emit-module -primary-file %S/Inputs/call_as_function_other_module.swift -emit-module-path %t/call_as_function_other_module.swiftmodule | ||
// RUN: %target-swift-frontend -typecheck -I %t -primary-file %s -verify | ||
|
||
import call_as_function_other_module | ||
|
||
func testLayer<L: Layer>(_ layer: L) -> Float { | ||
return layer(1) | ||
} | ||
|
||
func testDense() -> Float { | ||
let dense = Dense() | ||
return dense(1) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.