Skip to content

Commit 137c9cc

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-rebranch
2 parents 996f043 + d2445d5 commit 137c9cc

File tree

9 files changed

+136
-95
lines changed

9 files changed

+136
-95
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -921,8 +921,9 @@ bool MissingExplicitConversionFailure::diagnoseAsError() {
921921
if (auto *paren = dyn_cast<ParenExpr>(anchor))
922922
anchor = paren->getSubExpr();
923923

924-
auto fromType = getType(anchor)->getRValueType();
925-
Type toType = resolveType(ConvertingTo);
924+
auto fromType = getFromType();
925+
Type toType = getToType();
926+
926927
if (!toType->hasTypeRepr())
927928
return false;
928929

lib/Sema/CSDiagnostics.h

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -544,45 +544,6 @@ class MissingForcedDowncastFailure final : public FailureDiagnostic {
544544
bool diagnoseAsError() override;
545545
};
546546

547-
/// Diagnose failures related attempt to implicitly convert types which
548-
/// do not support such implicit converstion.
549-
/// "as" or "as!" has to be specified explicitly in cases like that.
550-
class MissingExplicitConversionFailure final : public FailureDiagnostic {
551-
Type ConvertingTo;
552-
553-
public:
554-
MissingExplicitConversionFailure(Expr *expr, ConstraintSystem &cs,
555-
ConstraintLocator *locator, Type toType)
556-
: FailureDiagnostic(expr, cs, locator), ConvertingTo(toType) {}
557-
558-
bool diagnoseAsError() override;
559-
560-
private:
561-
bool exprNeedsParensBeforeAddingAs(Expr *expr) {
562-
auto *DC = getDC();
563-
auto &TC = getTypeChecker();
564-
565-
auto asPG = TC.lookupPrecedenceGroup(
566-
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc());
567-
if (!asPG)
568-
return true;
569-
return exprNeedsParensInsideFollowingOperator(TC, DC, expr, asPG);
570-
}
571-
572-
bool exprNeedsParensAfterAddingAs(Expr *expr, Expr *rootExpr) {
573-
auto *DC = getDC();
574-
auto &TC = getTypeChecker();
575-
576-
auto asPG = TC.lookupPrecedenceGroup(
577-
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc());
578-
if (!asPG)
579-
return true;
580-
581-
return exprNeedsParensOutsideFollowingOperator(TC, DC, expr, rootExpr,
582-
asPG);
583-
}
584-
};
585-
586547
/// Diagnose failures related to attempting member access on optional base
587548
/// type without optional chaining or force-unwrapping it first.
588549
class MemberAccessOnOptionalBaseFailure final : public FailureDiagnostic {
@@ -739,6 +700,44 @@ class ContextualFailure : public FailureDiagnostic {
739700
void tryComputedPropertyFixIts(Expr *expr) const;
740701
};
741702

703+
/// Diagnose failures related attempt to implicitly convert types which
704+
/// do not support such implicit converstion.
705+
/// "as" or "as!" has to be specified explicitly in cases like that.
706+
class MissingExplicitConversionFailure final : public ContextualFailure {
707+
public:
708+
MissingExplicitConversionFailure(Expr *expr, ConstraintSystem &cs,
709+
Type fromType, Type toType,
710+
ConstraintLocator *locator)
711+
: ContextualFailure(expr, cs, fromType, toType, locator) {}
712+
713+
bool diagnoseAsError() override;
714+
715+
private:
716+
bool exprNeedsParensBeforeAddingAs(Expr *expr) {
717+
auto *DC = getDC();
718+
auto &TC = getTypeChecker();
719+
720+
auto asPG = TC.lookupPrecedenceGroup(
721+
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc());
722+
if (!asPG)
723+
return true;
724+
return exprNeedsParensInsideFollowingOperator(TC, DC, expr, asPG);
725+
}
726+
727+
bool exprNeedsParensAfterAddingAs(Expr *expr, Expr *rootExpr) {
728+
auto *DC = getDC();
729+
auto &TC = getTypeChecker();
730+
731+
auto asPG = TC.lookupPrecedenceGroup(
732+
DC, DC->getASTContext().Id_CastingPrecedence, SourceLoc());
733+
if (!asPG)
734+
return true;
735+
736+
return exprNeedsParensOutsideFollowingOperator(TC, DC, expr, rootExpr,
737+
asPG);
738+
}
739+
};
740+
742741
/// Diagnose failures related to passing value of some type
743742
/// to `inout` or pointer parameter, without explicitly specifying `&`.
744743
class MissingAddressOfFailure final : public ContextualFailure {

lib/Sema/CSFix.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,24 @@ void ConstraintFix::dump() const {print(llvm::errs()); }
4848

4949
std::string ForceDowncast::getName() const {
5050
llvm::SmallString<16> name;
51-
name += "force downcast (as! ";
52-
name += DowncastTo->getString();
51+
name += "force downcast (";
52+
name += getFromType()->getString();
53+
name += " as! ";
54+
name += getToType()->getString();
5355
name += ")";
5456
return name.c_str();
5557
}
5658

5759
bool ForceDowncast::diagnose(Expr *expr, bool asNote) const {
58-
MissingExplicitConversionFailure failure(expr, getConstraintSystem(),
59-
getLocator(), DowncastTo);
60+
auto &cs = getConstraintSystem();
61+
MissingExplicitConversionFailure failure(expr, cs, getFromType(), getToType(),
62+
getLocator());
6063
return failure.diagnose(asNote);
6164
}
6265

63-
ForceDowncast *ForceDowncast::create(ConstraintSystem &cs, Type toType,
64-
ConstraintLocator *locator) {
65-
return new (cs.getAllocator()) ForceDowncast(cs, toType, locator);
66+
ForceDowncast *ForceDowncast::create(ConstraintSystem &cs, Type fromType,
67+
Type toType, ConstraintLocator *locator) {
68+
return new (cs.getAllocator()) ForceDowncast(cs, fromType, toType, locator);
6669
}
6770

6871
bool ForceOptional::diagnose(Expr *root, bool asNote) const {

lib/Sema/CSFix.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -243,22 +243,6 @@ class ConstraintFix {
243243
ConstraintSystem &getConstraintSystem() const { return CS; }
244244
};
245245

246-
/// Append 'as! T' to force a downcast to the specified type.
247-
class ForceDowncast final : public ConstraintFix {
248-
Type DowncastTo;
249-
250-
ForceDowncast(ConstraintSystem &cs, Type toType, ConstraintLocator *locator)
251-
: ConstraintFix(cs, FixKind::ForceDowncast, locator), DowncastTo(toType) {
252-
}
253-
254-
public:
255-
std::string getName() const override;
256-
bool diagnose(Expr *root, bool asNote = false) const override;
257-
258-
static ForceDowncast *create(ConstraintSystem &cs, Type toType,
259-
ConstraintLocator *locator);
260-
};
261-
262246
/// Introduce a '!' to force an optional unwrap.
263247
class ForceOptional final : public ConstraintFix {
264248
Type BaseType;
@@ -510,6 +494,22 @@ class ContextualMismatch : public ConstraintFix {
510494
ConstraintLocator *locator);
511495
};
512496

497+
/// Append 'as! T' to force a downcast to the specified type.
498+
class ForceDowncast final : public ContextualMismatch {
499+
ForceDowncast(ConstraintSystem &cs, Type fromType, Type toType,
500+
ConstraintLocator *locator)
501+
: ContextualMismatch(cs, FixKind::ForceDowncast, fromType, toType,
502+
locator) {}
503+
504+
public:
505+
std::string getName() const override;
506+
507+
bool diagnose(Expr *root, bool asNote = false) const override;
508+
509+
static ForceDowncast *create(ConstraintSystem &cs, Type fromType, Type toType,
510+
ConstraintLocator *locator);
511+
};
512+
513513
/// Introduce a '&' to take the address of an lvalue.
514514
class AddAddressOf final : public ContextualMismatch {
515515
AddAddressOf(ConstraintSystem &cs, Type argTy, Type paramTy,

lib/Sema/CSSimplify.cpp

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,58 @@ static ConstraintFix *fixPropertyWrapperFailure(
21862186
return nullptr;
21872187
}
21882188

2189+
static bool canBridgeThroughCast(ConstraintSystem &cs, Type fromType,
2190+
Type toType) {
2191+
// If we have a value of type AnyObject that we're trying to convert to
2192+
// a class, force a downcast.
2193+
// FIXME: Also allow types bridged through Objective-C classes.
2194+
if (fromType->isAnyObject() && toType->getClassOrBoundGenericClass())
2195+
return true;
2196+
2197+
auto &TC = cs.getTypeChecker();
2198+
auto bridged = TC.getDynamicBridgedThroughObjCClass(cs.DC, fromType, toType);
2199+
if (!bridged)
2200+
return false;
2201+
2202+
// Note: don't perform this recovery for NSNumber;
2203+
if (auto classType = bridged->getAs<ClassType>()) {
2204+
SmallString<16> scratch;
2205+
if (classType->getDecl()->isObjC() &&
2206+
classType->getDecl()->getObjCRuntimeName(scratch) == "NSNumber")
2207+
return false;
2208+
}
2209+
2210+
return true;
2211+
}
2212+
2213+
static bool
2214+
repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
2215+
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2216+
ConstraintLocatorBuilder locator) {
2217+
auto objectType1 = fromType->getOptionalObjectType();
2218+
auto objectType2 = toType->getOptionalObjectType();
2219+
2220+
if (objectType1 && !objectType2) {
2221+
auto *anchor = locator.trySimplifyToExpr();
2222+
if (!anchor)
2223+
return false;
2224+
2225+
if (auto *overload = cs.findSelectedOverloadFor(anchor)) {
2226+
auto *decl = overload->Choice.getDeclOrNull();
2227+
if (decl &&
2228+
decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
2229+
fromType = objectType1;
2230+
}
2231+
}
2232+
2233+
if (!canBridgeThroughCast(cs, fromType, toType))
2234+
return false;
2235+
2236+
conversionsOrFixes.push_back(ForceDowncast::create(
2237+
cs, fromType, toType, cs.getConstraintLocator(locator)));
2238+
return true;
2239+
}
2240+
21892241
/// Attempt to repair typing failures and record fixes if needed.
21902242
/// \return true if at least some of the failures has been repaired
21912243
/// successfully, which allows type matcher to continue.
@@ -2301,6 +2353,9 @@ bool ConstraintSystem::repairFailures(
23012353

23022354
if (repairByAnyToAnyObjectCast(lhs, rhs))
23032355
return true;
2356+
2357+
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
2358+
return true;
23042359
}
23052360

23062361
return false;
@@ -2321,7 +2376,10 @@ bool ConstraintSystem::repairFailures(
23212376
case ConstraintLocator::ApplyArgToParam: {
23222377
auto loc = getConstraintLocator(locator);
23232378
if (repairByInsertingExplicitCall(lhs, rhs))
2324-
return true;
2379+
break;
2380+
2381+
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
2382+
break;
23252383

23262384
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
23272385
conversionsOrFixes.push_back(
@@ -2444,10 +2502,13 @@ bool ConstraintSystem::repairFailures(
24442502
}
24452503

24462504
if (repairByInsertingExplicitCall(lhs, rhs))
2447-
return true;
2505+
break;
24482506

24492507
if (repairByAnyToAnyObjectCast(lhs, rhs))
2450-
return true;
2508+
break;
2509+
2510+
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
2511+
break;
24512512

24522513
// If both types are key path, the only differences
24532514
// between them are mutability and/or root, value type mismatch.
@@ -3317,32 +3378,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
33173378
}
33183379
}
33193380

3320-
// If we have a value of type AnyObject that we're trying to convert to
3321-
// a class, force a downcast.
3322-
// FIXME: Also allow types bridged through Objective-C classes.
3323-
if (objectType1->isAnyObject() &&
3324-
type2->getClassOrBoundGenericClass()) {
3325-
conversionsOrFixes.push_back(
3326-
ForceDowncast::create(*this, type2, getConstraintLocator(locator)));
3327-
}
3328-
3329-
// If we could perform a bridging cast, try it.
3330-
if (auto bridged =
3331-
TC.getDynamicBridgedThroughObjCClass(DC, objectType1, type2)) {
3332-
// Note: don't perform this recovery for NSNumber;
3333-
bool useFix = true;
3334-
if (auto classType = bridged->getAs<ClassType>()) {
3335-
SmallString<16> scratch;
3336-
if (classType->getDecl()->isObjC() &&
3337-
classType->getDecl()->getObjCRuntimeName(scratch) == "NSNumber")
3338-
useFix = false;
3339-
}
3340-
3341-
if (useFix)
3342-
conversionsOrFixes.push_back(
3343-
ForceDowncast::create(*this, type2, getConstraintLocator(locator)));
3344-
}
3345-
33463381
if (!type1->is<LValueType>() && type2->is<InOutType>()) {
33473382
// If we have a concrete type that's an rvalue, "fix" it.
33483383
conversionsOrFixes.push_back(

test/Constraints/bridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ func rdar20029786(_ ns: NSString?) {
296296

297297
let s3: NSString? = "str" as String? // expected-error {{cannot convert value of type 'String?' to specified type 'NSString?'}}{{39-39= as NSString?}}
298298

299-
var s4: String = ns ?? "str" // expected-error{{cannot convert value of type 'NSString' to specified type 'String'}}{{31-31= as String}}
299+
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}}
300300
var s5: String = (ns ?? "str") as String // fixed version
301301
}
302302

test/expr/cast/array_iteration.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ for view in rootView.subviews as! [View] { // expected-warning{{immutable value
1616
doFoo()
1717
}
1818

19-
for view:View in rootView.subviews { // expected-error{{'AnyObject' is not convertible to 'View'}}
19+
for view:View in rootView.subviews { // expected-error{{cannot convert sequence element type 'AnyObject' to expected type 'View'}}
2020
doFoo()
2121
}
2222

test/expr/cast/dictionary_bridge.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ func testUpcastBridge() {
8080
dictOB = dictBB as [ObjC: BridgedToObjC]
8181

8282
dictBB = dictBO // expected-error{{cannot assign value of type '[BridgedToObjC : ObjC]' to type '[BridgedToObjC : BridgedToObjC]'}}
83+
// expected-note@-1 {{arguments to generic parameter 'Value' ('ObjC' and 'BridgedToObjC') are expected to be equal}}
8384
dictBB = dictOB // expected-error{{cannot assign value of type '[ObjC : BridgedToObjC]' to type '[BridgedToObjC : BridgedToObjC]'}}
85+
// expected-note@-1 {{arguments to generic parameter 'Key' ('ObjC' and 'BridgedToObjC') are expected to be equal}}
8486

8587
dictDO = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[DerivesObjC : ObjC]'}}
8688
//expected-note@-1 {{arguments to generic parameter 'Key' ('BridgedToObjC' and 'DerivesObjC') are expected to be equal}}

test/expr/cast/set_bridge.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func testUpcastBridge() {
5959

6060
// Upcast object to bridged type
6161
setB = setO // expected-error{{cannot assign value of type 'Set<ObjC>' to type 'Set<BridgedToObjC>'}}
62+
// expected-note@-1 {{arguments to generic parameter 'Element' ('ObjC' and 'BridgedToObjC') are expected to be equal}}
6263

6364
// Failed upcast
6465
setD = setB // expected-error{{cannot assign value of type 'Set<BridgedToObjC>' to type 'Set<DerivesObjC>'}}

0 commit comments

Comments
 (0)