Skip to content

Commit

Permalink
Merge pull request swiftlang#8772 from DougGregor/rdar-31408971
Browse files Browse the repository at this point in the history
  • Loading branch information
swift-ci authored Apr 14, 2017
2 parents e9d6b48 + 5cf233b commit 54e1f83
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 21 deletions.
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}}
}

0 comments on commit 54e1f83

Please sign in to comment.