Skip to content

Commit dd09401

Browse files
authored
Merge pull request #29528 from xedin/anyobject-conversion-diagnostics
[Diagnostics] Port invalid conversion to AnyObject diagnostic
2 parents 7710ee8 + ec3b783 commit dd09401

12 files changed

+136
-38
lines changed

include/swift/AST/DiagnosticsSema.def

+16-1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ ERROR(cannot_convert_initializer_value,none,
338338
"cannot convert value of type %0 to specified type %1", (Type,Type))
339339
ERROR(cannot_convert_initializer_value_protocol,none,
340340
"value of type %0 does not conform to specified type %1", (Type,Type))
341+
ERROR(cannot_convert_initializer_value_anyobject,none,
342+
"value of type %0 expected to be instance of class or "
343+
"class-constrained type",
344+
(Type, Type))
341345
ERROR(cannot_convert_initializer_value_nil,none,
342346
"'nil' cannot initialize specified type %0", (Type))
343347

@@ -346,6 +350,10 @@ ERROR(cannot_convert_to_return_type,none,
346350
(Type,Type))
347351
ERROR(cannot_convert_to_return_type_protocol,none,
348352
"return expression of type %0 does not conform to %1", (Type,Type))
353+
ERROR(cannot_convert_return_type_to_anyobject,none,
354+
"return expression of type %0 expected to be an instance of "
355+
"a class or class-constrained type",
356+
(Type, Type))
349357
ERROR(cannot_convert_to_return_type_nil,none,
350358
"'nil' is incompatible with return type %0", (Type))
351359

