Skip to content

Commit 8e4efaf

Browse files
committed
[Sema] Diagnose availability via TypeReprs rather than Types.
The code that diagnosed availability for types was reverse-engineering the Type itself, rather than making use of the declaration already stored within the TypeRepr. More importantly, it would completely skip nested types, so it would fail to diagnose a deprecated/unavailable “Bar” in “Foo.Bar”. Replace the type-inspecting check with a much-simpler walk over the components of the IdentTypeRepr that looks at the declarations stored in the IdentTypeRepr directly. This provides proper source-location information and handles nested types. This is a source-breaking change for ill-formed Swift 3 code that used nested type references to refer to something that should be unavailable. Given that such Swift 3 code was ill-formed, and most uses of it would crash at runtime, we likely do not need to provide specific logic to address this in Swift 3 compatibility mode.
1 parent 6382ed6 commit 8e4efaf

File tree

4 files changed

+26
-47
lines changed

4 files changed

+26
-47
lines changed

lib/AST/Type.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,10 @@ TypeDecl *TypeBase::getDirectlyReferencedTypeDecl() const {
981981
return nullptr;
982982
}
983983

984+
if (auto substituted = dyn_cast<SubstitutedType>(this)) {
985+
return substituted->getOriginal()->getDirectlyReferencedTypeDecl();
986+
}
987+
984988
return nullptr;
985989
}
986990

lib/Sema/TypeCheckType.cpp

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,55 +1340,18 @@ static Type resolveIdentTypeComponent(
13401340
unsatisfiedDependency);
13411341
}
13421342

1343-
static bool checkTypeDeclAvailability(const TypeDecl *TypeDecl,
1344-
IdentTypeRepr *IdType,
1345-
SourceLoc Loc, DeclContext *DC,
1346-
TypeChecker &TC,
1347-
bool AllowPotentiallyUnavailableProtocol){
1348-
if (isa<ComponentIdentTypeRepr>(IdType)) {
1349-
return diagnoseDeclAvailability(TypeDecl, TC, DC, Loc,
1350-
AllowPotentiallyUnavailableProtocol,
1351-
false);
1352-
}
1353-
1354-
return false;
1355-
}
1356-
1357-
1358-
static bool diagnoseAvailability(Type ty, IdentTypeRepr *IdType, SourceLoc Loc,
1343+
static bool diagnoseAvailability(IdentTypeRepr *IdType,
13591344
DeclContext *DC, TypeChecker &TC,
13601345
bool AllowPotentiallyUnavailableProtocol) {
1361-
if (auto *NAT = dyn_cast<NameAliasType>(ty.getPointer())) {
1362-
if (checkTypeDeclAvailability(NAT->getDecl(), IdType, Loc, DC, TC,
1363-
AllowPotentiallyUnavailableProtocol))
1364-
return true;
1365-
}
1366-
1367-
if (auto *GPT = dyn_cast<GenericTypeParamType>(ty.getPointer())) {
1368-
if (auto GP = GPT->getDecl()) {
1369-
if (checkTypeDeclAvailability(GP, IdType, Loc, DC, TC,
1370-
AllowPotentiallyUnavailableProtocol)) {
1346+
for (auto comp : IdType->getComponentRange()) {
1347+
if (auto typeDecl = dyn_cast_or_null<TypeDecl>(comp->getBoundDecl())) {
1348+
if (diagnoseDeclAvailability(typeDecl, TC, DC, comp->getIdLoc(),
1349+
AllowPotentiallyUnavailableProtocol,
1350+
false))
13711351
return true;
1372-
}
1373-
}
1374-
}
1375-
1376-
// Look through substituted types to diagnose when the original
1377-
// type is marked unavailable.
1378-
if (auto *ST = dyn_cast<SubstitutedType>(ty.getPointer())) {
1379-
if (diagnoseAvailability(ST->getOriginal(), IdType, Loc, DC, TC,
1380-
AllowPotentiallyUnavailableProtocol)) {
1381-
return true;
13821352
}
13831353
}
13841354

1385-
CanType canTy = ty.getCanonicalTypeOrNull();
1386-
if (canTy.isNull())
1387-
return false;
1388-
if (auto NTD = canTy.getAnyNominal())
1389-
return checkTypeDeclAvailability(NTD, IdType, Loc, DC, TC,
1390-
AllowPotentiallyUnavailableProtocol);
1391-
13921355
return false;
13931356
}
13941357

@@ -1468,8 +1431,7 @@ Type TypeChecker::resolveIdentifierType(
14681431

14691432
// Check the availability of the type.
14701433
if (!(options & TR_AllowUnavailable) &&
1471-
diagnoseAvailability(result, IdType,
1472-
Components.back()->getIdLoc(), DC, *this,
1434+
diagnoseAvailability(IdType, DC, *this,
14731435
AllowPotentiallyUnavailableProtocol)) {
14741436
Components.back()->setInvalid();
14751437
return ErrorType::get(Context);

test/Interpreter/SDK/submodules_smoke_test.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import AppKit.NSPanGestureRecognizer
1515

1616
@available(OSX, introduced: 10.10)
1717
typealias PanRecognizer = NSPanGestureRecognizer
18+
19+
@available(OSX, introduced: 10.10)
1820
typealias PanRecognizer2 = AppKit.NSPanGestureRecognizer
1921

2022
#if !NO_ERROR

test/Sema/availability.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -module-name MyModule
22

33
// REQUIRES: OS=macosx
44

@@ -10,10 +10,21 @@ func test() {
1010
}
1111

1212
@available(*,unavailable,message: "use 'Int' instead")
13-
struct NSUInteger {} // expected-note 2 {{explicitly marked unavailable here}}
13+
struct NSUInteger {} // expected-note 3 {{explicitly marked unavailable here}}
14+
15+
struct Outer {
16+
@available(*,unavailable,message: "use 'UInt' instead")
17+
struct NSUInteger {} // expected-note 2 {{explicitly marked unavailable here}}
18+
}
1419

1520
func foo(x : NSUInteger) { // expected-error {{'NSUInteger' is unavailable: use 'Int' instead}}
1621
let y : NSUInteger = 42 // expected-error {{'NSUInteger' is unavailable: use 'Int' instead}}
22+
23+
let z : MyModule.NSUInteger = 42 // expected-error {{'NSUInteger' is unavailable: use 'Int' instead}}
24+
25+
let z2 : Outer.NSUInteger = 42 // expected-error {{'NSUInteger' is unavailable: use 'UInt' instead}}
26+
27+
let z3 : MyModule.Outer.NSUInteger = 42 // expected-error {{'NSUInteger' is unavailable: use 'UInt' instead}}
1728
}
1829

1930
// Test preventing overrides of unavailable methods.

0 commit comments

Comments
 (0)