mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Performance Hints] Implement check for existential any
This commit introduces a performance hint check that warns on the use of existential any in variable declarations, function and closure parameters and returns, and typealiases.
This commit is contained in:
@@ -48,6 +48,8 @@ namespace swift {
|
||||
class FuncDecl;
|
||||
class SourceManager;
|
||||
class SourceFile;
|
||||
class ParamDecl;
|
||||
class AnyPattern;
|
||||
|
||||
/// Enumeration describing all of possible diagnostics.
|
||||
///
|
||||
|
||||
@@ -82,6 +82,8 @@ GROUP(WeakMutability, "weak-mutability")
|
||||
GROUP(PerformanceHints, "performance-hints")
|
||||
GROUP(ReturnTypeImplicitCopy, "return-type-implicit-copy")
|
||||
GROUP_LINK(PerformanceHints, ReturnTypeImplicitCopy)
|
||||
GROUP(ExistentialType, "existential-type")
|
||||
GROUP_LINK(PerformanceHints, ExistentialType)
|
||||
|
||||
#define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
|
||||
#include "swift/AST/DefineDiagnosticGroupsMacros.h"
|
||||
|
||||
@@ -8946,6 +8946,30 @@ GROUPED_WARNING(perf_hint_closure_returns_array,ReturnTypeImplicitCopy,DefaultIg
|
||||
"Performance: closure returns a%select{ dictionary|n array}0, leading to implicit copies. "
|
||||
"Consider using an 'inout' parameter instead.", (bool))
|
||||
|
||||
GROUPED_WARNING(perf_hint_param_expects_existential,ExistentialType,DefaultIgnore,
|
||||
"Performance: %0 expects an existential, leading to heap allocation, reference counting, "
|
||||
"and dynamic dispatch. Consider using generic constraints or concrete types instead.",
|
||||
(const ParamDecl*))
|
||||
GROUPED_WARNING(perf_hint_func_returns_existential,ExistentialType,DefaultIgnore,
|
||||
"Performance: %0 returns an existential, leading to heap allocation, reference counting, "
|
||||
"and dynamic dispatch. Consider using generic constraints or concrete types instead.",
|
||||
(const FuncDecl*))
|
||||
GROUPED_WARNING(perf_hint_closure_returns_existential,ExistentialType,DefaultIgnore,
|
||||
"Performance: closure returns an existential, leading to heap allocation, reference counting, "
|
||||
"and dynamic dispatch. Consider using generic constraints or concrete types instead.", ())
|
||||
GROUPED_WARNING(perf_hint_var_uses_existential,ExistentialType,DefaultIgnore,
|
||||
"Performance: %0 uses an existential, leading to heap allocation, reference counting, "
|
||||
"and dynamic dispatch. Consider using generic constraints or concrete types instead.",
|
||||
(const VarDecl *))
|
||||
GROUPED_WARNING(perf_hint_any_pattern_uses_existential,ExistentialType,DefaultIgnore,
|
||||
"Performance: declaration uses an existential, leading to heap allocation, reference counting, "
|
||||
"and dynamic dispatch. Consider using generic constraints or concrete types instead.",
|
||||
())
|
||||
GROUPED_WARNING(perf_hint_typealias_uses_existential,ExistentialType,DefaultIgnore,
|
||||
"Performance: %0 aliases an existential type, leading to heap allocation, reference counting, "
|
||||
"and dynamic dispatch. Consider using generic constraints or concrete types instead.",
|
||||
(const TypeAliasDecl *))
|
||||
|
||||
ERROR(unsafe_self_dependent_result_attr_on_invalid_decl,none,
|
||||
"invalid use of @_unsafeSelfDependentResult", ())
|
||||
|
||||
|
||||
@@ -25,12 +25,27 @@
|
||||
#include "swift/AST/Evaluator.h"
|
||||
#include "swift/AST/Expr.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/AST/TypeVisitor.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
bool swift::performanceHintDiagnosticsEnabled(ASTContext &ctx) {
|
||||
return !ctx.Diags.isIgnoredDiagnostic(diag::perf_hint_closure_returns_array.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(diag::perf_hint_function_returns_array.ID);
|
||||
return !ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_closure_returns_array.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_function_returns_array.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_param_expects_existential.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_func_returns_existential.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_closure_returns_existential.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_var_uses_existential.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_any_pattern_uses_existential.ID) ||
|
||||
!ctx.Diags.isIgnoredDiagnostic(
|
||||
diag::perf_hint_typealias_uses_existential.ID);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -52,6 +67,52 @@ void checkImplicitCopyReturnType(const ClosureExpr *Closure,
|
||||
}
|
||||
}
|
||||
|
||||
bool hasExistentialAnyInType(Type T) {
|
||||
return T->getCanonicalType().findIf(
|
||||
[](CanType CT) { return isa<ExistentialType>(CT); });
|
||||
}
|
||||
|
||||
void checkExistentialInFunctionReturnType(const FuncDecl *FD,
|
||||
DiagnosticEngine &Diags) {
|
||||
Type T = FD->getResultInterfaceType();
|
||||
|
||||
if (hasExistentialAnyInType(T))
|
||||
Diags.diagnose(FD, diag::perf_hint_func_returns_existential, FD);
|
||||
}
|
||||
|
||||
void checkExistentialInClosureReturnType(const ClosureExpr *CE,
|
||||
DiagnosticEngine &Diags) {
|
||||
Type T = CE->getResultType();
|
||||
|
||||
if (hasExistentialAnyInType(T))
|
||||
Diags.diagnose(CE->getLoc(), diag::perf_hint_closure_returns_existential);
|
||||
}
|
||||
|
||||
void checkExistentialInVariableType(const VarDecl *VD,
|
||||
DiagnosticEngine &Diags) {
|
||||
Type T = VD->getInterfaceType();
|
||||
|
||||
if (hasExistentialAnyInType(T))
|
||||
Diags.diagnose(VD, diag::perf_hint_var_uses_existential, VD);
|
||||
}
|
||||
|
||||
void checkExistentialInPatternType(const AnyPattern *AP,
|
||||
DiagnosticEngine &Diags) {
|
||||
Type T = AP->getType();
|
||||
|
||||
if (hasExistentialAnyInType(T))
|
||||
Diags.diagnose(AP->getLoc(), diag::perf_hint_any_pattern_uses_existential);
|
||||
}
|
||||
|
||||
void checkExistentialInTypeAlias(const TypeAliasDecl *TAD,
|
||||
DiagnosticEngine &Diags) {
|
||||
Type T = TAD->getUnderlyingType();
|
||||
|
||||
if (hasExistentialAnyInType(T))
|
||||
Diags.diagnose(TAD->getLoc(), diag::perf_hint_typealias_uses_existential,
|
||||
TAD);
|
||||
}
|
||||
|
||||
/// Produce performance hint diagnostics for a SourceFile.
|
||||
class PerformanceHintDiagnosticWalker final : public ASTWalker {
|
||||
ASTContext &Ctx;
|
||||
@@ -64,16 +125,64 @@ public:
|
||||
SF->walk(Walker);
|
||||
}
|
||||
|
||||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
|
||||
if (P->isImplicit())
|
||||
return Action::SkipNode(P);
|
||||
|
||||
return Action::Continue(P);
|
||||
}
|
||||
|
||||
PostWalkResult<Pattern *> walkToPatternPost(Pattern *P) override {
|
||||
assert(!P->isImplicit() &&
|
||||
"Traversing implicit patterns is disabled in the pre-walk visitor");
|
||||
|
||||
if (const AnyPattern *AP = dyn_cast<AnyPattern>(P)) {
|
||||
checkExistentialInPatternType(AP, Ctx.Diags);
|
||||
}
|
||||
|
||||
return Action::Continue(P);
|
||||
}
|
||||
|
||||
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
|
||||
if (auto Closure = dyn_cast<ClosureExpr>(E))
|
||||
checkImplicitCopyReturnType(Closure, Ctx.Diags);
|
||||
if (E->isImplicit())
|
||||
return Action::SkipNode(E);
|
||||
|
||||
return Action::Continue(E);
|
||||
}
|
||||
|
||||
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
|
||||
assert(
|
||||
!E->isImplicit() &&
|
||||
"Traversing implicit expressions is disabled in the pre-walk visitor");
|
||||
|
||||
if (const ClosureExpr *CE = dyn_cast<ClosureExpr>(E)) {
|
||||
checkImplicitCopyReturnType(CE, Ctx.Diags);
|
||||
checkExistentialInClosureReturnType(CE, Ctx.Diags);
|
||||
}
|
||||
|
||||
return Action::Continue(E);
|
||||
}
|
||||
|
||||
PreWalkAction walkToDeclPre(Decl *D) override {
|
||||
if (auto *FD = dyn_cast<FuncDecl>(D))
|
||||
if (D->isImplicit())
|
||||
return Action::SkipNode();
|
||||
|
||||
return Action::Continue();
|
||||
}
|
||||
|
||||
PostWalkAction walkToDeclPost(Decl *D) override {
|
||||
assert(
|
||||
!D->isImplicit() &&
|
||||
"Traversing implicit declarations is disabled in the pre-walk visitor");
|
||||
|
||||
if (const FuncDecl *FD = dyn_cast<FuncDecl>(D)) {
|
||||
checkImplicitCopyReturnType(FD, Ctx.Diags);
|
||||
checkExistentialInFunctionReturnType(FD, Ctx.Diags);
|
||||
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
checkExistentialInVariableType(VD, Ctx.Diags);
|
||||
} else if (const TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(D)) {
|
||||
checkExistentialInTypeAlias(TAD, Ctx.Diags);
|
||||
}
|
||||
|
||||
return Action::Continue();
|
||||
}
|
||||
|
||||
246
test/PerformanceHints/existential-any.swift
Normal file
246
test/PerformanceHints/existential-any.swift
Normal file
@@ -0,0 +1,246 @@
|
||||
// RUN: %target-typecheck-verify-swift -Werror ExistentialType
|
||||
|
||||
protocol Animal {
|
||||
var Name: String { get }
|
||||
}
|
||||
|
||||
struct Tiger: Animal {
|
||||
let Name: String = "Tiger"
|
||||
}
|
||||
|
||||
struct Panda: Animal {
|
||||
let Name: String = "Panda"
|
||||
}
|
||||
|
||||
struct AnimalError: Error {
|
||||
let reason: String
|
||||
|
||||
init(reason: String) {
|
||||
self.reason = reason
|
||||
}
|
||||
}
|
||||
|
||||
struct Container<T> {
|
||||
let value: T
|
||||
}
|
||||
|
||||
protocol Person {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Typealias
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typealias AnyAnimal = any Animal // expected-error {{Performance: 'AnyAnimal' aliases an existential type, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
typealias AnimalContainer<T> = Container<any Animal> // expected-error {{Performance: 'AnimalContainer' aliases an existential type, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
typealias AnimalHandler = (any Animal) -> (any Animal)? // expected-error {{Performance: 'AnimalHandler' aliases an existential type, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Function Return Type
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Regular
|
||||
func returnAnimal1() -> any Animal { return Tiger() } // expected-error {{Performance: 'returnAnimal1()' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
// Optional
|
||||
func returnAnimal2() -> (any Animal)? { // expected-error {{Performance: 'returnAnimal2()' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
let n = Int.random(in: 1...100)
|
||||
return (n <= 50) ? nil : Tiger()
|
||||
}
|
||||
|
||||
// Throwing
|
||||
func returnAnimal3() throws -> any Animal { // expected-error {{Performance: 'returnAnimal3()' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
let n = Int.random(in: 1...100)
|
||||
if n <= 50 {
|
||||
throw AnimalError(reason: "All animals are extinct.")
|
||||
} else {
|
||||
return Tiger()
|
||||
}
|
||||
}
|
||||
|
||||
// Async
|
||||
func returnAnimal4() async -> any Animal {} // expected-error {{Performance: 'returnAnimal4()' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Function Parameter Type
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Regular parameters
|
||||
func animalParam1(_ animal: any Animal) {} // expected-error {{Performance: 'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead}}
|
||||
|
||||
// Multiple parameters
|
||||
func animalParam2(
|
||||
_ animal: any Animal, // expected-error {{Performance: 'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
to other: any Animal // expected-error {{Performance: 'other' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
) {}
|
||||
|
||||
// Variadic parameters
|
||||
func animalParam3(_ animals: any Animal...) {} // expected-error {{Performance: 'animals' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
// In-out parameters
|
||||
func animalParam4(_ animal: inout any Animal) {} // expected-error {{Performance: 'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Protocol
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
protocol AnimalShelter {
|
||||
var animal: (any Animal)? { // expected-error {{Performance: 'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
get // expected-error {{Performance: getter for 'animal' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
}
|
||||
func admit(_ animal: any Animal) // expected-error {{Performance: 'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
func releaseAnimal() -> (any Animal)? // expected-error {{Performance: 'releaseAnimal()' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
subscript(id: String) -> (any Animal)? { get } // expected-error {{Performance: getter for 'subscript(_:)' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class Zoo {
|
||||
var animals: [any Animal] // expected-error {{Performance: 'animals' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
init(with animal: any Animal) { // expected-error {{Performance: 'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
self.animals = [animal]
|
||||
}
|
||||
|
||||
init(animals: [any Animal]) { // expected-error {{Performance: 'animals' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
self.animals = animals
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Compound Types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
func testCompoundTypes() {
|
||||
let animals1: [any Animal] = [] // expected-error {{Performance: 'animals1' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals1))
|
||||
|
||||
let animals2: [any Animal] = [] // expected-error {{Performance: 'animals2' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals2))
|
||||
|
||||
let animals3: [String: any Animal] = [:] // expected-error {{Performance: 'animals3' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals3))
|
||||
|
||||
let animals4: [String: any Animal] = [:] // expected-error {{Performance: 'animals4' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals4))
|
||||
|
||||
let animals5: (any Animal)? = nil // expected-error {{Performance: 'animals5' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals5))
|
||||
|
||||
let animals6: (any Animal)? = nil // expected-error {{Performance: 'animals6' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals6))
|
||||
|
||||
let animals7: Result<any Animal, Error> = .success(Tiger()) // expected-error {{Performance: 'animals7' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: animals7))
|
||||
|
||||
let container = Container<any Animal>(value: Tiger()) // expected-error {{Performance: 'container' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: container))
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Tuple
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
func tupleTest() {
|
||||
let _ = ([Tiger() as any Animal], [Panda() as any Animal]) // expected-error {{Performance: declaration uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
let (
|
||||
animalsA, // expected-error {{Performance: 'animalsA' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
animalsB // expected-error {{Performance: 'animalsB' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
) = ([Tiger() as any Animal], [Panda() as any Animal])
|
||||
print(type(of: animalsA))
|
||||
print(type(of: animalsB))
|
||||
|
||||
let (
|
||||
_, // expected-error {{Performance: declaration uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
animalsC // expected-error {{Performance: 'animalsC' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
) = ([Tiger() as any Animal], [Panda() as any Animal])
|
||||
|
||||
print(type(of: animalsC))
|
||||
|
||||
let (_, _) = ([Tiger() as any Animal], [Panda() as any Animal]) // expected-error 2 {{Performance: declaration uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
let tuple: (animal1: any Animal, animal2: any Animal) = (Tiger(), Panda()) // expected-error {{Performance: 'tuple' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: tuple))
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Closure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
func closureTest() {
|
||||
// Closure parameter type
|
||||
let handler: (any Animal) -> Void = { // expected-error {{Performance: 'handler' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
animal in print(type(of: animal)) // expected-error {{'animal' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
}
|
||||
handler(Tiger())
|
||||
|
||||
// Closure return type
|
||||
let factory: () -> any Animal = { Tiger() } // expected-error {{Performance: 'factory' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}} expected-error {{Performance: closure returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: factory()))
|
||||
|
||||
// Both parameter and return types
|
||||
let transformer: (any Animal) -> any Animal = { $0 } // expected-error {{Performance: 'transformer' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}} expected-error {{Performance: closure returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: transformer(Tiger())))
|
||||
|
||||
// Escaping closures
|
||||
var handlers: [(any Animal) -> Void] = [] // expected-error {{Performance: 'handlers' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
func registerHandler(with handler: @escaping (any Animal) -> Void) { // expected-error {{Performance: 'handler' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
handlers.append(handler)
|
||||
}
|
||||
|
||||
// Autoclosure
|
||||
func registerHandler2(animalThunk: @autoclosure () -> any Animal) { // expected-error {{Performance: 'animalThunk' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
handlers[0](animalThunk())
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Type casting
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
protocol A {
|
||||
}
|
||||
|
||||
protocol A1: A {
|
||||
}
|
||||
|
||||
protocol A2: A {
|
||||
}
|
||||
|
||||
struct S1: A1 {
|
||||
}
|
||||
|
||||
struct S2: A2 {
|
||||
}
|
||||
|
||||
func testTypeCasting() {
|
||||
let randomNumber = Int.random(in: 1...100)
|
||||
|
||||
let value: any A = randomNumber <= 50 ? S1() : S2() // expected-error {{Performance: 'value' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
|
||||
let a1 = value as? any A1 // expected-error {{Performance: 'a1' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: a1))
|
||||
|
||||
let a2 = value as! any A2 // expected-error {{Performance: 'a2' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
print(type(of: a2))
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Enum
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
enum PetOwnership {
|
||||
case owned(
|
||||
pet: any Animal, // expected-error {{Performance: 'pet' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
owner: any Person) // expected-error {{Performance: 'owner' uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
case stray(any Animal) // expected-error {{Performance: parameter uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
case multiple([any Animal]) // expected-error {{Performance: parameter uses an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// An existential in parent type
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct Outer<T> {
|
||||
struct Inner {}
|
||||
var i = Inner()
|
||||
}
|
||||
|
||||
func f() -> Outer<any Animal>.Inner { // expected-error {{Performance: 'f()' returns an existential, leading to heap allocation, reference counting, and dynamic dispatch. Consider using generic constraints or concrete types instead.}}
|
||||
return Outer<any Animal>().i
|
||||
}
|
||||
Reference in New Issue
Block a user