From 331b570329ce52cd169be1ed206ee2dfc06fa716 Mon Sep 17 00:00:00 2001 From: Chris Willmore Date: Fri, 1 May 2015 08:27:19 +0000 Subject: [PATCH] Remove reverse subtype constraint between Objective-C classes when type checking checked cast via bridging. It prevented bridging upcasts using 'as!' from typechecking; we should emit an 'as!'->'as' warning instead. Also, use ExplicitConversion constraint instead of Conversion when determining whether a checked cast can be carried out unconditionally. This matches the constraint used after applying the 'as!'->'as' fixit. (Also, fix the error that was responsible for breaking the expr/cast/bridged.swift test.) Swift SVN r28034 --- lib/Sema/CSSimplify.cpp | 17 +++++------------ lib/Sema/TypeCheckConstraints.cpp | 5 +++-- test/Constraints/bridging.swift | 7 +++++++ test/expr/cast/bridged.swift | 11 +++++++++-- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 63d00894091..010b411d5a5 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2518,22 +2518,15 @@ ConstraintSystem::simplifyCheckedCastConstraint( case CheckedCastKind::BridgeFromObjectiveC: { // This existential-to-concrete cast might bridge through an Objective-C // class type. - if (auto classType = TC.getDynamicBridgedThroughObjCClass(DC, true, - fromType, - toType)) { - // The class we're bridging through must be a subtype of the type we're - // coming from. - addConstraint(ConstraintKind::Subtype, classType, fromType, - getConstraintLocator(locator)); - return SolutionKind::Solved; - } - Type objCClass = TC.getDynamicBridgedThroughObjCClass(DC, true, fromType, toType); assert(objCClass && "Type must be bridged"); - addConstraint(ConstraintKind::Subtype, objCClass, fromType, - getConstraintLocator(locator)); + (void)objCClass; + // Otherwise no constraint is necessary; as long as both objCClass and + // fromType are Objective-C types, they can't have any open type variables, + // and conversion between unrelated classes will be diagnosed in + // typeCheckCheckedCast. return SolutionKind::Solved; } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 4b9cdddf709..b6549f90046 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2023,9 +2023,10 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, SourceRange diagToRange, std::function convertToType, bool suppressDiagnostics) { - // If the from/to types are equivalent or implicitly convertible, + // If the from/to types are equivalent or explicitly convertible, // this is a coercion. - if (fromType->isEqual(toType) || isConvertibleTo(fromType, toType, dc)) { + if (fromType->isEqual(toType) || + isExplicitlyConvertibleTo(fromType, toType, dc)) { return CheckedCastKind::Coercion; } diff --git a/test/Constraints/bridging.swift b/test/Constraints/bridging.swift index c77acbbfdf3..01f14e28eba 100644 --- a/test/Constraints/bridging.swift +++ b/test/Constraints/bridging.swift @@ -257,3 +257,10 @@ func rdar20029786(ns: NSString?) { var s4: String = ns ?? "str" // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}}{{20-20=(}}{{31-31=) as String}} var s5: String = (ns ?? "str") as String // fixed version } + +// QoI: Using as! instead of as in this case produces really bad diagnostic +func rdar19813772(nsma: NSMutableArray) { + var a1 = nsma as! Array // expected-error{{argument for generic parameter 'T' could not be inferred}} + var a2 = nsma as! Array // expected-warning{{forced cast from 'NSMutableArray' to 'Array' always succeeds; did you mean to use 'as'?}} + var a3 = nsma as Array +} diff --git a/test/expr/cast/bridged.swift b/test/expr/cast/bridged.swift index 148148837e8..e427e5423e8 100644 --- a/test/expr/cast/bridged.swift +++ b/test/expr/cast/bridged.swift @@ -9,6 +9,8 @@ class NSObject { } class BridgedClass : NSObject { } +class SubclassOfBridgedClass : BridgedClass { } + struct BridgedStruct : _ObjectiveCBridgeable { static func _isBridgedToObjectiveC() -> Bool { return true @@ -67,12 +69,17 @@ func testBridgeDowncastSuperclass(obj: NSObject, objOpt: NSObject?, func testBridgeDowncastExact(obj: BridgedClass, objOpt: BridgedClass?, objImplicitOpt: BridgedClass!) -> BridgedStruct? { - var s1Opt = obj as? BridgedStruct + var s1Opt = obj as? BridgedStruct // expected-warning{{conditional cast from 'BridgedClass' to 'BridgedStruct' always succeeds}} var s2Opt = objOpt as? BridgedStruct - var s3Opt = objImplicitOpt as? BridgedStruct + var s3Opt = objImplicitOpt as? BridgedStruct // expected-warning{{conditional cast from 'BridgedClass!' to 'BridgedStruct' always succeeds}} } func testExplicitBridging(var object: BridgedClass, var value: BridgedStruct) { object = value as BridgedClass value = object as BridgedStruct } + +func testBridgingFromSubclass(obj: SubclassOfBridgedClass) { + var s1 = obj as! BridgedStruct // expected-warning{{forced cast from 'SubclassOfBridgedClass' to 'BridgedStruct' always succeeds; did you mean to use 'as'?}} + var s2 = obj as BridgedStruct +}