@@ -440,7 +448,10 @@ NOTE(candidate_performs_illegal_ephemeral_conv,none,
440448

441449
ERROR(cannot_convert_argument_value_protocol,none,
442450
"argument type %0 does not conform to expected type %1", (Type, Type))
443-
451+
ERROR(cannot_convert_argument_value_anyobject,none,
452+
"argument type %0 expected to be an instance of "
453+
"a class or class-constrained type",
454+
(Type, Type))
444455
ERROR(cannot_convert_argument_value_nil,none,
445456
"'nil' is not compatible with expected argument type %0", (Type))
446457

@@ -536,6 +547,10 @@ NOTE(assign_protocol_conformance_fix_it,none,
536547
ERROR(cannot_convert_assign_protocol,none,
537548
"value of type %0 does not conform to %1 in assignment",
538549
(Type, Type))
550+
ERROR(cannot_convert_assign_anyobject,none,
551+
"value of type %0 expected to be an instance of "
552+
"a class or class-constrained type in assignment",
553+
(Type, Type))
539554
ERROR(cannot_convert_assign_nil,none,
540555
"'nil' cannot be assigned to type %0", (Type))
541556

lib/Sema/CSDiagnostics.cpp

+38-18
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,7 @@ bool ContextualFailure::diagnoseAsError() {
19771977
CTP = CTP_ClosureResult;
19781978
}
19791979

1980-
if (auto msg = getDiagnosticFor(CTP, toType->isExistentialType())) {
1980+
if (auto msg = getDiagnosticFor(CTP, toType)) {
19811981
diagnostic = *msg;
19821982
break;
19831983
}
@@ -2276,11 +2276,9 @@ bool ContextualFailure::diagnoseCoercionToUnrelatedType() const {
22762276
if (auto *coerceExpr = dyn_cast<CoerceExpr>(anchor)) {
22772277
auto fromType = getType(coerceExpr->getSubExpr());
22782278
auto toType = getType(coerceExpr->getCastTypeLoc());
2279-
2280-
auto diagnostic =
2281-
getDiagnosticFor(CTP_CoerceOperand,
2282-
/*forProtocol=*/toType->isExistentialType());
2283-
2279+
2280+
auto diagnostic = getDiagnosticFor(CTP_CoerceOperand, toType);
2281+
22842282
auto diag =
22852283
emitDiagnostic(anchor->getLoc(), *diagnostic, fromType, toType);
22862284
diag.highlight(anchor->getSourceRange());
@@ -2844,15 +2842,24 @@ bool ContextualFailure::isIntegerToStringIndexConversion() const {
28442842

28452843
Optional<Diag<Type, Type>>
28462844
ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
2847-
bool forProtocol) {
2845+
Type contextualType) {
2846+
auto forProtocol = contextualType->isExistentialType();
28482847
switch (context) {
2849-
case CTP_Initialization:
2848+
case CTP_Initialization: {
2849+
if (contextualType->isAnyObject())
2850+
return diag::cannot_convert_initializer_value_anyobject;
2851+
28502852
return forProtocol ? diag::cannot_convert_initializer_value_protocol
28512853
: diag::cannot_convert_initializer_value;
2854+
}
28522855
case CTP_ReturnStmt:
2853-
case CTP_ReturnSingleExpr:
2856+
case CTP_ReturnSingleExpr: {
2857+
if (contextualType->isAnyObject())
2858+
return diag::cannot_convert_return_type_to_anyobject;
2859+
28542860
return forProtocol ? diag::cannot_convert_to_return_type_protocol
28552861
: diag::cannot_convert_to_return_type;
2862+
}
28562863
case CTP_EnumCaseRawValue:
28572864
return diag::cannot_convert_raw_initializer_value;
28582865
case CTP_DefaultParameter:
@@ -2861,9 +2868,13 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
28612868
case CTP_YieldByValue:
28622869
return forProtocol ? diag::cannot_convert_yield_value_protocol
28632870
: diag::cannot_convert_yield_value;
2864-
case CTP_CallArgument:
2871+
case CTP_CallArgument: {
2872+
if (contextualType->isAnyObject())
2873+
return diag::cannot_convert_argument_value_anyobject;
2874+
28652875
return forProtocol ? diag::cannot_convert_argument_value_protocol
28662876
: diag::cannot_convert_argument_value;
2877+
}
28672878
case CTP_ClosureResult:
28682879
return forProtocol ? diag::cannot_convert_closure_result_protocol
28692880
: diag::cannot_convert_closure_result;
@@ -2879,9 +2890,13 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
28792890
case CTP_CoerceOperand:
28802891
return forProtocol ? diag::cannot_convert_coerce_protocol
28812892
: diag::cannot_convert_coerce;
2882-
case CTP_AssignSource:
2893+
case CTP_AssignSource: {
2894+
if (contextualType->isAnyObject())
2895+
return diag::cannot_convert_assign_anyobject;
2896+
28832897
return forProtocol ? diag::cannot_convert_assign_protocol
28842898
: diag::cannot_convert_assign;
2899+
}
28852900
case CTP_SubscriptAssignSource:
28862901
return forProtocol ? diag::cannot_convert_subscript_assign_protocol
28872902
: diag::cannot_convert_subscript_assign;
@@ -2908,7 +2923,7 @@ bool TupleContextualFailure::diagnoseAsError() {
29082923
else if ((purpose == CTP_Initialization) &&
29092924
!cs.getContextualType(getAnchor()))
29102925
diagnostic = diag::tuple_types_not_convertible;
2911-
else if (auto diag = getDiagnosticFor(purpose, /*forProtocol=*/false))
2926+
else if (auto diag = getDiagnosticFor(purpose, getToType()))
29122927
diagnostic = *diag;
29132928
else
29142929
return false;
@@ -2919,7 +2934,7 @@ bool TupleContextualFailure::diagnoseAsError() {
29192934

29202935
bool FunctionTypeMismatch::diagnoseAsError() {
29212936
auto purpose = getContextualTypePurpose();
2922-
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);
2937+
auto diagnostic = getDiagnosticFor(purpose, getToType());
29232938
if (!diagnostic)
29242939
return false;
29252940

@@ -4839,17 +4854,16 @@ bool MissingContextualConformanceFailure::diagnoseAsError() {
48394854
if (path.empty()) {
48404855
assert(isa<AssignExpr>(anchor));
48414856
if (isa<SubscriptExpr>(cast<AssignExpr>(anchor)->getDest())) {
4842-
diagnostic =
4843-
getDiagnosticFor(CTP_SubscriptAssignSource, /*forProtocol=*/true);
4857+
diagnostic = getDiagnosticFor(CTP_SubscriptAssignSource, getToType());
48444858
} else {
4845-
diagnostic = getDiagnosticFor(CTP_AssignSource, /*forProtocol=*/true);
4859+
diagnostic = getDiagnosticFor(CTP_AssignSource, getToType());
48464860
}
48474861
} else {
48484862
const auto &last = path.back();
48494863
switch (last.getKind()) {
48504864
case ConstraintLocator::ContextualType:
48514865
assert(Context != CTP_Unused);
4852-
diagnostic = getDiagnosticFor(Context, /*forProtocol=*/true);
4866+
diagnostic = getDiagnosticFor(Context, getToType());
48534867
break;
48544868

48554869
case ConstraintLocator::SequenceElementType: {
@@ -5277,7 +5291,7 @@ bool InOutConversionFailure::diagnoseAsError() {
52775291
assert(locator->findLast<LocatorPathElt::ContextualType>());
52785292
auto contextualType = cs.getContextualType(anchor);
52795293
auto purpose = getContextualTypePurpose();
5280-
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);
5294+
auto diagnostic = getDiagnosticFor(purpose, contextualType);
52815295

52825296
if (!diagnostic)
52835297
return false;
@@ -5385,6 +5399,12 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
53855399
auto argType = getFromType();
53865400
auto paramType = getToType();
53875401

5402+
if (paramType->isAnyObject()) {
5403+
emitDiagnostic(getLoc(), diag::cannot_convert_argument_value_anyobject,
5404+
argType, paramType);
5405+
return true;
5406+
}
5407+
53885408
Diag<Type, Type> diagnostic = diag::cannot_convert_argument_value;
53895409

53905410
// If parameter type is a protocol value, let's says that

lib/Sema/CSDiagnostics.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ class ContextualFailure : public FailureDiagnostic {
653653
ContextualTypePurpose getContextualTypePurpose() const { return CTP; }
654654

655655
static Optional<Diag<Type, Type>>
656-
getDiagnosticFor(ContextualTypePurpose context, bool forProtocol);
656+
getDiagnosticFor(ContextualTypePurpose context, Type contextualType);
657657
};
658658

659659
/// Diagnose errors related to converting function type which

lib/Sema/CSFix.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -1180,3 +1180,40 @@ SpecifyObjectLiteralTypeImport::create(ConstraintSystem &cs,
11801180
ConstraintLocator *locator) {
11811181
return new (cs.getAllocator()) SpecifyObjectLiteralTypeImport(cs, locator);
11821182
}
1183+
1184+
AllowNonClassTypeToConvertToAnyObject::AllowNonClassTypeToConvertToAnyObject(
1185+
ConstraintSystem &cs, Type type, ConstraintLocator *locator)
1186+
: ContextualMismatch(cs, FixKind::AllowNonClassTypeToConvertToAnyObject,
1187+
type, cs.getASTContext().getAnyObjectType(), locator) {
1188+
}
1189+
1190+
bool AllowNonClassTypeToConvertToAnyObject::diagnose(bool asNote) const {
1191+
auto &cs = getConstraintSystem();
1192+
1193+
auto *locator = getLocator();
1194+
if (locator->getPath().empty())
1195+
return false;
1196+
1197+
const auto &last = locator->getPath().back();
1198+
switch (last.getKind()) {
1199+
case ConstraintLocator::ContextualType: {
1200+
ContextualFailure failure(cs, getFromType(), getToType(), locator);
1201+
return failure.diagnose(asNote);
1202+
}
1203+
1204+
case ConstraintLocator::ApplyArgToParam: {
1205+
ArgumentMismatchFailure failure(cs, getFromType(), getToType(), locator);
1206+
return failure.diagnose(asNote);
1207+
}
1208+
1209+
default:
1210+
return false;
1211+
}
1212+
}
1213+
1214+
AllowNonClassTypeToConvertToAnyObject *
1215+
AllowNonClassTypeToConvertToAnyObject::create(ConstraintSystem &cs, Type type,
1216+
ConstraintLocator *locator) {
1217+
return new (cs.getAllocator())
1218+
AllowNonClassTypeToConvertToAnyObject(cs, type, locator);
1219+
}

lib/Sema/CSFix.h

+20-2
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,15 @@ enum class FixKind : uint8_t {
235235
/// Closure return type has to be explicitly specified because it can't be
236236
/// inferred in current context e.g. because it's a multi-statement closure.
237237
SpecifyClosureReturnType,
238-
239-
/// Object literal type coudn't be infered because the module where
238+
239+
/// Object literal type coudn't be inferred because the module where
240240
/// the default type that implements the associated literal protocol
241241
/// is declared was not imported.
242242
SpecifyObjectLiteralTypeImport,
243243

244+
/// Allow any type (and not just class or class-constrained type) to
245+
/// be convertible to AnyObject.
246+
AllowNonClassTypeToConvertToAnyObject,
244247
};
245248

246249
class ConstraintFix {
@@ -1655,6 +1658,21 @@ class SpecifyObjectLiteralTypeImport final : public ConstraintFix {
16551658

16561659
};
16571660

1661+
class AllowNonClassTypeToConvertToAnyObject final : public ContextualMismatch {
1662+
AllowNonClassTypeToConvertToAnyObject(ConstraintSystem &cs, Type type,
1663+
ConstraintLocator *locator);
1664+
1665+
public:
1666+
std::string getName() const {
1667+
return "allow non-class type to convert to 'AnyObject'";
1668+
}
1669+
1670+
bool diagnose(bool asNote = false) const;
1671+
1672+
static AllowNonClassTypeToConvertToAnyObject *
1673+
create(ConstraintSystem &cs, Type type, ConstraintLocator *locator);
1674+
};
1675+
16581676
} // end namespace constraints
16591677
} // end namespace swift
16601678

lib/Sema/CSSimplify.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -2095,9 +2095,17 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
20952095
// Subtype relation to AnyObject also allows class-bound
20962096
// existentials that are not @objc and therefore carry
20972097
// witness tables.
2098-
if (!type1->isClassExistentialType() &&
2099-
!type1->mayHaveSuperclass())
2098+
if (!type1->isClassExistentialType() && !type1->mayHaveSuperclass()) {
2099+
if (shouldAttemptFixes()) {
2100+
auto *fix = AllowNonClassTypeToConvertToAnyObject::create(
2101+
*this, type1, getConstraintLocator(locator));
2102+
2103+
return recordFix(fix) ? getTypeMatchFailure(locator)
2104+
: getTypeMatchSuccess();
2105+
}
2106+
21002107
return getTypeMatchFailure(locator);
2108+
}
21012109
}
21022110

21032111
// Keep going.
@@ -8842,6 +8850,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
88428850
case FixKind::AllowMutatingMemberOnRValueBase:
88438851
case FixKind::AllowTupleSplatForSingleParameter:
88448852
case FixKind::AllowInvalidUseOfTrailingClosure:
8853+
case FixKind::AllowNonClassTypeToConvertToAnyObject:
88458854
case FixKind::SpecifyClosureReturnType:
88468855
llvm_unreachable("handled elsewhere");
88478856
}

test/ClangImporter/attr-swift_private.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func testCF(_ a: __PrivCFType, b: __PrivCFSub, c: __PrivInt) {
121121
makeSureAnyObject(a)
122122
makeSureAnyObject(b)
123123
#if !IRGEN
124-
makeSureAnyObject(c) // expected-error {{argument type '__PrivInt' (aka 'Int32') does not conform to expected type 'AnyObject'}}
124+
makeSureAnyObject(c) // expected-error {{argument type '__PrivInt' (aka 'Int32') expected to be an instance of a class or class-constrained type}}
125125
#endif
126126
}
127127

test/Constraints/bridging.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func bridgeToObjC(_ s: BridgedStruct) -> BridgedClass {
8989
}
9090

9191
func bridgeToAnyObject(_ s: BridgedStruct) -> AnyObject {
92-
return s // expected-error{{return expression of type 'BridgedStruct' does not conform to 'AnyObject'}}
92+
return s // expected-error{{return expression of type 'BridgedStruct' expected to be an instance of a class or class-constrained type}}
9393
return s as AnyObject
9494
}
9595

@@ -344,14 +344,14 @@ func forceUniversalBridgeToAnyObject<T, U: KnownClassProtocol>(a: T, b: U, c: An
344344
z = g as AnyObject
345345
z = h as AnyObject
346346

347-
z = a // expected-error{{does not conform to 'AnyObject'}}
347+
z = a // expected-error{{value of type 'T' expected to be an instance of a class or class-constrained type in assignment}}
348348
z = b
349-
z = c // expected-error{{does not conform to 'AnyObject'}} expected-note {{cast 'Any' to 'AnyObject'}} {{8-8= as AnyObject}}
350-
z = d // expected-error{{does not conform to 'AnyObject'}}
349+
z = c // expected-error{{value of type 'Any' expected to be an instance of a class or class-constrained type in assignment}} expected-note {{cast 'Any' to 'AnyObject'}} {{8-8= as AnyObject}}
350+
z = d // expected-error{{value of type 'KnownUnbridged' expected to be an instance of a class or class-constrained type in assignment}}
351351
z = e
352352
z = f
353353
z = g
354-
z = h // expected-error{{does not conform to 'AnyObject'}}
354+
z = h // expected-error{{value of type 'String' expected to be an instance of a class or class-constrained type in assignment}}
355355

356356
_ = z
357357
}

test/Generics/existential_restrictions.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func fT<T>(_ t: T) { }
2525
func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) {
2626
fP(p) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
2727
fAO(p) // expected-error{{global function 'fAO' requires that 'P' be a class type}}
28-
fAOE(p) // expected-error{{argument type 'P' does not conform to expected type 'AnyObject'}}
28+
fAOE(p) // expected-error{{argument type 'P' expected to be an instance of a class or class-constrained type}}
2929
fT(p)
3030

3131
fOP(op)

test/Interpreter/SDK/misc_osx.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ func testFSEventStreamRef(stream: FSEventStreamRef) {
1313
FSEventStreamRetain(stream) // no-warning
1414
FSEventStreamRelease(stream)
1515

16-
let _: AnyObject = stream // expected-error {{value of type 'FSEventStreamRef' (aka 'OpaquePointer') does not conform to specified type 'AnyObject'}}
16+
let _: AnyObject = stream // expected-error {{value of type 'FSEventStreamRef' (aka 'OpaquePointer') expected to be instance of class or class-constrained type}}
1717
}

test/Parse/metatype_object_conversion.swift

+3-4
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@ func takesAnyObject(_ x: AnyObject) {}
1212

1313
func concreteTypes() {
1414
takesAnyObject(C.self)
15-
// TODO: Better error messages
16-
takesAnyObject(S.self) // expected-error{{argument type 'S.Type' does not conform to expected type 'AnyObject'}}
17-
takesAnyObject(ClassConstrainedProto.self) // expected-error{{argument type 'ClassConstrainedProto.Protocol' does not conform to expected type 'AnyObject'}}
15+
takesAnyObject(S.self) // expected-error{{argument type 'S.Type' expected to be an instance of a class or class-constrained type}}
16+
takesAnyObject(ClassConstrainedProto.self) // expected-error{{argument type 'ClassConstrainedProto.Protocol' expected to be an instance of a class or class-constrained type}}
1817
}
1918

2019
func existentialMetatypes(nonClass: NonClassProto.Type,
2120
classConstrained: ClassConstrainedProto.Type,
2221
compo: (NonClassProto & ClassConstrainedProto).Type) {
23-
takesAnyObject(nonClass) // expected-error{{argument type 'NonClassProto.Type' does not conform to expected type 'AnyObject'}}
22+
takesAnyObject(nonClass) // expected-error{{argument type 'NonClassProto.Type' expected to be an instance of a class or class-constrained type}}
2423
takesAnyObject(classConstrained)
2524
takesAnyObject(compo)
2625
}

test/Sema/diag_metatype_cast_to_reference_no_objc.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
class C {}
44

55
func test(c: AnyClass) {
6-
let _: AnyObject = c // expected-error {{value of type 'AnyClass' (aka 'AnyObject.Type') does not conform to specified type 'AnyObject'}}
7-
let _: AnyObject = C.self // expected-error {{value of type 'C.Type' does not conform to specified type 'AnyObject'}}
6+
let _: AnyObject = c // expected-error {{value of type 'AnyClass' (aka 'AnyObject.Type') expected to be instance of class or class-constrained type}}
7+
let _: AnyObject = C.self // expected-error {{value of type 'C.Type' expected to be instance of class or class-constrained type}}
88
}

0 commit comments

Comments
 (0)