Skip to content

Commit 7d21bc3

Browse files
committed
[Embedded] Diagnose untyped throws as an Embedded Swift restriction
Untyped throws depends on existentials (`any Error`), and is therefore not available in Embedded Swift. Introduce a diagnostic that diagnoses any use of untyped throws, suggesting that one use typed throws instead. Make this an opt-in diagnostic enabled with `-Wwarning EmbeddedRestrictions`, whether in Embedded Swift or not, using the "default ignore" flag on these new warnings. Document this new diagnostic group, and put the existing Embedded Swift error about weak/unowned references in it as well. Part of the general push to have the type checker identify code that will not compile as Embedded Swift earlier, rdar://133874555.
1 parent f4dd6e2 commit 7d21bc3

14 files changed

+251
-8
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,10 @@ namespace swift {
701701
ignoredDiagnostics[(unsigned)id] = ignored;
702702
}
703703

704+
bool isIgnoredDiagnostic(DiagID id) const {
705+
return ignoredDiagnostics[(unsigned)id];
706+
}
707+
704708
void swap(DiagnosticState &other) {
705709
std::swap(showDiagnosticsAfterFatalError, other.showDiagnosticsAfterFatalError);
706710
std::swap(suppressWarnings, other.suppressWarnings);
@@ -947,6 +951,10 @@ namespace swift {
947951
state.setIgnoredDiagnostic(id, true);
948952
}
949953

954+
bool isIgnoredDiagnostic(DiagID id) const {
955+
return state.isIgnoredDiagnostic(id);
956+
}
957+
950958
void resetHadAnyError() {
951959
state.resetHadAnyError();
952960
}

include/swift/AST/DiagnosticGroups.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ GROUP(ClangDeclarationImport, "clang-declaration-import")
4646
GROUP(ConformanceIsolation, "conformance-isolation")
4747
GROUP(DeprecatedDeclaration, "deprecated-declaration")
4848
GROUP(DynamicCallable, "dynamic-callable-requirements")
49+
GROUP(EmbeddedRestrictions, "embedded-restrictions")
4950
GROUP(ErrorInFutureSwiftVersion, "error-in-future-swift-version")
5051
GROUP(ExclusivityViolation, "exclusivity-violation")
5152
GROUP(ExistentialAny, "existential-any")

include/swift/AST/DiagnosticsSema.def

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,9 +2234,6 @@ ERROR(attr_only_at_non_generic_scope, none,
22342234
ERROR(attr_only_on_static_properties, none,
22352235
"properties with attribute %0 must be static", (DeclAttribute))
22362236

2237-
ERROR(weak_unowned_in_embedded_swift, none,
2238-
"attribute %0 cannot be used in embedded Swift", (ReferenceOwnership))
2239-
22402237
ERROR(access_control_in_protocol,none,
22412238
"%0 modifier cannot be used in protocols", (DeclAttribute))
22422239
NOTE(access_control_in_protocol_detail,none,
@@ -8606,6 +8603,18 @@ ERROR(inlinearray_literal_incorrect_count,none,
86068603
ERROR(inline_array_type_backwards,none,
86078604
"element count must precede inline array element type", ())
86088605

8606+
//===----------------------------------------------------------------------===//
8607+
// MARK: Embedded Swift
8608+
//===----------------------------------------------------------------------===//
8609+
8610+
GROUPED_ERROR(weak_unowned_in_embedded_swift, EmbeddedRestrictions, none,
8611+
"attribute %0 cannot be used in Embedded Swift",
8612+
(ReferenceOwnership))
8613+
8614+
GROUPED_WARNING(untyped_throws_in_embedded_swift, EmbeddedRestrictions,
8615+
DefaultIgnore,
8616+
"untyped throws is not available in Embedded Swift; add a thrown error type with '(type)'", ())
8617+
86098618
//===----------------------------------------------------------------------===//
86108619
// MARK: @abi Attribute
86118620
//===----------------------------------------------------------------------===//

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ add_swift_host_library(swiftSema STATIC
6969
TypeCheckEffects.cpp
7070
TypeCheckExpr.cpp
7171
TypeCheckExprObjC.cpp
72+
TypeCheckEmbedded.cpp
7273
TypeCheckGeneric.cpp
7374
TypeCheckInvertible.cpp
7475
TypeCheckMacros.cpp

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "OpenedExistentials.h"
2121
#include "TypeCheckAvailability.h"
2222
#include "TypeCheckConcurrency.h"
23+
#include "TypeCheckEmbedded.h"
2324
#include "TypeCheckMacros.h"
2425
#include "TypeCheckType.h"
2526
#include "TypeChecker.h"
@@ -1456,6 +1457,9 @@ FunctionType::ExtInfo ClosureEffectsRequest::evaluate(
14561457
bool sendable = expr->getAttrs().hasAttribute<SendableAttr>();
14571458

14581459
if (throws || async) {
1460+
if (expr->getThrowsLoc().isValid() && !expr->getExplicitThrownTypeRepr())
1461+
diagnoseUntypedThrowsInEmbedded(expr, expr->getThrowsLoc());
1462+
14591463
return ASTExtInfoBuilder()
14601464
.withThrows(throws, /*FIXME:*/Type())
14611465
.withAsync(async)

lib/Sema/TypeCheckAttr.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "TypeCheckAvailability.h"
1919
#include "TypeCheckConcurrency.h"
2020
#include "TypeCheckDistributed.h"
21+
#include "TypeCheckEmbedded.h"
2122
#include "TypeCheckMacros.h"
2223
#include "TypeCheckObjC.h"
2324
#include "TypeCheckType.h"
@@ -5501,12 +5502,14 @@ Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
55015502
}
55025503

55035504
// Embedded Swift prohibits weak/unowned but allows unowned(unsafe).
5504-
if (ctx.LangOpts.hasFeature(Feature::Embedded)) {
5505+
if (auto behavior = shouldDiagnoseEmbeddedLimitations(
5506+
dc, attr->getLocation(),
5507+
/*wasAlwaysEmbeddedError=*/true)) {
55055508
if (ownershipKind == ReferenceOwnership::Weak ||
55065509
ownershipKind == ReferenceOwnership::Unowned) {
55075510
Diags.diagnose(attr->getLocation(), diag::weak_unowned_in_embedded_swift,
5508-
ownershipKind);
5509-
attr->setInvalid();
5511+
ownershipKind)
5512+
.limitBehavior(*behavior);
55105513
}
55115514
}
55125515

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "TypeCheckAvailability.h"
2424
#include "TypeCheckConcurrency.h"
2525
#include "TypeCheckDecl.h"
26+
#include "TypeCheckEmbedded.h"
2627
#include "TypeCheckMacros.h"
2728
#include "TypeCheckObjC.h"
2829
#include "TypeCheckType.h"
@@ -3535,6 +3536,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
35353536

35363537
TypeChecker::checkDeclAttributes(FD);
35373538
TypeChecker::checkDistributedFunc(FD);
3539+
checkEmbeddedRestrictionsInSignature(FD);
35383540

35393541
if (!checkOverrides(FD)) {
35403542
// If a method has an 'override' keyword but does not
@@ -3920,6 +3922,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
39203922

39213923
TypeChecker::checkDeclAttributes(CD);
39223924
TypeChecker::checkParameterList(CD->getParameters(), CD);
3925+
checkEmbeddedRestrictionsInSignature(CD);
39233926

39243927
if (CD->getAsyncLoc().isValid())
39253928
TypeChecker::checkConcurrencyAvailability(CD->getAsyncLoc(), CD);

lib/Sema/TypeCheckEmbedded.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- TypeCheckEmbedded.cpp - Embedded ----------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements type checking support for Embedded Swift.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "TypeCheckEmbedded.h"
18+
#include "swift/AST/ASTContext.h"
19+
#include "swift/AST/Decl.h"
20+
#include "swift/AST/DiagnosticsSema.h"
21+
#include "swift/AST/Effects.h"
22+
#include "swift/AST/Types.h"
23+
24+
using namespace swift;
25+
26+
std::optional<DiagnosticBehavior>
27+
swift::shouldDiagnoseEmbeddedLimitations(const DeclContext *dc, SourceLoc loc,
28+
bool wasAlwaysEmbeddedError) {
29+
// In Embedded Swift, things that were always errors will still be emitted
30+
// as errors. Use "unspecified" so we don't change anything.
31+
if (dc->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
32+
wasAlwaysEmbeddedError) {
33+
return DiagnosticBehavior::Unspecified;
34+
}
35+
36+
// Check one of the Embedded restriction diagnostics that is ignored by
37+
// default. If it's still ignored, we won't diagnose anything.
38+
// limitations.
39+
auto &diags = dc->getASTContext().Diags;
40+
if (diags.isIgnoredDiagnostic(diag::untyped_throws_in_embedded_swift.ID))
41+
return std::nullopt;
42+
43+
// If this was always an error in Embedded Swift, we aren't in Embedded Swift
44+
// now, so downgrade to a warning.
45+
if (wasAlwaysEmbeddedError)
46+
return DiagnosticBehavior::Warning;
47+
48+
// Leave it as-is.
49+
return DiagnosticBehavior::Unspecified;
50+
}
51+
52+
/// Check embedded restrictions in the signature of the given function.
53+
void swift::checkEmbeddedRestrictionsInSignature(
54+
const AbstractFunctionDecl *func) {
55+
// If we are not supposed to diagnose Embedded Swift limitations, do nothing.
56+
auto behavior = shouldDiagnoseEmbeddedLimitations(func, func->getLoc());
57+
if (!behavior)
58+
return;
59+
60+
// Untyped throws is not permitted.
61+
SourceLoc throwsLoc = func->getThrowsLoc();
62+
if (throwsLoc.isValid() && !func->getThrownTypeRepr() &&
63+
!func->hasPolymorphicEffect(EffectKind::Throws)) {
64+
diagnoseUntypedThrowsInEmbedded(func, throwsLoc);
65+
}
66+
}
67+
68+
void swift::diagnoseUntypedThrowsInEmbedded(
69+
const DeclContext *dc, SourceLoc throwsLoc) {
70+
// If we are not supposed to diagnose Embedded Swift limitations, do nothing.
71+
auto behavior = shouldDiagnoseEmbeddedLimitations(dc, throwsLoc);
72+
if (!behavior)
73+
return;
74+
75+
dc->getASTContext().Diags.diagnose(
76+
throwsLoc, diag::untyped_throws_in_embedded_swift)
77+
.limitBehavior(*behavior)
78+
.fixItInsertAfter(throwsLoc, "(<#thrown error type#>)");
79+
}

lib/Sema/TypeCheckEmbedded.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===--- TypeCheckEmbedded.h - Embedded -------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file provides type checking support for Embedded Swift.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SEMA_TYPECHECKEMBEDDED_H
18+
#define SWIFT_SEMA_TYPECHECKEMBEDDED_H
19+
20+
#include <optional>
21+
22+
namespace swift {
23+
24+
class AbstractFunctionDecl;
25+
class DeclContext;
26+
struct DiagnosticBehavior;
27+
class SourceLoc;
28+
29+
/// Whether we should diagnose language-level limitations of Embedded Swift
30+
/// at the given source location, and how.
31+
///
32+
/// @param dc The declaration context in which the diagnostic would be emitted.
33+
/// @param loc The source location at which the diagnostic would be emitted.
34+
/// @param wasAlwaysEmbeddedError Whether this diagnostic was always an error
35+
/// in Embedded Swift, which is used to avoid downgrading for
36+
/// source-compatibility reasons.
37+
/// @returns `std::nullopt` if no diagnostic should be emitted. Otherwise, a
38+
/// behavior limit to place on the diagnostic when it is emitted.
39+
std::optional<DiagnosticBehavior>
40+
shouldDiagnoseEmbeddedLimitations(const DeclContext *dc, SourceLoc loc,
41+
bool wasAlwaysEmbeddedError = false);
42+
43+
/// Check embedded restrictions in the signature of the given function.
44+
void checkEmbeddedRestrictionsInSignature(const AbstractFunctionDecl *func);
45+
46+
/// Diagnose a declaration of typed throws at the given location.
47+
void diagnoseUntypedThrowsInEmbedded(const DeclContext *dc, SourceLoc throwsLoc);
48+
49+
}
50+
#endif // SWIFT_SEMA_TYPECHECKEMBEDDED_H

lib/Sema/TypeCheckType.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "NonisolatedNonsendingByDefaultMigration.h"
2020
#include "TypeCheckAvailability.h"
2121
#include "TypeCheckConcurrency.h"
22+
#include "TypeCheckEmbedded.h"
2223
#include "TypeCheckInvertible.h"
2324
#include "TypeCheckProtocol.h"
2425
#include "TypeChecker.h"
@@ -4428,6 +4429,8 @@ NeverNullType TypeResolver::resolveASTFunctionType(
44284429
thrownTy);
44294430
}
44304431
}
4432+
} else if (repr->getThrowsLoc().isValid()) {
4433+
diagnoseUntypedThrowsInEmbedded(getDeclContext(), repr->getThrowsLoc());
44314434
}
44324435

44334436
bool hasSendingResult =
@@ -7011,6 +7014,7 @@ Type ExplicitCaughtTypeRequest::evaluate(
70117014

70127015
// Explicit 'throws' implies that this throws 'any Error'.
70137016
if (closure->getThrowsLoc().isValid()) {
7017+
diagnoseUntypedThrowsInEmbedded(closure, closure->getThrowsLoc());
70147018
return ctx.getErrorExistentialType();
70157019
}
70167020

@@ -7030,6 +7034,8 @@ Type ExplicitCaughtTypeRequest::evaluate(
70307034

70317035
// If there is no explicitly-specified thrown error type, it's 'any Error'.
70327036
if (!typeRepr) {
7037+
diagnoseUntypedThrowsInEmbedded(doCatch->getDeclContext(),
7038+
doCatch->getThrowsLoc());
70337039
return ctx.getErrorExistentialType();
70347040
}
70357041

0 commit comments

Comments
 (0)