-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathhow-never-works-internally-in-swift.html
More file actions
430 lines (382 loc) · 26 KB
/
Copy pathhow-never-works-internally-in-swift.html
File metadata and controls
430 lines (382 loc) · 26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://use.fontawesome.com/afd448ce82.js"></script>
<!-- Meta Tag -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- SEO -->
<meta name="author" content="Bruno Rocha">
<meta name="keywords" content="Software, Engineering, Blog, Posts, iOS, Xcode, Swift, Articles, Tutorials, OBJ-C, Objective-C, Apple">
<meta name="description" content="Added in Swift 3, the Never type allows you to define a method that is guaranteed to crash your app.">
<meta name="title" content="How Never Works Internally in Swift">
<meta name="url" content="https://swiftrocks.com/how-never-works-internally-in-swift">
<meta name="image" content="https://swiftrocks.com/images/thumbs/thumb_dark.jpg">
<meta name="copyright" content="Bruno Rocha">
<meta name="robots" content="index,follow">
<meta property="og:title" content="How Never Works Internally in Swift"/>
<meta property="og:image" content="https://swiftrocks.com/images/thumbs/thumb_dark.jpg"/>
<meta property="og:description" content="Added in Swift 3, the Never type allows you to define a method that is guaranteed to crash your app."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://swiftrocks.com/how-never-works-internally-in-swift"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://swiftrocks.com/images/thumbs/thumb_dark.jpg"/>
<meta name="twitter:image:alt" content="Page Thumbnail"/>
<meta name="twitter:title" content="How Never Works Internally in Swift"/>
<meta name="twitter:description" content="Added in Swift 3, the Never type allows you to define a method that is guaranteed to crash your app."/>
<meta name="twitter:site" content="@rockbruno_"/>
<meta name="fediverse:creator" content="@rockbruno@hachyderm.io">
<!-- Favicon -->
<!-- 16x16 -->
<link rel="shortcut icon" href="images/favicon/favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="images/favicon/favicon_180.png" sizes="180x180">
<link rel="icon" href="images/favicon/favicon_32.png" sizes="32x32" type="image/png">
<link rel="icon" href="images/favicon/favicon_48.png" sizes="48x48" type="image/png">
<link rel="icon" href="images/favicon/favicon_96.png" sizes="96x96" type="image/png">
<link rel="icon" href="images/favicon/favicon_144.png" sizes="144x144" type="image/png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap" rel="stylesheet">
<link rel="canonical" href="https://swiftrocks.com/how-never-works-internally-in-swift"/>
<!-- Bootstrap CSS Plugins -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
<!-- Prism CSS Stylesheet -->
<link rel="stylesheet" type="text/css" href="css/prism5.css">
<!-- Main CSS Stylesheet -->
<link rel="stylesheet" type="text/css" href="css/style49.css">
<link rel="stylesheet" type="text/css" href="css/sponsor5.css">
<!-- HTML5 shiv and Respond.js support IE8 or Older for HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://swiftrocks.com/how-never-works-internally-in-swift"
},
"image": [
"https://swiftrocks.com/images/thumbs/thumb_dark.jpg"
],
"datePublished": "2018-11-14T13:42:07+00:00",
"dateModified": "2020-04-12T14:00:00+02:00",
"author": {
"@type": "Person",
"name": "Bruno Rocha"
},
"publisher": {
"@type": "Organization",
"name": "SwiftRocks",
"logo": {
"@type": "ImageObject",
"url": "https://swiftrocks.com/images/thumbs/thumb_dark.jpg"
}
},
"headline": "How Never Works Internally in Swift",
"abstract": "Added in Swift 3, the Never type allows you to define a method that is guaranteed to crash your app."
}
</script>
</head>
<body>
<div id="main">
<!-- Blog Header -->
<!-- Blog Post (Right Sidebar) Start -->
<div class="container">
<div class="col-xs-12">
<div class="page-body">
<div class="row">
<div><a class="logo-link" href="https://swiftrocks.com">
<img id="logo" class="logo" alt="SwiftRocks" src="images/bg/logo2dark.png">
</a>
<div class="menu-large">
<div class="menu-arrow-right"></div>
<div class="menu-header menu-header-large">
<div class="menu-item">
<a href="blog">blog</a>
</div>
<div class="menu-item">
<a href="about">about</a>
</div>
<div class="menu-item">
<a href="talks">talks</a>
</div>
<div class="menu-item">
<a href="projects">projects</a>
</div>
<div class="menu-item">
<a href="software-engineering-book-recommendations">book recs</a>
</div>
<div class="menu-item">
<a href="games">game recs</a>
</div>
<div class="menu-arrow-right-2"></div>
</div>
</div>
<div class="menu-small">
<div class="menu-arrow-right"></div>
<div class="menu-header menu-header-small-1">
<div class="menu-item">
<a href="blog">blog</a>
</div>
<div class="menu-item">
<a href="about">about</a>
</div>
<div class="menu-item">
<a href="talks">talks</a>
</div>
<div class="menu-item">
<a href="projects">projects</a>
</div>
<div class="menu-arrow-right-2"></div>
</div>
<div class="menu-arrow-right"></div>
<div class="menu-header menu-header-small-2">
<div class="menu-item">
<a href="software-engineering-book-recommendations">book recs</a>
</div>
<div class="menu-item">
<a href="games">game recs</a>
</div>
<div class="menu-arrow-right-2"></div>
</div>
</div>
</div>
<div class="content-page" id="WRITEIT_DYNAMIC_CONTENT">
<!--WRITEIT_POST_NAME=How Never Works Internally in Swift-->
<!--WRITEIT_POST_HTML_NAME=how-never-works-internally-in-swift-->
<!--WRITEIT_POST_SITEMAP_DATE_LAST_MOD=2020-04-12T14:00:00+02:00-->
<!--WRITEIT_POST_SITEMAP_DATE=2018-11-14T13:42:07+00:00-->
<!--Add here the additional properties that you want each page to possess.-->
<!--These properties can be used to change content in the template page or in the page itself as shown here.-->
<!--Properties must start with 'WRITE_IT_POST'.-->
<!--Writeit provides and injects WRITEIT_POST_NAME and WRITEIT_POST_HTML_NAME by default.-->
<!--WRITEIT_POST_SHORT_DESCRIPTION=Added in Swift 3, the Never type allows you to define a method that is guaranteed to crash your app.-->
<title>How Never Works Internally in Swift</title>
<div class="blog-post">
<div class="post-title-index">
<h1>How Never Works Internally in Swift</h1>
</div>
<div class="post-info">
<div class="post-info-text">
Published on 14 Nov 2018
</div>
</div>
<p>Added in Swift 3, the <code>Never</code> type allows you to define a method that is guaranteed to crash your app. Although we rarely write methods that use this type directly, we do interact with it constantly given that it is the return type of forced-crash methods like <code>fatalError()</code>. The advantage this type brings is that a method that calls another <code>Never</code>-returning method does not need to provide a return value, after all, a crash is certain to happen:</p>
<pre><code>func getSomeNumber() -> Int
fatalError()
//I'm not returning an Int, but this still compiles
//because fatalError() returns 'Never'.
}</code></pre>
<div class="sponsor-article-ad-auto hidden"></div>
<p>Deep down, <code>Never</code> is just the revamped "swifty" version of <code>@noreturn</code>: an attribute that provided the exact same functionality but was removed for being too complex due to its nature as an attribute. Connecting this behavior to a return type allowed the compiler to work better, and certainly ended up looking better for the developer as well.</p>
<p>Something about <code>Never</code> intrigued me though. We know that there's nothing in the language itself that allows you to skip return values, so what magic is done in the compiler to allow this?</p>
<p>Just like in my <a href="https://swiftrocks.com/how-caseiterable-works-internally-in-swift">previous article about the innards of CaseIterable</a>, I'm going to dive into the compiler in order to extract and analyze the pieces of code that intercept and change the functionality of methods that return <code>Never</code> in order to learn more about how the Swift compiler works.</p>
<p><i>Disclaimer: As always, this is a result of my own research and reverse-engineering. As I have nothing to do with the original development of <code>Never</code>, some assumptions might be not fully correct.</i></p>
<h2>Uninhabited Types / Never Patterns</h2>
<p>Expecting to find complex pieces of code, the implementation of <code>Never</code> in the Standard Library shows us something else - the type is nothing but an empty enum:</p>
<pre><code>public enum Never {}</code></pre>
<p>Although that certainly looks weird, it is correct in its theory. When <code>Never</code> got implemented, Swift also added the concept of <b>uninhabited types</b> to its lingo - a type with no value, often used to represent the nonexistent result of something that will never happen. Because an enum with no cases can't be instantiated in any way, it becomes perfect to represent this concept. But if the type itself doesn't do anything, where is the magic done?</p>
<p>A quick search for <code>"never typecheck"</code> in the Swift repo reveals a method called <code>isNoReturnFunction()</code>, which searches for the presence of an uninhabited type return:</p>
<pre><code>bool SILFunctionType::isNoReturnFunction() const {
for (unsigned i = 0, e = getNumResults(); i < e; ++i) {
if (getResults()[i].getType()->isUninhabited())
return true;
}
return false;
}</code></pre>
<p>The implementation of the mentioned <code>isUninhabited()</code> itself just checks if we're dealing with an empty enum:</p>
<pre><code>bool TypeBase::isUninhabited() {
// Empty enum declarations are uninhabited
if (auto nominalDecl = getAnyNominal())
if (auto enumDecl = dyn_cast<EnumDecl>(nominalDecl))
if (enumDecl->getAllElements().empty())
return true;
return false;
}</code></pre>
<p>Because <code>Never</code> has no actual code, I expected the compiler to directly identify and change it somehow, but what this shows is that <code>Never</code> <b>really</b> is just an empty enum - the behavior we see has nothing to do with the type itself, but with the concept of an uninhabited type. This means that you don't need <code>Never</code> at all to ignore return statements:</p>
<pre><code>enum Crash {}
func logAndCrash() -> Crash {
print("Oops!")
fatalError()
}
func doSomething() -> Int {
logAndCrash() //Compiles!
}</code></pre>
<p>In fact, because the compiler doesn't know the difference, my <code>Crash</code> type will even throw the same errors as <code>Never</code>:</p>
<pre><code>func logAndCrash() -> Crash {
//Function with uninhabited return type 'Crash'
//is missing call to another never-returning function on all paths
}</code></pre>
<p>For context, the very first commit of <code>Never</code> was indeed using the type itself to generate this behavior, but it was later changed to work with all uninhabited types due to multiple bugs that a <code>Never</code>-only solution was causing.</p>
<p>That's a great start, but I still have two major questions:</p>
<ul>
<li>First, where are these methods used?</li>
<li>Second, if all never-returning methods need to return another never-returning method, don't we have an infinite recursion? Because the app is guaranteed to crash, <b>someone</b> down the line will have to not return something. Who makes this decision?</li>
</ul>
<h2>SIL generation of Never-returning methods</h2>
<p>The first question can be answered by inspecting what Swift does to your code during the compilation process. To make it straightforward, the secrets of <code>Never</code> are hidden in a source file's SIL representation.</p>
<h3>Swift Intermediate Language</h3>
<p>In short, SIL is the middle-ground between your .swift files and the LLVM IR, basically acting as your Swift files translated to a "language" that contains high-level semantic information about what's happening behind the scenes. This allows the compiler to diagnose compilation errors and perform early optimizations while still allowing it to seamlessly generate the final LLVM IR necessary to let LLVM handle the rest of the compilation.</p>
<div class="post-image margin-top-40 margin-bottom-40">
<img src="https://i.imgur.com/xbVOfbq.png" alt="" style="background-color: #fff">
</div>
<p>Inspecting the SIL version of a method that returns <code>Never</code> should reveal to us an optimized version of it, with hopefully an indicator of how the type works behind the scenes. I'm going to compile the following snippet - with an explicit return statement just to see how the SIL version reacts to it:</p>
<pre><code>@inline(never) func crash() -> Never {
fatalError()
}
func doSomething() -> Int {
crash()
let number = 1+1
let otherNumber = number * 2
return otherNumber
}</code></pre>
<pre class="command-line language-bash" data-host="SwiftRocks"><code>swiftc -emit-sil never.swift</code></pre>
<p>After running the command above, the output will contain the following reference to <code>doSomething()</code>:</p>
<pre><code>// doSomething()
sil hidden @$S5never11doSomethingSiyF : $@convention(thin) () -> Int {
bb0:
// function_ref crash()
%0 = function_ref @$S5never5crashs5NeverOyF : $@convention(thin) () -> Never // user: %1
%1 = apply %0() : $@convention(thin) () -> Never
unreachable // id: %2
} // end sil function '$S5never11doSomethingSiyF'</code></pre>
<p>SIL is not very easy to read, but it thankfully comes with a few comments that help us understand what's going on. The first thing we can notice here is the beauty of optimizations: all the unreachable number code I added there is completely gone!</p>
<p>Besides that, we can see that an <code>unreachable</code> statement was added right after the call to <code>crash()</code>. Normal methods would show a return statement, so this was clearly added by whatever logic handles <code>Never</code>.</p>
<p>A quick search into the Swift repo revealed that <code>unreachable</code> relates to <code>UnreachableInst</code>, a type that is injected and later used when the compiler needs to make decisions when it comes to code that will never succeed, or even be executed in this case.</p>
<pre><code>TERMINATOR(UnreachableInst, unreachable,
TermInst, None, DoesNotRelease)</code></pre>
<p>However, this type is not exclusively used by <code>Never</code>, so more investigation is needed: After attaching lldb to the command used above and creating a breakpoint for <code>UnreachableInst</code>'s init, a call inside <code>simplifyBlocksWithCallsToNoReturn()</code> is revealed: a method defined inside <code>DiagnoseUnreachable.cpp</code>, whose's backtrace revealed it to be one of the mandatory optimization passes before attempting to generate the final LLVM IR. (take a look at my CaseIterable article for details on how to manually use lldb!)</p>
<p><a href="https://github.com/apple/swift/blob/ad8cd1423398124f7dea0441395ba9c42ed6a0d6/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp#L473">The actual method is quite large</a>, so I've pseudo-coded it:</p>
<pre><code>static bool simplifyBlocksWithCallsToNoReturn(SILBasicBlock &BB,
UnreachableUserCodeReportingState *State) {
if method_returns_never
delete_everything_after_call
inject_fake_unreachable_instruction
}</code></pre>
<p>This does exactly what we've seen in the snippet, but still doesn't answer the first question! Why is this enough to stop requiring return values?</p>
<p>The answer is another mandatory optimization pass file named <code>DataflowDiagnostics.cpp</code>: the responsible for throwing unreachable-related compilation errors such as "missing return", "guard body missing return" and the "never method must call another never-method" from the previous examples.</p>
<p>One of the methods inside this file is called <code>diagnoseMissingReturn()</code>, which throws the "missing return" error: (note the call to <code>isNoReturnFunction()</code> to throw the different <code>Never</code> error!)</p>
<pre><code>static void diagnoseMissingReturn(const UnreachableInst *UI,
ASTContext &Context) {
//Removed: Retrieving type data
auto diagID = F->isNoReturnFunction() ? diag::missing_never_call
: diag::missing_return;
//"diagnose" throws the compilation error
diagnose(Context,
L.getEndSourceLoc(),
diagID, ResTy,
FLoc.isASTNode&ClosureExpr>() ? 1 : 0);
}</code></pre>
<p>The decision to call <code>diagnoseMissingReturn()</code> is handled by <code>diagnoseUnreachable()</code>, which checks if the relevant <code>UnreachableInst</code> points to an actual position in the code (when you're really missing a return, so throw an error) or was injected by the compiler (like returning <code>Never</code>, so do nothing), which is exactly our case. Remember that the previous optimization removed everything after the <code>Never</code> call, so we only have the injected one at this point:</p>
<pre><code>static void diagnoseUnreachable(const SILInstruction *I,
ASTContext &Context) {
if (auto *UI = dyn_cast<UnreachableInst>(I)) {
SILLocation L = UI->getLoc();
// Invalid location means that the instruction has been generated by SIL
// passes, such as DCE. FIXME: we might want to just introduce a separate
// instruction kind, instead of keeping this invariant.
//
// We also do not want to emit diagnostics for code that was
// transparently inlined. We should have already emitted these
// diagnostics when we process the callee function prior to
// inlining it.
if (!L || L.is<MandatoryInlinedLocation>())
return;
// The most common case of getting an unreachable instruction is a
// missing return statement. In this case, we know that the instruction
// location will be the enclosing function.
if (L.isASTNode<AbstractFunctionDecl>() || L.isASTNode<ClosureExpr>()) {
diagnoseMissingReturn(UI, Context);
return;
}
if (auto *Guard = L.getAsASTNode<GuardStmt>()) {
diagnose(Context, Guard->getBody()->getEndLoc(),
diag::guard_body_must_not_fallthrough);
return;
}
}
}</code></pre>
<p>In short, <code>Never</code>'s behavior is defined in the optimization passes - after <code>DiagnoseUnreachable.cpp</code> detects and marks the instruction after a never call as unreachable, <code>DataflowDiagnostics.cpp</code> sees that this specific unreachable statement was injected by the compiler itself, avoids throwing a "missing return" compilation error, and lets the compilation continue.</p>
<h2>Internals of <code>fatalError()</code></h2>
<p>Although the main functionality is now uncovered, something still bugs me; We've seen that creating a <code>Never</code> returning method will result in a compilation error if it doesn't call another <code>Never</code> method. Isn't this an infinite loop? Where is this loop broken?</p>
<p>To get the answer to that, we can inspect the contents of <code>fatalError()</code> and start going up its backtrace. Here's how <code>fatalError()</code> is defined:</p>
<pre><code>public func fatalError(
_ message: @autoclosure () -> String = String(),
file: StaticString = #file, line: UInt = #line
) -> Never {
_assertionFailure("Fatal error", message(), file: file, line: line,
flags: _fatalErrorFlags())
}</code></pre>
<p>This will compile correctly, since <code>_assertionFailure</code> also returns <code>Never</code>. Going up the backtrace, we'll see that it has the following implementation:</p>
<pre><code>internal func _assertionFailure(
_ prefix: StaticString, _ message: StaticString,
file: StaticString, line: UInt,
flags: UInt32
) -> Never {
//Removed: Write to file
Builtin.int_trap()
}</code></pre>
<p>Now, <code>Builtin.int_trap()</code> also returns <code>Never</code>, so this too will compile correctly. Going up the backtrace, we'll see that <code>int_trap()</code> is defined as... uhhh....</p>
<p>Actually, there's no definition for this method! <code>Builtin</code> is not a normal framework - it seems to be generated inside the compiler as a way to allow Swift code to directly access LLVM functions. It appears to be all done <a href="https://github.com/apple/swift/blob/4fb4cb058d5d81f5fc3f8aaeb0adec2b933c5511/lib/AST/Builtins.cpp">in Builtins.cpp</a> by parsing <a href="https://github.com/apple/swift-llvm/blob/e9e59b13f33aadfb02075c373d52506b261a26ac/include/llvm/IR/Intrinsics.td#L835">a table all the way from the swift-llvm repository</a> and generating "pre-compiled" Swift methods from them. In this case, <code>int_trap()</code> is parsed as a <code>Never</code> returning method that calls <a href="https://llvm.org/docs/LangRef.html#llvm-trap-intrinsic">llvm.trap()</a>, a function that adds an instruction to blow up your app.</p>
<p>So how does the infinite loop stops? The answer seems to be that it simply does not. Because the final call of the chain is inside a "pre-compiled framework" in a sense, diagnostics do not seem to affect it, allowing the app to compile correctly.</p>
<h2>Conclusion</h2>
<div class="sponsor-article-ad-auto hidden"></div>
<p>Compilers are scary monsters, but knowing the internals of a language can really help you write efficient code. In this case, spelunking <code>Never</code> was interesting to see how each optimization pass complements each other when it comes to finding problems or changing the behaviour of a piece of code.</p>
<h2>References and Good reads</h2>
<a href="https://github.com/apple/swift">The Swift Source Code</a>
<br>
<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0102-noreturn-bottom-type.md">SE-0102: Introduce Never</a>
<br>
<a href="https://github.com/apple/swift/blob/master/docs/SIL.rst">Swift Intermediate Language</a>
<br>
<a href="https://github.com/apple/swift-llvm">swift-llvm</a>
<br>
<a href="https://llvm.org/docs/LangRef.html">LLVM Ref</a>
<br>
</div></div>
<div class="blog-post footer-main">
<div class="footer-logos">
<a href="https://swiftrocks.com/rss.xml"><i class="fa fa-rss"></i></a>
<a href="https://hachyderm.io/@rockbruno"><svg class="svg-logo-link" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M433 179.1c0-97.2-63.7-125.7-63.7-125.7-62.5-28.7-228.6-28.4-290.5 0 0 0-63.7 28.5-63.7 125.7 0 115.7-6.6 259.4 105.6 289.1 40.5 10.7 75.3 13 103.3 11.4 50.8-2.8 79.3-18.1 79.3-18.1l-1.7-36.9s-36.3 11.4-77.1 10.1c-40.4-1.4-83-4.4-89.6-54a102.5 102.5 0 0 1 -.9-13.9c85.6 20.9 158.7 9.1 178.8 6.7 56.1-6.7 105-41.3 111.2-72.9 9.8-49.8 9-121.5 9-121.5zm-75.1 125.2h-46.6v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.3V197c0-58.5-64-56.6-64-6.9v114.2H90.2c0-122.1-5.2-147.9 18.4-175 25.9-28.9 79.8-30.8 103.8 6.1l11.6 19.5 11.6-19.5c24.1-37.1 78.1-34.8 103.8-6.1 23.7 27.3 18.4 53 18.4 175z"/></svg></a>
<a href="https://twitter.com/rockbruno_"><i class="fa fa-twitter"></i></a>
<a href="https://github.com/rockbruno"><i class="fa fa-github"></i></a>
</div>
<div class="footer-text">
© 2026 Bruno Rocha
</div>
<div class="footer-text">
<p><a href="https://swiftrocks.com">Home</a> / <a href="blog">See all posts</a></p>
</div>
<div class="footer-text">
No AI has ever been used in this blog. Everything down to the HTML/CSS has been handcrafted by me.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Blog Post (Right Sidebar) End -->
</div>
</div>
</div>
<!-- All Javascript Plugins -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script type="text/javascript" src="js/prism5.js"></script>
<!-- Main Javascript File -->
<script type="text/javascript" src="js/scripts30.js"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H8KZTWSQ1R"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-H8KZTWSQ1R');
</script>
</body>
</html>