Skip to content

Commit 3e981b7

Browse files
authored
Merge pull request #84374 from DougGregor/embedded-swift-restrictions
Embedded swift restrictions
2 parents dbc93c5 + 9bdd7db commit 3e981b7

12 files changed

+322
-43
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -378,52 +378,57 @@ ERROR(bad_attr_on_non_const_global,none,
378378
"global variable must be a compile-time constant to use %0 attribute", (StringRef))
379379
ERROR(global_must_be_compile_time_const,none,
380380
"global variable must be a compile-time constant", ())
381-
ERROR(embedded_cannot_specialize_class_method,none,
381+
ERROR(perf_diag_existential_type,none,
382+
"cannot use a value of protocol type %0 in '@_noExistential' function", (Type))
383+
ERROR(perf_diag_existential,none,
384+
"cannot use a value of protocol type in '@_noExistential' function", ())
385+
386+
// Embedded Swift diagnostics
387+
GROUPED_ERROR(embedded_cannot_specialize_class_method,EmbeddedRestrictions,none,
382388
"classes cannot have a non-final, generic method %0 in embedded Swift", (DeclName))
383-
ERROR(embedded_cannot_specialize_witness_method,none,
389+
GROUPED_ERROR(embedded_cannot_specialize_witness_method,EmbeddedRestrictions,none,
384390
"a protocol type cannot contain a generic method %0 in embedded Swift", (DeclName))
385-
ERROR(cannot_specialize_class,none,
391+
GROUPED_ERROR(cannot_specialize_class,EmbeddedRestrictions,none,
386392
"cannot specialize %0 because class definition is not available (make sure to build with -wmo)", (Type))
387-
ERROR(embedded_swift_existential_type,none,
393+
GROUPED_ERROR(embedded_swift_existential_type,EmbeddedRestrictions,none,
388394
"cannot use a value of protocol type %0 in embedded Swift", (Type))
389-
ERROR(embedded_swift_existential_protocol,none,
395+
GROUPED_ERROR(embedded_swift_existential_protocol,EmbeddedRestrictions,none,
390396
"cannot use a value of protocol type 'any %0' in embedded Swift", (StringRef))
391-
ERROR(embedded_swift_existential,none,
397+
GROUPED_ERROR(embedded_swift_existential,EmbeddedRestrictions,none,
392398
"cannot use a value of protocol type in embedded Swift", ())
393-
ERROR(perf_diag_existential_type,none,
394-
"cannot use a value of protocol type %0 in '@_noExistential' function", (Type))
395-
ERROR(perf_diag_existential,none,
396-
"cannot use a value of protocol type in '@_noExistential' function", ())
397-
ERROR(embedded_swift_value_deinit,none,
399+
GROUPED_ERROR(embedded_swift_value_deinit,EmbeddedRestrictions,none,
398400
"cannot de-virtualize deinit of type %0", (Type))
399-
ERROR(embedded_swift_metatype_type,none,
401+
GROUPED_ERROR(embedded_swift_metatype_type,EmbeddedRestrictions,none,
400402
"cannot use metatype of type %0 in embedded Swift", (Type))
401-
ERROR(embedded_swift_metatype,none,
403+
GROUPED_ERROR(embedded_swift_metatype,EmbeddedRestrictions,none,
402404
"cannot use metatype in embedded Swift", ())
403-
ERROR(embedded_swift_keypath,none,
405+
GROUPED_ERROR(embedded_swift_keypath,EmbeddedRestrictions,none,
404406
"cannot use key path in embedded Swift", ())
405-
ERROR(embedded_swift_dynamic_cast,none,
407+
GROUPED_ERROR(embedded_swift_dynamic_cast,EmbeddedRestrictions,none,
406408
"cannot do dynamic casting in embedded Swift", ())
407-
ERROR(embedded_swift_allocating_type,none,
408-
"cannot use allocating type %0 in -no-allocations mode", (Type))
409-
ERROR(embedded_swift_allocating_coroutine,none,
410-
"cannot use co-routines (like accessors) in -no-allocations mode", ())
411-
ERROR(embedded_swift_allocating_closure,none,
412-
"cannot use escaping closures in -no-allocations mode", ())
413-
ERROR(embedded_swift_allocating,none,
414-
"cannot use allocating operation in -no-allocations mode", ())
415-
ERROR(embedded_capture_of_generic_value_with_deinit,none,
409+
GROUPED_ERROR(embedded_capture_of_generic_value_with_deinit,EmbeddedRestrictions,none,
416410
"capturing generic non-copyable type with deinit in escaping closure not supported in embedded Swift", ())
417-
ERROR(embedded_call_generic_function,none,
411+
GROUPED_ERROR(embedded_call_generic_function,EmbeddedRestrictions,none,
418412
"cannot specialize generic function or default protocol method in this context", ())
419-
ERROR(embedded_call_generic_function_with_dynamic_self,none,
413+
GROUPED_ERROR(embedded_call_generic_function_with_dynamic_self,EmbeddedRestrictions,none,
420414
"cannot call an initializer or static method, which is defined as default protocol method, from a class method or initializer", ())
421415
NOTE(embedded_specialization_called_from,none,
422416
"generic specialization called here", ())
423417
NOTE(embedded_existential_created,none,
424418
"protocol type value created here", ())
425419
NOTE(embedded_constructor_called,none,
426420
"instance of type created here", ())
421+
422+
// no-allocations diagnostics
423+
ERROR(embedded_swift_allocating_type,none,
424+
"cannot use allocating type %0 in -no-allocations mode", (Type))
425+
ERROR(embedded_swift_allocating_coroutine,none,
426+
"cannot use co-routines (like accessors) in -no-allocations mode", ())
427+
ERROR(embedded_swift_allocating_closure,none,
428+
"cannot use escaping closures in -no-allocations mode", ())
429+
ERROR(embedded_swift_allocating,none,
430+
"cannot use allocating operation in -no-allocations mode", ())
431+
427432
ERROR(wrong_linkage_for_serialized_function,none,
428433
"function has wrong linkage to be called from %0", (StringRef))
429434
NOTE(performance_called_from,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8616,6 +8616,18 @@ GROUPED_ERROR(weak_unowned_in_embedded_swift, EmbeddedRestrictions, none,
86168616
GROUPED_WARNING(untyped_throws_in_embedded_swift, EmbeddedRestrictions,
86178617
DefaultIgnore,
86188618
"untyped throws is not available in Embedded Swift; add a thrown error type with '(type)'", ())
8619+
GROUPED_WARNING(generic_nonfinal_in_embedded_swift, EmbeddedRestrictions,
8620+
DefaultIgnore,
8621+
"generic %kind0 in a class %select{must be 'final'|cannot be 'required'}1 in Embedded Swift",
8622+
(const Decl *, bool))
8623+
GROUPED_WARNING(use_generic_member_of_existential_in_embedded_swift,
8624+
EmbeddedRestrictions, DefaultIgnore,
8625+
"cannot use generic %kind0 on a value of type %1 in Embedded Swift",
8626+
(const Decl *, Type))
8627+
GROUPED_WARNING(dynamic_cast_involving_protocol_in_embedded_swift,
8628+
EmbeddedRestrictions, DefaultIgnore,
8629+
"cannot perform a dynamic cast to a type involving %kind0 in Embedded Swift",
8630+
(const Decl *))
86198631

86208632
//===----------------------------------------------------------------------===//
86218633
// MARK: @abi Attribute

lib/Sema/CSApply.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "MiscDiagnostics.h"
2222
#include "OpenedExistentials.h"
2323
#include "TypeCheckConcurrency.h"
24+
#include "TypeCheckEmbedded.h"
2425
#include "TypeCheckMacros.h"
2526
#include "TypeCheckProtocol.h"
2627
#include "TypeCheckType.h"
@@ -924,8 +925,9 @@ namespace {
924925
/// \returns An OpaqueValueExpr that provides a reference to the value
925926
/// stored within the expression or its metatype (if the base was a
926927
/// metatype).
927-
Expr *openExistentialReference(Expr *base, ExistentialArchetypeType *archetype,
928-
ValueDecl *member) {
928+
Expr *openExistentialReference(Expr *base,
929+
ExistentialArchetypeType *archetype,
930+
ValueDecl *member, SourceLoc memberLoc) {
929931
assert(archetype && "archetype not already opened?");
930932

931933
// Dig out the base type.
@@ -955,6 +957,11 @@ namespace {
955957

956958
assert(baseTy->isAnyExistentialType() && "Type must be existential");
957959

960+
// Embedded Swift has limitations on the use of generic members of
961+
// existentials. Diagnose them here.
962+
diagnoseGenericMemberOfExistentialInEmbedded(
963+
dc, memberLoc, baseTy, member);
964+
958965
// If the base was an lvalue but it will only be treated as an
959966
// rvalue, turn the base into an rvalue now. This results in
960967
// better SILGen.
@@ -1983,7 +1990,8 @@ namespace {
19831990
(!member->getDeclContext()->getSelfProtocolDecl() &&
19841991
baseIsInstance && member->isInstanceMember())) {
19851992
// Open the existential before performing the member reference.
1986-
base = openExistentialReference(base, knownOpened->second, member);
1993+
base = openExistentialReference(base, knownOpened->second, member,
1994+
memberLoc.getBaseNameLoc());
19871995
baseTy = baseOpenedTy;
19881996
selfTy = baseTy;
19891997
openedExistential = true;
@@ -2490,7 +2498,8 @@ namespace {
24902498
auto memberLoc = cs.getCalleeLocator(cs.getConstraintLocator(locator));
24912499
auto knownOpened = solution.OpenedExistentialTypes.find(memberLoc);
24922500
if (knownOpened != solution.OpenedExistentialTypes.end()) {
2493-
base = openExistentialReference(base, knownOpened->second, subscript);
2501+
base = openExistentialReference(base, knownOpened->second, subscript,
2502+
args->getLoc());
24942503
baseTy = knownOpened->second;
24952504
}
24962505

@@ -6551,7 +6560,8 @@ ArgumentList *ExprRewriter::coerceCallArguments(
65516560
cs.getConstraintLocator(argLoc));
65526561
if (knownOpened != solution.OpenedExistentialTypes.end()) {
65536562
argExpr = openExistentialReference(
6554-
argExpr, knownOpened->second, callee.getDecl());
6563+
argExpr, knownOpened->second, callee.getDecl(),
6564+
apply ? apply->getLoc() : argExpr->getLoc());
65556565
argType = cs.getType(argExpr);
65566566
}
65576567
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "MiscDiagnostics.h"
1818
#include "TypeCheckAvailability.h"
1919
#include "TypeCheckConcurrency.h"
20+
#include "TypeCheckEmbedded.h"
2021
#include "TypeCheckInvertible.h"
2122
#include "TypeChecker.h"
2223
#include "swift/AST/ASTBridging.h"
@@ -390,6 +391,9 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
390391
}
391392
}
392393

394+
// Embedded Swift places restrictions on dynamic casting.
395+
diagnoseDynamicCastInEmbedded(DC, cast);
396+
393397
// now, look for conditional casts to marker protocols.
394398

395399
if (!isa<ConditionalCheckedCastExpr>(cast) && !isa<IsExpr>(cast))

lib/Sema/TypeCheckEmbedded.cpp

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,31 @@
1919
#include "swift/AST/Decl.h"
2020
#include "swift/AST/DiagnosticsSema.h"
2121
#include "swift/AST/Effects.h"
22+
#include "swift/AST/Expr.h"
23+
#include "swift/AST/ExistentialLayout.h"
2224
#include "swift/AST/SourceFile.h"
2325
#include "swift/AST/Types.h"
2426
#include "swift/Basic/SourceLoc.h"
2527
#include "swift/Bridging/ASTGen.h"
2628

2729
using namespace swift;
2830

31+
static DiagnosticBehavior
32+
defaultEmbeddedLimitationForError(const DeclContext *dc, SourceLoc loc) {
33+
if (dc->getASTContext().LangOpts.hasFeature(Feature::Embedded))
34+
return DiagnosticBehavior::Unspecified;
35+
36+
return DiagnosticBehavior::Warning;
37+
}
38+
2939
std::optional<DiagnosticBehavior>
3040
swift::shouldDiagnoseEmbeddedLimitations(const DeclContext *dc, SourceLoc loc,
3141
bool wasAlwaysEmbeddedError) {
3242
// In Embedded Swift, things that were always errors will still be emitted
3343
// as errors. Use "unspecified" so we don't change anything.
3444
if (dc->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
3545
wasAlwaysEmbeddedError) {
36-
return DiagnosticBehavior::Unspecified;
46+
return defaultEmbeddedLimitationForError(dc, loc);
3747
}
3848

3949
// Check one of the Embedded restriction diagnostics that is ignored by
@@ -66,6 +76,42 @@ swift::shouldDiagnoseEmbeddedLimitations(const DeclContext *dc, SourceLoc loc,
6676
return DiagnosticBehavior::Unspecified;
6777
}
6878

79+
/// Determine whether the inner signature is more generic than the outer
80+
/// signature, ignoring differences that
81+
static bool isABIMoreGenericThan(GenericSignature innerSig, GenericSignature outerSig) {
82+
auto canInnerSig = innerSig.getCanonicalSignature();
83+
auto canOuterSig = outerSig.getCanonicalSignature();
84+
if (canInnerSig == canOuterSig)
85+
return false;
86+
87+
// The inner signature added generic parameters.
88+
if (canOuterSig.getGenericParams().size() !=
89+
canInnerSig.getGenericParams().size())
90+
return true;
91+
92+
// Look at the requirements of the inner signature that aren't satisfied
93+
// by the outer signature, to see if there are any requirements that aren't
94+
// just marker protocols.
95+
auto requirements = canInnerSig.requirementsNotSatisfiedBy(canOuterSig);
96+
for (const auto &req : requirements) {
97+
switch (req.getKind()) {
98+
case RequirementKind::Conformance:
99+
if (req.getProtocolDecl()->isMarkerProtocol())
100+
continue;
101+
102+
return true;
103+
104+
case RequirementKind::Superclass:
105+
case RequirementKind::Layout:
106+
case RequirementKind::SameShape:
107+
case RequirementKind::SameType:
108+
return true;
109+
}
110+
}
111+
112+
return false;
113+
}
114+
69115
/// Check embedded restrictions in the signature of the given function.
70116
void swift::checkEmbeddedRestrictionsInSignature(
71117
const AbstractFunctionDecl *func) {
@@ -80,6 +126,20 @@ void swift::checkEmbeddedRestrictionsInSignature(
80126
!func->hasPolymorphicEffect(EffectKind::Throws)) {
81127
diagnoseUntypedThrowsInEmbedded(func, throwsLoc);
82128
}
129+
130+
// If we're in a class, one cannot have a non-final generic function.
131+
if (auto classDecl = dyn_cast<ClassDecl>(func->getDeclContext())) {
132+
if (!classDecl->isSemanticallyFinal() &&
133+
((isa<FuncDecl>(func) && !func->isSemanticallyFinal()) ||
134+
(isa<ConstructorDecl>(func) &&
135+
cast<ConstructorDecl>(func)->isRequired())) &&
136+
isABIMoreGenericThan(func->getGenericSignature(),
137+
classDecl->getGenericSignature())) {
138+
func->diagnose(diag::generic_nonfinal_in_embedded_swift, func,
139+
isa<ConstructorDecl>(func))
140+
.limitBehavior(defaultEmbeddedLimitationForError(func, func->getLoc()));
141+
}
142+
}
83143
}
84144

85145
void swift::diagnoseUntypedThrowsInEmbedded(
@@ -94,3 +154,45 @@ void swift::diagnoseUntypedThrowsInEmbedded(
94154
.limitBehavior(*behavior)
95155
.fixItInsertAfter(throwsLoc, "(<#thrown error type#>)");
96156
}
157+
158+
void swift::diagnoseGenericMemberOfExistentialInEmbedded(
159+
const DeclContext *dc, SourceLoc loc,
160+
Type baseType, const ValueDecl *member) {
161+
// If we are not supposed to diagnose Embedded Swift limitations, do nothing.
162+
auto behavior = shouldDiagnoseEmbeddedLimitations(dc, loc);
163+
if (!behavior)
164+
return;
165+
166+
if (isABIMoreGenericThan(
167+
member->getInnermostDeclContext()->getGenericSignatureOfContext(),
168+
member->getDeclContext()->getGenericSignatureOfContext())) {
169+
dc->getASTContext().Diags.diagnose(loc, diag::use_generic_member_of_existential_in_embedded_swift, member,
170+
baseType)
171+
.limitBehavior(*behavior);
172+
}
173+
}
174+
175+
void swift::diagnoseDynamicCastInEmbedded(
176+
const DeclContext *dc, const CheckedCastExpr *cast) {
177+
// If we are not supposed to diagnose Embedded Swift limitations, do nothing.
178+
auto behavior = shouldDiagnoseEmbeddedLimitations(dc, cast->getLoc());
179+
if (!behavior)
180+
return;
181+
182+
// We only care about casts to existential types.
183+
Type toType = cast->getCastType()->lookThroughAllOptionalTypes();
184+
if (!toType->isAnyExistentialType())
185+
return;
186+
187+
ExistentialLayout layout = toType->getExistentialLayout();
188+
for (auto proto : layout.getProtocols()) {
189+
if (proto->isMarkerProtocol())
190+
continue;
191+
192+
dc->getASTContext().Diags.diagnose(
193+
cast->getLoc(),
194+
diag::dynamic_cast_involving_protocol_in_embedded_swift, proto)
195+
.limitBehaviorIf(behavior);
196+
return;
197+
}
198+
}

lib/Sema/TypeCheckEmbedded.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ namespace swift {
2424
class AbstractFunctionDecl;
2525
class DeclContext;
2626
struct DiagnosticBehavior;
27+
class CheckedCastExpr;
2728
class SourceLoc;
28-
29+
class Type;
30+
class ValueDecl;
31+
2932
/// Whether we should diagnose language-level limitations of Embedded Swift
3033
/// at the given source location, and how.
3134
///
@@ -46,5 +49,16 @@ void checkEmbeddedRestrictionsInSignature(const AbstractFunctionDecl *func);
4649
/// Diagnose a declaration of typed throws at the given location.
4750
void diagnoseUntypedThrowsInEmbedded(const DeclContext *dc, SourceLoc throwsLoc);
4851

52+
/// Diagnose references to a generic member via an existential type, which are
53+
/// not available in Embedded Swift.
54+
void diagnoseGenericMemberOfExistentialInEmbedded(
55+
const DeclContext *dc, SourceLoc loc,
56+
Type baseType, const ValueDecl *member);
57+
58+
/// Diagnose dynamic casts (is/as?/as!) to a type, which is not always available
59+
/// in Embedded Swift.
60+
void diagnoseDynamicCastInEmbedded(
61+
const DeclContext *dc, const CheckedCastExpr *cast);
62+
4963
}
5064
#endif // SWIFT_SEMA_TYPECHECKEMBEDDED_H

0 commit comments

Comments
 (0)