mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Embedded] Diagnose dynamic casts to existentials
Embedded Swift doesn't have protocol conformance metadata, so it cannot handle dynamic casts to existentials (nor should it). Another part of rdar://119383905.
This commit is contained in:
@@ -8620,6 +8620,10 @@ GROUPED_WARNING(use_generic_member_of_existential_in_embedded_swift,
|
||||
EmbeddedRestrictions, DefaultIgnore,
|
||||
"cannot use generic %kind0 on a value of type %1 in Embedded Swift",
|
||||
(const Decl *, Type))
|
||||
GROUPED_WARNING(dynamic_cast_involving_protocol_in_embedded_swift,
|
||||
EmbeddedRestrictions, DefaultIgnore,
|
||||
"cannot perform a dynamic cast to a type involving %kind0 in Embedded Swift",
|
||||
(const Decl *))
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MARK: @abi Attribute
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "MiscDiagnostics.h"
|
||||
#include "TypeCheckAvailability.h"
|
||||
#include "TypeCheckConcurrency.h"
|
||||
#include "TypeCheckEmbedded.h"
|
||||
#include "TypeCheckInvertible.h"
|
||||
#include "TypeChecker.h"
|
||||
#include "swift/AST/ASTBridging.h"
|
||||
@@ -390,6 +391,9 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
|
||||
}
|
||||
}
|
||||
|
||||
// Embedded Swift places restrictions on dynamic casting.
|
||||
diagnoseDynamicCastInEmbedded(DC, cast);
|
||||
|
||||
// now, look for conditional casts to marker protocols.
|
||||
|
||||
if (!isa<ConditionalCheckedCastExpr>(cast) && !isa<IsExpr>(cast))
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "swift/AST/Decl.h"
|
||||
#include "swift/AST/DiagnosticsSema.h"
|
||||
#include "swift/AST/Effects.h"
|
||||
#include "swift/AST/Expr.h"
|
||||
#include "swift/AST/ExistentialLayout.h"
|
||||
#include "swift/AST/SourceFile.h"
|
||||
#include "swift/AST/Types.h"
|
||||
#include "swift/Basic/SourceLoc.h"
|
||||
@@ -157,7 +159,7 @@ void swift::diagnoseGenericMemberOfExistentialInEmbedded(
|
||||
const DeclContext *dc, SourceLoc loc,
|
||||
Type baseType, const ValueDecl *member) {
|
||||
// If we are not supposed to diagnose Embedded Swift limitations, do nothing.
|
||||
auto behavior = shouldDiagnoseEmbeddedLimitations(dc, loc, true);
|
||||
auto behavior = shouldDiagnoseEmbeddedLimitations(dc, loc);
|
||||
if (!behavior)
|
||||
return;
|
||||
|
||||
@@ -169,3 +171,28 @@ void swift::diagnoseGenericMemberOfExistentialInEmbedded(
|
||||
.limitBehavior(*behavior);
|
||||
}
|
||||
}
|
||||
|
||||
void swift::diagnoseDynamicCastInEmbedded(
|
||||
const DeclContext *dc, const CheckedCastExpr *cast) {
|
||||
// If we are not supposed to diagnose Embedded Swift limitations, do nothing.
|
||||
auto behavior = shouldDiagnoseEmbeddedLimitations(dc, cast->getLoc());
|
||||
if (!behavior)
|
||||
return;
|
||||
|
||||
// We only care about casts to existential types.
|
||||
Type toType = cast->getCastType()->lookThroughAllOptionalTypes();
|
||||
if (!toType->isAnyExistentialType())
|
||||
return;
|
||||
|
||||
ExistentialLayout layout = toType->getExistentialLayout();
|
||||
for (auto proto : layout.getProtocols()) {
|
||||
if (proto->isMarkerProtocol())
|
||||
continue;
|
||||
|
||||
dc->getASTContext().Diags.diagnose(
|
||||
cast->getLoc(),
|
||||
diag::dynamic_cast_involving_protocol_in_embedded_swift, proto)
|
||||
.limitBehaviorIf(behavior);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace swift {
|
||||
class AbstractFunctionDecl;
|
||||
class DeclContext;
|
||||
struct DiagnosticBehavior;
|
||||
class CheckedCastExpr;
|
||||
class SourceLoc;
|
||||
class Type;
|
||||
class ValueDecl;
|
||||
@@ -53,5 +54,11 @@ void diagnoseUntypedThrowsInEmbedded(const DeclContext *dc, SourceLoc throwsLoc)
|
||||
void diagnoseGenericMemberOfExistentialInEmbedded(
|
||||
const DeclContext *dc, SourceLoc loc,
|
||||
Type baseType, const ValueDecl *member);
|
||||
|
||||
/// Diagnose dynamic casts (is/as?/as!) to a type, which is not always available
|
||||
/// in Embedded Swift.
|
||||
void diagnoseDynamicCastInEmbedded(
|
||||
const DeclContext *dc, const CheckedCastExpr *cast);
|
||||
|
||||
}
|
||||
#endif // SWIFT_SEMA_TYPECHECKEMBEDDED_H
|
||||
|
||||
@@ -14,6 +14,7 @@ public func test() -> Int {
|
||||
|
||||
func castToExistential<T>(x: T) {
|
||||
if x is any FixedWidthInteger { // expected-error {{cannot do dynamic casting in embedded Swift}}
|
||||
// expected-warning@-1{{cannot perform a dynamic cast to a type involving protocol 'FixedWidthInteger' in Embedded Swift}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +111,30 @@ public func existentials(q: any AnyObject & Q, i: Int) {
|
||||
qm.h(i) // expected-warning{{cannot use generic instance method 'h' on a value of type 'any AnyObject & Q' in Embedded Swift}}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Dynamic casting restrictions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class ConformsToQ: Q {
|
||||
final func f<T>(_ value: T) { }
|
||||
func okay() { }
|
||||
}
|
||||
|
||||
func dynamicCasting(object: AnyObject, cq: ConformsToQ) {
|
||||
// expected-warning@+1{{cannot perform a dynamic cast to a type involving protocol 'Q' in Embedded Swift}}
|
||||
if let q = object as? any AnyObject & Q {
|
||||
_ = q
|
||||
}
|
||||
|
||||
// expected-warning@+1{{cannot perform a dynamic cast to a type involving protocol 'Q' in Embedded Swift}}
|
||||
if object is any AnyObject & Q { }
|
||||
|
||||
// expected-warning@+1{{cannot perform a dynamic cast to a type involving protocol 'Q' in Embedded Swift}}
|
||||
_ = object as! AnyObject & Q
|
||||
|
||||
_ = cq as AnyObject & Q
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// #if handling to suppress diagnostics for non-Embedded-only code
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -12,6 +12,15 @@ Diagnostics in the `EmbeddedRestrictions` group describe those language features
|
||||
weak var parent: Node? // error: attribute 'weak' cannot be used in Embedded Swift
|
||||
}
|
||||
|
||||
* Dynamic casts to a type involving a protocol are not supported, because Embedded Swift does not include runtime metadata about protocol conformances. For example:
|
||||
|
||||
protocol P: AnyObject { }
|
||||
func casting(object: AnyObject) {
|
||||
if let p = object as? P { // error: cannot perform a dynamic cast to a type involving protocol 'P' in Embedded Swift
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
* Non-final generic methods in a class, which are prohibited because they cannot be specialized for every possible call site. For example:
|
||||
|
||||
class MyGenericClass<T> {
|
||||
|
||||
Reference in New Issue
Block a user