mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Merge pull request #12736 from d10c/swift/capture-flow
Swift: Closure Capture Helper APIs
This commit is contained in:
@@ -60,7 +60,6 @@ ql/lib/codeql/swift/elements/decl/SubscriptDeclConstructor.qll 3a88617b41f96827c
|
||||
ql/lib/codeql/swift/elements/decl/TopLevelCodeDeclConstructor.qll 6920a4e7aec45ae2a561cef95b9082b861f81c16c259698541f317481645e194 4bd65820b93a5ec7332dd1bbf59326fc19b77e94c122ad65d41393c84e6ac581
|
||||
ql/lib/codeql/swift/elements/decl/TypeAliasDecl.qll 984c5802c35e595388f7652cef1a50fb963b32342ab4f9d813b7200a0e6a37ca 630dc9cbf20603855c599a9f86037ba0d889ad3d2c2b6f9ac17508d398bff9e3
|
||||
ql/lib/codeql/swift/elements/decl/TypeAliasDeclConstructor.qll ba70bb69b3a14283def254cc1859c29963838f624b3f1062a200a8df38f1edd5 96ac51d1b3156d4139e583f7f803e9eb95fe25cc61c12986e1b2972a781f9c8b
|
||||
ql/lib/codeql/swift/elements/decl/ValueDecl.qll 1b7d8eeb17be4bdbabc156cb0689641ed4f9e697e334d2d14f423ed3d1a419f6 e3056cf6a883da2737cb220a89499a9e3977eb1c56b9e1d2f41a56b71a0c29f9
|
||||
ql/lib/codeql/swift/elements/expr/AbiSafeConversionExpr.qll 39b856c89b8aff769b75051fd9e319f2d064c602733eaa6fed90d8f626516306 a87738539276438cef63145461adf25309d1938cfac367f53f53d33db9b12844
|
||||
ql/lib/codeql/swift/elements/expr/AbiSafeConversionExprConstructor.qll 7d70e7c47a9919efcb1ebcbf70e69cab1be30dd006297b75f6d72b25ae75502a e7a741c42401963f0c1da414b3ae779adeba091e9b8f56c9abf2a686e3a04d52
|
||||
ql/lib/codeql/swift/elements/expr/AbstractClosureExpr.qll 4027b51a171387332f96cb7b78ca87a6906aec76419938157ac24a60cff16519 400790fe643585ad39f40c433eff8934bbe542d140b81341bca3b6dfc5b22861
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
private import codeql.swift.generated.AstNode
|
||||
private import codeql.swift.elements.decl.AbstractFunctionDecl
|
||||
private import codeql.swift.elements.decl.Decl
|
||||
private import codeql.swift.elements.expr.AbstractClosureExpr
|
||||
private import codeql.swift.elements.Callable
|
||||
private import codeql.swift.generated.ParentChild
|
||||
|
||||
private module Cached {
|
||||
@@ -21,10 +23,59 @@ private module Cached {
|
||||
AbstractFunctionDecl getEnclosingFunction(AstNode ast) {
|
||||
result = getEnclosingFunctionStep*(getEnclosingDecl(ast))
|
||||
}
|
||||
|
||||
private Element getEnclosingClosureStep(Element e) {
|
||||
not e instanceof Callable and
|
||||
result = getImmediateParent(e)
|
||||
}
|
||||
|
||||
cached
|
||||
AbstractClosureExpr getEnclosingClosure(AstNode ast) {
|
||||
result = getEnclosingClosureStep*(getImmediateParent(ast))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node in the abstract syntax tree.
|
||||
*/
|
||||
class AstNode extends Generated::AstNode {
|
||||
/**
|
||||
* Gets the nearest function definition that contains this AST node, if any.
|
||||
* This includes functions, methods, (de)initializers, and accessors, but not closures.
|
||||
*
|
||||
* For example, in the following code, the AST node for `n + 1` has `foo` as its
|
||||
* enclosing function (via `getEnclosingFunction`), whereas its enclosing callable is
|
||||
* the closure `{(n : Int) in n + 1 }` (via `getEnclosingCallable`):
|
||||
*
|
||||
* ```swift
|
||||
* func foo() {
|
||||
* var f = { (n : Int) in n + 1 }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final AbstractFunctionDecl getEnclosingFunction() { result = Cached::getEnclosingFunction(this) }
|
||||
|
||||
/**
|
||||
* Gets the nearest declaration that contains this AST node, if any.
|
||||
*/
|
||||
final Decl getEnclosingDecl() { result = Cached::getEnclosingDecl(this) }
|
||||
|
||||
/**
|
||||
* Gets the nearest `Callable` that contains this AST node, if any.
|
||||
* This includes (auto)closures, functions, methods, (de)initializers, and accessors.
|
||||
*
|
||||
* For example, in the following code, the AST node for `n + 1` has the closure
|
||||
* `{(n : Int) in n + 1 }` as its enclosing callable.
|
||||
*
|
||||
* ```swift
|
||||
* func foo() {
|
||||
* var f = { (n : Int) in n + 1 }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
final Callable getEnclosingCallable() {
|
||||
if exists(Cached::getEnclosingClosure(this))
|
||||
then result = Cached::getEnclosingClosure(this)
|
||||
else result = Cached::getEnclosingFunction(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
private import codeql.swift.generated.decl.CapturedDecl
|
||||
private import codeql.swift.elements.Callable
|
||||
private import codeql.swift.elements.expr.DeclRefExpr
|
||||
|
||||
/**
|
||||
* A captured variable or function parameter in the scope of a closure.
|
||||
*/
|
||||
class CapturedDecl extends Generated::CapturedDecl {
|
||||
override string toString() { result = this.getDecl().toString() }
|
||||
|
||||
/**
|
||||
* Gets the closure or function that captures this variable.
|
||||
*/
|
||||
Callable getScope() { result.getACapture() = this }
|
||||
|
||||
/**
|
||||
* Get an access to this capture within the scope of its closure.
|
||||
*/
|
||||
DeclRefExpr getAnAccess() {
|
||||
result.getEnclosingCallable() = this.getScope() and
|
||||
result.getDecl() = this.getDecl()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
|
||||
private import codeql.swift.generated.decl.ValueDecl
|
||||
private import codeql.swift.elements.decl.CapturedDecl
|
||||
private import codeql.swift.elements.expr.DeclRefExpr
|
||||
|
||||
class ValueDecl extends Generated::ValueDecl { }
|
||||
/**
|
||||
* A declaration that introduces a value with a type.
|
||||
*/
|
||||
class ValueDecl extends Generated::ValueDecl {
|
||||
/**
|
||||
* Gets a capture of this declaration in the scope of a closure.
|
||||
*/
|
||||
CapturedDecl asCapturedDecl() { result.getDecl() = this }
|
||||
|
||||
/**
|
||||
* Holds if this declaration is captured by a closure.
|
||||
*/
|
||||
predicate isCaptured() { exists(this.asCapturedDecl()) }
|
||||
|
||||
/**
|
||||
* Gets an expression that references this declaration.
|
||||
*/
|
||||
DeclRefExpr getAnAccess() { result.getDecl() = this }
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
private import codeql.swift.generated.decl.VarDecl
|
||||
private import codeql.swift.elements.expr.DeclRefExpr
|
||||
private import codeql.swift.elements.decl.Decl
|
||||
|
||||
/**
|
||||
* A variable declaration.
|
||||
*/
|
||||
class VarDecl extends Generated::VarDecl {
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
DeclRefExpr getAnAccess() { result.getDecl() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A field declaration.
|
||||
*/
|
||||
class FieldDecl extends VarDecl {
|
||||
FieldDecl() { this = any(Decl ctx).getAMember() }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
private import codeql.swift.generated.expr.DeclRefExpr
|
||||
private import codeql.swift.elements.decl.CapturedDecl
|
||||
|
||||
/**
|
||||
* An expression that references or accesses a declaration.
|
||||
*/
|
||||
class DeclRefExpr extends Generated::DeclRefExpr {
|
||||
override string toString() {
|
||||
if exists(this.getDecl().toString())
|
||||
then result = this.getDecl().toString()
|
||||
else result = "(unknown declaration)"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the closure capture referenced by this expression, if any.
|
||||
*/
|
||||
CapturedDecl getCapturedDecl() { result.getAnAccess() = this }
|
||||
|
||||
/**
|
||||
* Holds if this expression references a closure capture.
|
||||
*/
|
||||
predicate hasCapturedDecl() { exists(this.getCapturedDecl()) }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
| closures.swift:8:12:8:12 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:7:6:7:6 | x | isDirect: | yes | isEscaping: | no |
|
||||
| closures.swift:9:12:9:12 | y | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:6:7:6:7 | y | isDirect: | yes | isEscaping: | no |
|
||||
| closures.swift:16:3:16:3 | escape | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:12:5:12:5 | escape | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:17:5:17:5 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:15:7:15:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:20:3:20:3 | escape | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:12:5:12:5 | escape | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:25:3:25:3 | escape | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:12:5:12:5 | escape | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:24:3:24:3 | escape | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:12:5:12:5 | escape | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:31:11:31:11 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:29:7:29:7 | x | isDirect: | no | isEscaping: | no |
|
||||
| closures.swift:32:14:32:14 | f | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:28:7:28:7 | f | isDirect: | no | isEscaping: | no |
|
||||
| closures.swift:32:14:32:14 | f | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:28:7:28:7 | f | isDirect: | yes | isEscaping: | no |
|
||||
| closures.swift:32:17:32:17 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:29:7:29:7 | x | isDirect: | yes | isEscaping: | no |
|
||||
| closures.swift:39:20:39:20 | callback | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:36:21:36:58 | callback | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:42:35:42:35 | wrapper(_:) | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:38:5:40:5 | wrapper(_:) | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:52:18:52:18 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:51:7:51:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:54:13:54:13 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:51:7:51:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:61:18:61:18 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:60:7:60:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:63:13:63:13 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:60:7:60:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:71:3:71:3 | g | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:68:5:68:5 | g | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:71:14:71:14 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:70:7:70:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:73:13:73:13 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:70:7:70:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:85:7:85:7 | y | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:79:7:79:7 | y | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:85:7:85:7 | y | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:79:7:79:7 | y | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:85:18:85:18 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:82:9:82:9 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:88:9:88:9 | b() | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:92:5:98:5 | b() | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:93:7:93:7 | y | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:79:7:79:7 | y | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:93:20:93:20 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:82:9:82:9 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:96:9:96:9 | a() | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:84:5:90:5 | a() | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:111:15:111:15 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:110:9:110:9 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:111:27:111:27 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:110:9:110:9 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:115:5:115:5 | incrX | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:109:8:109:8 | incrX | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:130:25:130:25 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:128:7:128:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:133:20:133:20 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:128:7:128:7 | x | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:133:20:133:20 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:128:7:128:7 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:133:24:133:24 | y | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:132:22:132:22 | y | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:151:21:151:21 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:149:10:149:15 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:154:16:154:16 | g(_:) | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:158:3:165:3 | g(_:) | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:155:21:155:21 | next | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:154:9:154:9 | next | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:155:34:155:34 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:149:10:149:15 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:160:21:160:21 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:158:10:158:15 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:163:16:163:16 | f(_:) | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:149:3:156:3 | f(_:) | isDirect: | no | isEscaping: | yes |
|
||||
| closures.swift:164:21:164:21 | next | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:163:9:163:9 | next | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:164:36:164:36 | x | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:158:10:158:15 | x | isDirect: | yes | isEscaping: | yes |
|
||||
| closures.swift:195:3:195:3 | g | getModule: | file://:0:0:0:0 | closures | getNumberOfMembers: | 0 | getDecl: | closures.swift:68:5:68:5 | g | isDirect: | yes | isEscaping: | yes |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,211 @@
|
||||
func bar() -> String {
|
||||
func hello() -> String {
|
||||
return "Hello world!"
|
||||
}
|
||||
|
||||
func foo() {
|
||||
func captureList() {
|
||||
let y = 123
|
||||
{ [x = bar()] () in
|
||||
{ [x = hello()] () in
|
||||
print(x)
|
||||
print(y) }()
|
||||
}
|
||||
|
||||
var escape: (() -> ())? = nil
|
||||
|
||||
func baz() {
|
||||
func setEscape() {
|
||||
var x = 0
|
||||
func quux() {
|
||||
escape = {
|
||||
x += 1
|
||||
print(x)
|
||||
}
|
||||
escape = quux
|
||||
}
|
||||
|
||||
func callEscape() {
|
||||
baz()
|
||||
setEscape()
|
||||
escape?()
|
||||
}
|
||||
|
||||
func logical() -> Bool {
|
||||
let f: ((Int) -> Int)? = { x in x + 1 }
|
||||
let x: Int? = 42
|
||||
return f != nil
|
||||
&& (x != nil
|
||||
&& f!(x!) == 43)
|
||||
}
|
||||
|
||||
func asyncTest() {
|
||||
func withCallback(_ callback: @escaping (Int) async -> Int) {
|
||||
@Sendable
|
||||
func wrapper(_ x: Int) async -> Int {
|
||||
return await callback(x + 1)
|
||||
}
|
||||
Task {
|
||||
print("asyncTest():", await wrapper(40))
|
||||
}
|
||||
}
|
||||
withCallback { x in
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
|
||||
func foo() -> Int {
|
||||
var x = 1 // x is a non-escaping capture of f and r
|
||||
let f = { y in x += y }
|
||||
x += 40
|
||||
let r = { x }
|
||||
f(1)
|
||||
return r() // 42
|
||||
}
|
||||
|
||||
func bar() -> () -> Int {
|
||||
var x = 1 // x is a non-escaping capture of f, escaping capture of r
|
||||
let f = { y in x += y }
|
||||
x += 40
|
||||
let r = { x }
|
||||
f(1)
|
||||
return r // constantly 42
|
||||
}
|
||||
|
||||
var g: ((Int) -> Void)? = nil
|
||||
func baz() -> () -> Int {
|
||||
var x = 1 // x is an escaping capture of g and r
|
||||
g = { y in x += y } // closure escapes!
|
||||
x += 40
|
||||
let r = { x }
|
||||
g!(1)
|
||||
return r
|
||||
}
|
||||
|
||||
func quux() -> Int {
|
||||
var y = 0
|
||||
|
||||
func f() -> () -> Void {
|
||||
var x = 5
|
||||
|
||||
func a() {
|
||||
y = 10*y + x
|
||||
x -= 1
|
||||
if x > 0 {
|
||||
b()
|
||||
}
|
||||
}
|
||||
|
||||
func b() {
|
||||
y = 10*y + 2*x
|
||||
x -= 1
|
||||
if x > 0 {
|
||||
a()
|
||||
}
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
let a = f()
|
||||
a()
|
||||
return y // 58341
|
||||
}
|
||||
|
||||
func sharedCapture() -> Int {
|
||||
let (incrX, getX) = {
|
||||
var x = 0
|
||||
return ({ x += 1 }, { x })
|
||||
}()
|
||||
|
||||
let doubleIncrX = {
|
||||
incrX()
|
||||
incrX()
|
||||
}
|
||||
|
||||
doubleIncrX()
|
||||
doubleIncrX()
|
||||
return getX() // 4
|
||||
}
|
||||
|
||||
func sink(_ x: Int) { print("sink:", x) }
|
||||
func source() -> Int { -1 }
|
||||
|
||||
func sharedCaptureMultipleWriters() {
|
||||
var x = 123
|
||||
|
||||
let callSink = { sink(x) }
|
||||
|
||||
let makeSetter = { y in
|
||||
let setter = { x = y }
|
||||
return setter
|
||||
}
|
||||
|
||||
let goodSetter = makeSetter(42)
|
||||
let badSetter = makeSetter(source())
|
||||
|
||||
goodSetter()
|
||||
callSink()
|
||||
|
||||
badSetter()
|
||||
callSink()
|
||||
}
|
||||
|
||||
func reentrant() -> Int {
|
||||
|
||||
func f(_ x: Int) -> (Int) -> Int {
|
||||
if x == 0 {
|
||||
return { _ in x }
|
||||
}
|
||||
|
||||
let next = g(x - 1)
|
||||
return { k in k*next(10*k) + x }
|
||||
}
|
||||
|
||||
func g(_ x: Int) -> (Int) -> Int {
|
||||
if x == 0 {
|
||||
return { _ in x }
|
||||
}
|
||||
|
||||
let next = f(x - 1)
|
||||
return { k in k*next(10*k) + 2*x }
|
||||
}
|
||||
|
||||
let h = f(5)
|
||||
|
||||
let y = h(10)
|
||||
|
||||
return y // 10004003085
|
||||
}
|
||||
|
||||
func main() {
|
||||
print("captureList():")
|
||||
captureList() // Hello world! 123
|
||||
|
||||
print("callEscape():")
|
||||
callEscape() // 1
|
||||
|
||||
print("logical():", logical()) // true
|
||||
|
||||
print("asyncTest():")
|
||||
asyncTest() // 42
|
||||
|
||||
print("foo():", foo()) // 42
|
||||
|
||||
let a = bar()
|
||||
let b = baz()
|
||||
|
||||
print("bar():", a(), a()) // 42 42
|
||||
|
||||
print("baz():", b(), b()) // 42 42
|
||||
|
||||
g!(1)
|
||||
print("g!(1):", b(), b()) // 43 43
|
||||
|
||||
g!(1)
|
||||
print("g!(1):", b(), b()) // 44 44
|
||||
|
||||
print("quux():", quux()) // 58341
|
||||
|
||||
print("sharedCapture():", sharedCapture()) // 4
|
||||
|
||||
print("sharedCaptureMultipleWriters():")
|
||||
sharedCaptureMultipleWriters() // 42, -1
|
||||
|
||||
print("reentrant():", reentrant()) // 10004003085
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user