Skip to content

[SE-0160] Swift 3: Downgrade error about non-ObjC @(IB|GK)Inspectable properties #8772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3080,6 +3080,10 @@ ERROR(objc_extension_not_class,none,
// If you change this, also change enum ObjCReason
#define OBJC_ATTR_SELECT "select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @IBAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)}"

WARNING(attribute_meaningless_when_nonobjc,none,
"'@%0' attribute is meaningless on a property that cannot be "
"represented in Objective-C", (StringRef))

ERROR(objc_invalid_on_var,none,
"property cannot be %" OBJC_ATTR_SELECT "0 "
"because its type cannot be represented in Objective-C", (unsigned))
Expand Down
28 changes: 24 additions & 4 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2366,8 +2366,10 @@ static Optional<ObjCReason> shouldMarkAsObjC(TypeChecker &TC,
// explicitly declared @objc.
if (VD->getAttrs().hasAttribute<ObjCAttr>())
return ObjCReason::ExplicitlyObjC;
// @IBOutlet, @IBAction, @IBInspectable, @NSManaged, and @GKInspectable
// imply @objc.
// @IBOutlet, @IBAction, @NSManaged, and @GKInspectable imply @objc.
//
// @IBInspectable and @GKInspectable imply @objc quietly in Swift 3
// (where they warn on failure) and loudly in Swift 4 (error on failure).
if (VD->getAttrs().hasAttribute<IBOutletAttr>())
return ObjCReason::ExplicitlyIBOutlet;
if (VD->getAttrs().hasAttribute<IBActionAttr>())
Expand Down Expand Up @@ -2735,7 +2737,7 @@ void swift::markAsObjC(TypeChecker &TC, ValueDecl *D,
// could be overridden by @nonobjc. If we see a @nonobjc and we are trying
// to add an @objc for whatever reason, diagnose an error.
if (auto *attr = D->getAttrs().getAttribute<NonObjCAttr>()) {
if (!shouldDiagnoseObjCReason(*isObjC))
if (!shouldDiagnoseObjCReason(*isObjC, TC.Context))
isObjC = ObjCReason::ImplicitlyObjC;

TC.diagnose(D->getStartLoc(), diag::nonobjc_not_allowed,
Expand Down Expand Up @@ -5113,7 +5115,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
// complain.
auto storageObjCAttr = storage->getAttrs().getAttribute<ObjCAttr>();
if (storageObjCAttr->isSwift3Inferred() &&
shouldDiagnoseObjCReason(*isObjC)) {
shouldDiagnoseObjCReason(*isObjC, TC.Context)) {
TC.diagnose(storage, diag::accessor_swift3_objc_inference,
storage->getDescriptiveKind(), storage->getFullName(),
isa<SubscriptDecl>(storage), FD->isSetter())
Expand Down Expand Up @@ -7282,6 +7284,24 @@ void TypeChecker::validateDecl(ValueDecl *D) {

markAsObjC(*this, VD, isObjC);

// Under the Swift 3 inference rules, if we have @IBInspectable or
// @GKInspectable but did not infer @objc, warn that the attribute is
if (!isObjC && Context.LangOpts.EnableSwift3ObjCInference) {
if (auto attr = VD->getAttrs().getAttribute<IBInspectableAttr>()) {
diagnose(attr->getLocation(),
diag::attribute_meaningless_when_nonobjc,
attr->getAttrName())
.fixItRemove(attr->getRange());
}

if (auto attr = VD->getAttrs().getAttribute<GKInspectableAttr>()) {
diagnose(attr->getLocation(),
diag::attribute_meaningless_when_nonobjc,
attr->getAttrName())
.fixItRemove(attr->getRange());
}
}

// Infer 'dynamic' before touching accessors.
inferDynamic(Context, VD);

Expand Down
16 changes: 8 additions & 8 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3145,7 +3145,7 @@ static void describeObjCReason(TypeChecker &TC, const ValueDecl *VD,
static void diagnoseFunctionParamNotRepresentable(
TypeChecker &TC, const AbstractFunctionDecl *AFD, unsigned NumParams,
unsigned ParamIndex, const ParamDecl *P, ObjCReason Reason) {
if (!shouldDiagnoseObjCReason(Reason))
if (!shouldDiagnoseObjCReason(Reason, TC.Context))
return;

if (NumParams == 1) {
Expand All @@ -3171,7 +3171,7 @@ static bool isParamListRepresentableInObjC(TypeChecker &TC,
ObjCReason Reason) {
// If you change this function, you must add or modify a test in PrintAsObjC.

bool Diagnose = shouldDiagnoseObjCReason(Reason);
bool Diagnose = shouldDiagnoseObjCReason(Reason, TC.Context);

bool IsObjC = true;
unsigned NumParams = PL->size();
Expand All @@ -3180,7 +3180,7 @@ static bool isParamListRepresentableInObjC(TypeChecker &TC,

// Swift Varargs are not representable in Objective-C.
if (param->isVariadic()) {
if (Diagnose && shouldDiagnoseObjCReason(Reason)) {
if (Diagnose && shouldDiagnoseObjCReason(Reason, TC.Context)) {
TC.diagnose(param->getStartLoc(), diag::objc_invalid_on_func_variadic,
getObjCDiagnosticAttrKind(Reason))
.highlight(param->getSourceRange());
Expand Down Expand Up @@ -3267,7 +3267,7 @@ static bool checkObjCInExtensionContext(TypeChecker &tc,
static bool checkObjCWithGenericParams(TypeChecker &TC,
const AbstractFunctionDecl *AFD,
ObjCReason Reason) {
bool Diagnose = shouldDiagnoseObjCReason(Reason);
bool Diagnose = shouldDiagnoseObjCReason(Reason, TC.Context);

if (AFD->getGenericParams()) {
// Diagnose this problem, if asked to.
Expand All @@ -3288,7 +3288,7 @@ static bool checkObjCWithGenericParams(TypeChecker &TC,
static bool checkObjCInForeignClassContext(TypeChecker &TC,
const ValueDecl *VD,
ObjCReason Reason) {
bool Diagnose = shouldDiagnoseObjCReason(Reason);
bool Diagnose = shouldDiagnoseObjCReason(Reason, TC.Context);

auto type = VD->getDeclContext()->getDeclaredInterfaceType();
if (!type)
Expand Down Expand Up @@ -3356,7 +3356,7 @@ bool TypeChecker::isRepresentableInObjC(

// If you change this function, you must add or modify a test in PrintAsObjC.

bool Diagnose = shouldDiagnoseObjCReason(Reason);
bool Diagnose = shouldDiagnoseObjCReason(Reason, Context);

if (checkObjCInForeignClassContext(*this, AFD, Reason))
return false;
Expand Down Expand Up @@ -3688,7 +3688,7 @@ bool TypeChecker::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
}
bool Result = T->isRepresentableIn(ForeignLanguage::ObjectiveC,
VD->getDeclContext());
bool Diagnose = shouldDiagnoseObjCReason(Reason);
bool Diagnose = shouldDiagnoseObjCReason(Reason, Context);

if (Result && checkObjCInExtensionContext(*this, VD, Diagnose))
return false;
Expand Down Expand Up @@ -3719,7 +3719,7 @@ bool TypeChecker::isRepresentableInObjC(const SubscriptDecl *SD,
ObjCReason Reason) {
// If you change this function, you must add or modify a test in PrintAsObjC.

bool Diagnose = shouldDiagnoseObjCReason(Reason);
bool Diagnose = shouldDiagnoseObjCReason(Reason, Context);

if (checkObjCInForeignClassContext(*this, SD, Reason))
return false;
Expand Down
9 changes: 6 additions & 3 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,8 @@ enum class ObjCReason {

/// Determine whether we should diagnose conflicts due to inferring @objc
/// with this particular reason.
static inline bool shouldDiagnoseObjCReason(ObjCReason reason) {
static inline bool shouldDiagnoseObjCReason(ObjCReason reason,
ASTContext &ctx) {
switch(reason) {
case ObjCReason::ExplicitlyCDecl:
case ObjCReason::ExplicitlyDynamic:
Expand All @@ -563,11 +564,13 @@ static inline bool shouldDiagnoseObjCReason(ObjCReason reason) {
case ObjCReason::OverridesObjC:
case ObjCReason::WitnessToObjC:
case ObjCReason::ImplicitlyObjC:
case ObjCReason::ExplicitlyIBInspectable:
case ObjCReason::ExplicitlyGKInspectable:
case ObjCReason::MemberOfObjCExtension:
return true;

case ObjCReason::ExplicitlyIBInspectable:
case ObjCReason::ExplicitlyGKInspectable:
return !ctx.LangOpts.EnableSwift3ObjCInference;

case ObjCReason::MemberOfObjCSubclass:
case ObjCReason::MemberOfObjCMembersClass:
case ObjCReason::Accessor:
Expand Down
6 changes: 0 additions & 6 deletions test/attr/attr_objc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1672,9 +1672,6 @@ class HasIBAction {
class HasIBInspectable {
@IBInspectable var goodProperty: AnyObject?
// CHECK: {{^}} @IBInspectable @objc var goodProperty: AnyObject?

@IBInspectable var badProperty: PlainStruct?
// expected-error@-1{{property cannot be marked @IBInspectable because its type cannot be represented in Objective-C}}
}

//===---
Expand All @@ -1685,9 +1682,6 @@ class HasIBInspectable {
class HasGKInspectable {
@GKInspectable var goodProperty: AnyObject?
// CHECK: {{^}} @GKInspectable @objc var goodProperty: AnyObject?

@GKInspectable var badProperty: PlainStruct?
// expected-error@-1{{property cannot be marked @GKInspectable because its type cannot be represented in Objective-C}}
}

//===---
Expand Down
5 changes: 5 additions & 0 deletions test/attr/attr_objc_swift3_deprecated_uses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import Foundation

struct SwiftStruct { }

class ObjCSubclass : NSObject {
func foo() { } // expected-note 2{{add '@objc' to expose this instance method to Objective-C}}{{3-3=@objc }}
var bar: NSObject? = nil // expected-note 2{{add '@objc' to expose this var to Objective-C}}{{3-3=@objc }}
Expand All @@ -22,6 +24,9 @@ class ObjCSubclass : NSObject {

set { }
}

@IBInspectable var ibvar: SwiftStruct = SwiftStruct() // expected-warning{{'@IBInspectable' attribute is meaningless on a property that cannot be represented in Objective-C}}{{3-18=}}
@GKInspectable var gkvar: SwiftStruct = SwiftStruct() // expected-warning{{'@GKInspectable' attribute is meaningless on a property that cannot be represented in Objective-C}}{{3-18=}}
}

class DynamicMembers {
Expand Down
10 changes: 10 additions & 0 deletions test/attr/attr_objc_swift4.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ func test(sc: ObjCSubclass, dm: DynamicMembers) {
_ = #selector(getter: dm.bar)
_ = #keyPath(DynamicMembers.bar)
}

struct PlainStruct { }

class BadInSwift4 {
@IBInspectable var badIBInspectable: PlainStruct?
// expected-error@-1{{property cannot be marked @IBInspectable because its type cannot be represented in Objective-C}}

@GKInspectable var badGKInspectable: PlainStruct?
// expected-error@-1{{property cannot be marked @GKInspectable because its type cannot be represented in Objective-C}}
}