mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Provide fix-its when implementing a protocol method with bridged types. (#2799)
This is the protocol version of 7bfdd4a2: if a protocol requirement
has a newly-bridged type (say, 'URL' instead of 'NSURL'), then any
conforming types will need to update their implementations of the
requirement. Reuse the override-checking mechanism to do so when
we're reasonably confident about it.
This slots the checking into the existing protocol diagnostics, which
doesn't result in the best user experience.
note: protocol requires property 'prop' with type 'Refrigerator?'
var prop: Refrigerator? { get }
^
note: candidate has non-matching type 'APPRefrigerator?'
var prop: APPRefrigerator? {
^ ~~~~~~~~~~~~~~~~
Refrigerator?
But we can come back and improve that later; right now this is better
than nothing.
rdar://problem/26237030
This commit is contained in:
@@ -997,6 +997,115 @@ bool swift::diagnoseArgumentLabelError(TypeChecker &TC, const Expr *expr,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool swift::fixItOverrideDeclarationTypes(TypeChecker &TC,
|
||||||
|
InFlightDiagnostic &diag,
|
||||||
|
ValueDecl *decl,
|
||||||
|
const ValueDecl *base) {
|
||||||
|
// For now, just rewrite cases where the base uses a value type and the
|
||||||
|
// override uses a reference type, and the value type is bridged to the
|
||||||
|
// reference type. This is a way to migrate code that makes use of types
|
||||||
|
// that previously were not bridged to value types.
|
||||||
|
auto checkType = [&](Type overrideTy, Type baseTy,
|
||||||
|
SourceRange typeRange) -> bool {
|
||||||
|
if (typeRange.isInvalid())
|
||||||
|
return false;
|
||||||
|
if (!baseTy) {
|
||||||
|
decl->dump();
|
||||||
|
base->dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto normalizeType = [](Type ty) -> Type {
|
||||||
|
ty = ty->getInOutObjectType();
|
||||||
|
if (Type unwrappedTy = ty->getAnyOptionalObjectType())
|
||||||
|
ty = unwrappedTy;
|
||||||
|
return ty;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Is the base type bridged?
|
||||||
|
Type normalizedBaseTy = normalizeType(baseTy);
|
||||||
|
const DeclContext *DC = decl->getDeclContext();
|
||||||
|
Optional<Type> maybeBridged =
|
||||||
|
TC.Context.getBridgedToObjC(DC, normalizedBaseTy, &TC);
|
||||||
|
|
||||||
|
// ...and just knowing that it's bridged isn't good enough if we don't
|
||||||
|
// know what it's bridged /to/. Also, don't do this check for trivial
|
||||||
|
// bridging---that doesn't count.
|
||||||
|
Type bridged = maybeBridged.getValueOr(Type());
|
||||||
|
if (!bridged || bridged->isEqual(normalizedBaseTy))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ...and is it bridged to the overridden type?
|
||||||
|
Type normalizedOverrideTy = normalizeType(overrideTy);
|
||||||
|
if (!bridged->isEqual(normalizedOverrideTy)) {
|
||||||
|
// If both are nominal types, check again, ignoring generic arguments.
|
||||||
|
auto *overrideNominal = normalizedOverrideTy->getAnyNominal();
|
||||||
|
if (!overrideNominal || bridged->getAnyNominal() != overrideNominal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type newOverrideTy = baseTy;
|
||||||
|
|
||||||
|
// Preserve optionality if we're dealing with a simple type.
|
||||||
|
OptionalTypeKind OTK;
|
||||||
|
if (Type unwrappedTy = newOverrideTy->getAnyOptionalObjectType())
|
||||||
|
newOverrideTy = unwrappedTy;
|
||||||
|
if (overrideTy->getAnyOptionalObjectType(OTK))
|
||||||
|
newOverrideTy = OptionalType::get(OTK, newOverrideTy);
|
||||||
|
|
||||||
|
SmallString<32> baseTypeBuf;
|
||||||
|
llvm::raw_svector_ostream baseTypeStr(baseTypeBuf);
|
||||||
|
PrintOptions options;
|
||||||
|
options.SynthesizeSugarOnTypes = true;
|
||||||
|
|
||||||
|
newOverrideTy->print(baseTypeStr, options);
|
||||||
|
diag.fixItReplace(typeRange, baseTypeStr.str());
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto *var = dyn_cast<VarDecl>(decl)) {
|
||||||
|
SourceRange typeRange = var->getTypeSourceRangeForDiagnostics();
|
||||||
|
return checkType(var->getType(), base->getType(), typeRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto *fn = dyn_cast<AbstractFunctionDecl>(decl)) {
|
||||||
|
auto *baseFn = cast<AbstractFunctionDecl>(base);
|
||||||
|
bool fixedAny = false;
|
||||||
|
if (fn->getParameterLists().back()->size() ==
|
||||||
|
baseFn->getParameterLists().back()->size()) {
|
||||||
|
for_each(*fn->getParameterLists().back(),
|
||||||
|
*baseFn->getParameterLists().back(),
|
||||||
|
[&](ParamDecl *param, const ParamDecl *baseParam) {
|
||||||
|
fixedAny |= fixItOverrideDeclarationTypes(TC, diag, param, baseParam);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (auto *method = dyn_cast<FuncDecl>(decl)) {
|
||||||
|
auto *baseMethod = cast<FuncDecl>(base);
|
||||||
|
fixedAny |= checkType(method->getBodyResultType(),
|
||||||
|
baseMethod->getResultType(),
|
||||||
|
method->getBodyResultTypeLoc().getSourceRange());
|
||||||
|
}
|
||||||
|
return fixedAny;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto *subscript = dyn_cast<SubscriptDecl>(decl)) {
|
||||||
|
auto *baseSubscript = cast<SubscriptDecl>(base);
|
||||||
|
bool fixedAny = false;
|
||||||
|
for_each(*subscript->getIndices(),
|
||||||
|
*baseSubscript->getIndices(),
|
||||||
|
[&](ParamDecl *param, const ParamDecl *baseParam) {
|
||||||
|
fixedAny |= fixItOverrideDeclarationTypes(TC, diag, param, baseParam);
|
||||||
|
});
|
||||||
|
fixedAny |= checkType(subscript->getElementType(),
|
||||||
|
baseSubscript->getElementType(),
|
||||||
|
subscript->getElementTypeLoc().getSourceRange());
|
||||||
|
return fixedAny;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("unknown overridable member");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Diagnose availability.
|
// Diagnose availability.
|
||||||
|
|||||||
@@ -68,6 +68,16 @@ void fixItAvailableAttrRename(TypeChecker &TC,
|
|||||||
SourceRange referenceRange,
|
SourceRange referenceRange,
|
||||||
const AvailableAttr *attr,
|
const AvailableAttr *attr,
|
||||||
const ApplyExpr *call);
|
const ApplyExpr *call);
|
||||||
|
|
||||||
|
/// Attempt to fix the type of \p decl so that it's a valid override for
|
||||||
|
/// \p base...but only if we're highly confident that we know what the user
|
||||||
|
/// should have written.
|
||||||
|
///
|
||||||
|
/// \returns true iff any fix-its were attached to \p diag.
|
||||||
|
bool fixItOverrideDeclarationTypes(TypeChecker &TC,
|
||||||
|
InFlightDiagnostic &diag,
|
||||||
|
ValueDecl *decl,
|
||||||
|
const ValueDecl *base);
|
||||||
} // namespace swift
|
} // namespace swift
|
||||||
|
|
||||||
#endif // SWIFT_SEMA_MISC_DIAGNOSTICS_H
|
#endif // SWIFT_SEMA_MISC_DIAGNOSTICS_H
|
||||||
|
|||||||
@@ -4783,115 +4783,6 @@ public:
|
|||||||
type = fnType->withExtInfo(extInfo);
|
type = fnType->withExtInfo(extInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to fix the type of \p decl so that it's a valid override for
|
|
||||||
/// \p base...but only if we're highly confident that we know what the user
|
|
||||||
/// should have written.
|
|
||||||
///
|
|
||||||
/// \returns true iff any fix-its were attached to \p diag.
|
|
||||||
static bool fixOverrideDeclarationTypes(InFlightDiagnostic &diag,
|
|
||||||
TypeChecker &TC,
|
|
||||||
ValueDecl *decl,
|
|
||||||
const ValueDecl *base) {
|
|
||||||
// For now, just rewrite cases where the base uses a value type and the
|
|
||||||
// override uses a reference type, and the value type is bridged to the
|
|
||||||
// reference type. This is a way to migrate code that makes use of types
|
|
||||||
// that previously were not bridged to value types.
|
|
||||||
auto checkType = [&](Type overrideTy, Type baseTy,
|
|
||||||
SourceRange typeRange) -> bool {
|
|
||||||
if (typeRange.isInvalid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto normalizeType = [](Type ty) -> Type {
|
|
||||||
ty = ty->getInOutObjectType();
|
|
||||||
if (Type unwrappedTy = ty->getAnyOptionalObjectType())
|
|
||||||
ty = unwrappedTy;
|
|
||||||
return ty;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Is the base type bridged?
|
|
||||||
Type normalizedBaseTy = normalizeType(baseTy);
|
|
||||||
const DeclContext *DC = decl->getDeclContext();
|
|
||||||
Optional<Type> maybeBridged =
|
|
||||||
TC.Context.getBridgedToObjC(DC, normalizedBaseTy, &TC);
|
|
||||||
|
|
||||||
// ...and just knowing that it's bridged isn't good enough if we don't
|
|
||||||
// know what it's bridged /to/. Also, don't do this check for trivial
|
|
||||||
// bridging---that doesn't count.
|
|
||||||
Type bridged = maybeBridged.getValueOr(Type());
|
|
||||||
if (!bridged || bridged->isEqual(normalizedBaseTy))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// ...and is it bridged to the overridden type?
|
|
||||||
Type normalizedOverrideTy = normalizeType(overrideTy);
|
|
||||||
if (!bridged->isEqual(normalizedOverrideTy)) {
|
|
||||||
// If both are nominal types, check again, ignoring generic arguments.
|
|
||||||
auto *overrideNominal = normalizedOverrideTy->getAnyNominal();
|
|
||||||
if (!overrideNominal || bridged->getAnyNominal() != overrideNominal) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Type newOverrideTy = baseTy;
|
|
||||||
|
|
||||||
// Preserve optionality if we're dealing with a simple type.
|
|
||||||
OptionalTypeKind OTK;
|
|
||||||
if (Type unwrappedTy = newOverrideTy->getAnyOptionalObjectType())
|
|
||||||
newOverrideTy = unwrappedTy;
|
|
||||||
if (overrideTy->getAnyOptionalObjectType(OTK))
|
|
||||||
newOverrideTy = OptionalType::get(OTK, newOverrideTy);
|
|
||||||
|
|
||||||
SmallString<32> baseTypeBuf;
|
|
||||||
llvm::raw_svector_ostream baseTypeStr(baseTypeBuf);
|
|
||||||
PrintOptions options;
|
|
||||||
options.SynthesizeSugarOnTypes = true;
|
|
||||||
|
|
||||||
newOverrideTy->print(baseTypeStr, options);
|
|
||||||
diag.fixItReplace(typeRange, baseTypeStr.str());
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (auto *var = dyn_cast<VarDecl>(decl)) {
|
|
||||||
SourceRange typeRange = var->getTypeSourceRangeForDiagnostics();
|
|
||||||
return checkType(var->getType(), base->getType(), typeRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto *fn = dyn_cast<AbstractFunctionDecl>(decl)) {
|
|
||||||
auto *baseFn = cast<AbstractFunctionDecl>(base);
|
|
||||||
bool fixedAny = false;
|
|
||||||
if (fn->getParameterLists().back()->size() ==
|
|
||||||
baseFn->getParameterLists().back()->size()) {
|
|
||||||
for_each(*fn->getParameterLists().back(),
|
|
||||||
*baseFn->getParameterLists().back(),
|
|
||||||
[&](ParamDecl *param, const ParamDecl *baseParam) {
|
|
||||||
fixedAny |= fixOverrideDeclarationTypes(diag, TC, param, baseParam);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (auto *method = dyn_cast<FuncDecl>(decl)) {
|
|
||||||
auto *baseMethod = cast<FuncDecl>(base);
|
|
||||||
fixedAny |= checkType(method->getBodyResultType(),
|
|
||||||
baseMethod->getBodyResultType(),
|
|
||||||
method->getBodyResultTypeLoc().getSourceRange());
|
|
||||||
}
|
|
||||||
return fixedAny;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto *subscript = dyn_cast<SubscriptDecl>(decl)) {
|
|
||||||
auto *baseSubscript = cast<SubscriptDecl>(base);
|
|
||||||
bool fixedAny = false;
|
|
||||||
for_each(*subscript->getIndices(),
|
|
||||||
*baseSubscript->getIndices(),
|
|
||||||
[&](ParamDecl *param, const ParamDecl *baseParam) {
|
|
||||||
fixedAny |= fixOverrideDeclarationTypes(diag, TC, param, baseParam);
|
|
||||||
});
|
|
||||||
fixedAny |= checkType(subscript->getElementType(),
|
|
||||||
baseSubscript->getElementType(),
|
|
||||||
subscript->getElementTypeLoc().getSourceRange());
|
|
||||||
return fixedAny;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm_unreachable("unknown overridable member");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the difference between the types of \p decl and \p base is something
|
/// If the difference between the types of \p decl and \p base is something
|
||||||
/// we feel confident about fixing (even partially), emit a note with fix-its
|
/// we feel confident about fixing (even partially), emit a note with fix-its
|
||||||
/// attached. Otherwise, no note will be emitted.
|
/// attached. Otherwise, no note will be emitted.
|
||||||
@@ -4926,7 +4817,7 @@ public:
|
|||||||
base->getDescriptiveKind(), baseTy));
|
base->getDescriptiveKind(), baseTy));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fixOverrideDeclarationTypes(*activeDiag, TC, decl, base))
|
if (fixItOverrideDeclarationTypes(TC, *activeDiag, decl, base))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1733,11 +1733,14 @@ diagnoseMatch(TypeChecker &tc, Module *module,
|
|||||||
// about them.
|
// about them.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MatchKind::TypeConflict:
|
case MatchKind::TypeConflict: {
|
||||||
tc.diagnose(match.Witness, diag::protocol_witness_type_conflict,
|
auto diag = tc.diagnose(match.Witness, diag::protocol_witness_type_conflict,
|
||||||
getTypeForDisplay(tc, module, match.Witness),
|
getTypeForDisplay(tc, module, match.Witness),
|
||||||
withAssocTypes);
|
withAssocTypes);
|
||||||
|
if (!isa<TypeDecl>(req))
|
||||||
|
fixItOverrideDeclarationTypes(tc, diag, match.Witness, req);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MatchKind::ThrowsConflict:
|
case MatchKind::ThrowsConflict:
|
||||||
tc.diagnose(match.Witness, diag::protocol_witness_throws_conflict);
|
tc.diagnose(match.Witness, diag::protocol_witness_throws_conflict);
|
||||||
|
|||||||
@@ -85,3 +85,125 @@ class Sub : Base {
|
|||||||
return super.prop // expected-error {{return type}}
|
return super.prop // expected-error {{return type}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protocol TestProto {
|
||||||
|
func test(a: Refrigerator, b: Refrigerator) -> Refrigerator? // expected-note {{protocol requires}} {{none}}
|
||||||
|
func testGeneric(a: ManufacturerInfo<NSString>, b: ManufacturerInfo<NSString>) -> ManufacturerInfo<NSString>? // expected-note {{protocol requires}} {{none}}
|
||||||
|
static func testInout(_: inout Refrigerator) // expected-note {{protocol requires}} {{none}}
|
||||||
|
func testUnmigrated(a: NSRuncingMode, b: Refrigerator, c: NSCoding) // expected-note {{protocol requires}} {{none}}
|
||||||
|
func testPartialMigrated(a: NSRuncingMode, b: Refrigerator) // expected-note {{protocol requires}} {{none}}
|
||||||
|
|
||||||
|
subscript(a a: Refrigerator, b b: Refrigerator) -> Refrigerator? { get } // expected-note {{protocol requires}} {{none}}
|
||||||
|
subscript(generic a: ManufacturerInfo<NSString>, b b: ManufacturerInfo<NSString>) -> ManufacturerInfo<NSString>? { get } // expected-note {{protocol requires}} {{none}}
|
||||||
|
|
||||||
|
init?(a: Refrigerator, b: Refrigerator) // expected-note {{protocol requires}} {{none}}
|
||||||
|
init?(generic: ManufacturerInfo<NSString>, b: ManufacturerInfo<NSString>) // expected-note {{protocol requires}} {{none}}
|
||||||
|
init(singleArgument: Refrigerator) // expected-note {{protocol requires}} {{none}}
|
||||||
|
|
||||||
|
var prop: Refrigerator? { get } // expected-note {{protocol requires}} {{none}}
|
||||||
|
var propGeneric: ManufacturerInfo<NSString>? { get } // expected-note {{protocol requires}} {{none}}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestProtoImpl : NSObject, TestProto { // expected-error {{type 'TestProtoImpl' does not conform to protocol 'TestProto'}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPRefrigerator, b: APPRefrigerator?) -> APPRefrigerator'}} {{16-31=Refrigerator}} {{36-52=Refrigerator?}} {{57-72=Refrigerator}}
|
||||||
|
func test(a: APPRefrigerator, b: APPRefrigerator?) -> APPRefrigerator {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject>'}} {{23-53=ManufacturerInfo<NSString>}} {{58-89=ManufacturerInfo<NSString>?}} {{94-124=ManufacturerInfo<NSString>}}
|
||||||
|
func testGeneric(a: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject> {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(inout APPRefrigerator) -> ()'}} {{27-48=inout Refrigerator}}
|
||||||
|
class func testInout(_: inout APPRefrigerator) {}
|
||||||
|
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: NSObject, b: NSObject, c: NSObject) -> ()'}}
|
||||||
|
func testUnmigrated(a: NSObject, b: NSObject, c: NSObject) {}
|
||||||
|
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: NSObject, b: APPRefrigerator) -> ()'}} {{44-59=Refrigerator}}
|
||||||
|
func testPartialMigrated(a: NSObject, b: APPRefrigerator) {}
|
||||||
|
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPRefrigerator, b: APPRefrigerator?) -> APPRefrigerator'}} {{18-33=Refrigerator}} {{40-56=Refrigerator?}} {{61-76=Refrigerator}}
|
||||||
|
subscript(a a: APPRefrigerator, b b: APPRefrigerator?) -> APPRefrigerator {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(generic: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject>'}} {{24-54=ManufacturerInfo<NSString>}} {{61-92=ManufacturerInfo<NSString>?}} {{97-127=ManufacturerInfo<NSString>}}
|
||||||
|
subscript(generic a: APPManufacturerInfo<AnyObject>, b b: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject> {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPRefrigerator, b: APPRefrigerator?)'}} {{11-26=Refrigerator}} {{31-47=Refrigerator?}}
|
||||||
|
init(a: APPRefrigerator, b: APPRefrigerator?) {}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(generic: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?)'}} {{19-49=ManufacturerInfo<NSString>}} {{54-85=ManufacturerInfo<NSString>?}}
|
||||||
|
init(generic a: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?) {}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(singleArgument: APPRefrigerator)'}} {{24-39=Refrigerator}}
|
||||||
|
init(singleArgument: APPRefrigerator) {}
|
||||||
|
|
||||||
|
// expected-note@+1 {{candidate has non-matching type 'APPRefrigerator?'}} {{13-29=Refrigerator?}} {{none}}
|
||||||
|
var prop: APPRefrigerator? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type 'APPManufacturerInfo<AnyObject>?'}} {{20-51=ManufacturerInfo<NSString>?}}
|
||||||
|
var propGeneric: APPManufacturerInfo<AnyObject>? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@objc protocol TestObjCProto {
|
||||||
|
@objc optional func test(a: Refrigerator, b: Refrigerator) -> Refrigerator? // expected-note {{here}} {{none}}
|
||||||
|
@objc optional func testGeneric(a: ManufacturerInfo<NSString>, b: ManufacturerInfo<NSString>) -> ManufacturerInfo<NSString>? // expected-note {{here}} {{none}}
|
||||||
|
@objc optional func testUnmigrated(a: NSRuncingMode, b: Refrigerator, c: NSCoding) // expected-note {{here}} {{none}}
|
||||||
|
@objc optional func testPartialMigrated(a: NSRuncingMode, b: Refrigerator) // expected-note {{here}} {{none}}
|
||||||
|
|
||||||
|
@objc optional subscript(a a: Refrigerator) -> Refrigerator? { get } // expected-note {{here}} {{none}}
|
||||||
|
@objc optional subscript(generic a: ManufacturerInfo<NSString>) -> ManufacturerInfo<NSString>? { get } // expected-note {{here}} {{none}}
|
||||||
|
|
||||||
|
@objc optional var prop: Refrigerator? { get } // expected-note {{here}} {{none}}
|
||||||
|
@objc optional var propGeneric: ManufacturerInfo<NSString>? { get } // expected-note {{here}} {{none}}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestObjCProtoImpl : NSObject, TestObjCProto {
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPRefrigerator, b: APPRefrigerator?) -> APPRefrigerator'}} {{16-31=Refrigerator}} {{36-52=Refrigerator?}} {{57-72=Refrigerator}}
|
||||||
|
func test(a: APPRefrigerator, b: APPRefrigerator?) -> APPRefrigerator { // expected-warning {{instance method 'test(a:b:)' nearly matches optional requirement 'test(a:b:)' of protocol 'TestObjCProto'}}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject>'}} {{23-53=ManufacturerInfo<NSString>}} {{58-89=ManufacturerInfo<NSString>?}} {{94-124=ManufacturerInfo<NSString>}}
|
||||||
|
func testGeneric(a: APPManufacturerInfo<AnyObject>, b: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject> { // expected-warning {{instance method 'testGeneric(a:b:)' nearly matches optional requirement 'testGeneric(a:b:)' of protocol 'TestObjCProto'}} {{none}}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: NSObject, b: NSObject, c: NSObject) -> ()'}} {{none}}
|
||||||
|
func testUnmigrated(a: NSObject, b: NSObject, c: NSObject) {} // expected-warning {{instance method 'testUnmigrated(a:b:c:)' nearly matches optional requirement 'testUnmigrated(a:b:c:)' of protocol 'TestObjCProto'}}
|
||||||
|
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: NSObject, b: APPRefrigerator) -> ()'}} {{44-59=Refrigerator}}
|
||||||
|
func testPartialMigrated(a: NSObject, b: APPRefrigerator) {} // expected-warning {{instance method 'testPartialMigrated(a:b:)' nearly matches optional requirement 'testPartialMigrated(a:b:)' of protocol 'TestObjCProto'}} {{none}}
|
||||||
|
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(a: APPRefrigerator?) -> APPRefrigerator'}} {{18-34=Refrigerator?}} {{39-54=Refrigerator}}
|
||||||
|
subscript(a a: APPRefrigerator?) -> APPRefrigerator { // expected-warning {{subscript 'subscript(a:)' nearly matches optional requirement 'subscript(a:)' of protocol 'TestObjCProto'}} {{none}}
|
||||||
|
// expected-note@-1 {{here}}
|
||||||
|
return a!
|
||||||
|
}
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type '(generic: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject>'}} {{24-55=ManufacturerInfo<NSString>?}} {{60-90=ManufacturerInfo<NSString>}}
|
||||||
|
subscript(generic a: APPManufacturerInfo<AnyObject>?) -> APPManufacturerInfo<AnyObject> { // expected-warning {{subscript 'subscript(generic:)' nearly matches optional requirement 'subscript(generic:)' of protocol 'TestObjCProto'}} {{none}}
|
||||||
|
// expected-error@-1 {{subscript getter with Objective-C selector 'objectForKeyedSubscript:' conflicts with previous declaration with the same Objective-C selector}}
|
||||||
|
return a!
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type 'APPRefrigerator?'}} {{13-29=Refrigerator?}}
|
||||||
|
var prop: APPRefrigerator? { // expected-warning {{var 'prop' nearly matches optional requirement 'prop' of protocol 'TestObjCProto'}} {{none}}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected-note@+2 {{private}} expected-note@+2 {{@nonobjc}} expected-note@+2 {{extension}}
|
||||||
|
// expected-note@+1 {{candidate has non-matching type 'APPManufacturerInfo<AnyObject>?'}} {{20-51=ManufacturerInfo<NSString>?}}
|
||||||
|
var propGeneric: APPManufacturerInfo<AnyObject>? { // expected-warning {{var 'propGeneric' nearly matches optional requirement 'propGeneric' of protocol 'TestObjCProto'}} {{none}}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user