@@ -355,6 +355,45 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
355
355
return true ;
356
356
}
357
357
358
+ // / Since a cast to an optional will consume a noncopyable type, check to see
359
+ // / if injecting the value into an optional here will potentially be confusing.
360
+ static bool willHaveConfusingConsumption (Type type,
361
+ ConstraintLocatorBuilder locator,
362
+ ConstraintSystem &cs) {
363
+ assert (type);
364
+ if (!type->isNoncopyable ())
365
+ return false ; // / If it's a copyable type, there's no confusion.
366
+
367
+ auto loc = cs.getConstraintLocator (locator);
368
+ if (!loc)
369
+ return true ;
370
+
371
+ auto path = loc->getPath ();
372
+ if (path.empty ())
373
+ return true ;
374
+
375
+ switch (loc->getPath ().back ().getKind ()) {
376
+ case ConstraintLocator::FunctionResult:
377
+ case ConstraintLocator::ClosureResult:
378
+ case ConstraintLocator::ClosureBody:
379
+ case ConstraintLocator::ContextualType:
380
+ case ConstraintLocator::CoercionOperand:
381
+ return false ; // These last-uses won't be confused for borrowing.
382
+
383
+ case ConstraintLocator::ApplyArgToParam: {
384
+ auto argLoc = loc->castLastElementTo <LocatorPathElt::ApplyArgToParam>();
385
+ auto paramFlags = argLoc.getParameterFlags ();
386
+ if (paramFlags.getOwnershipSpecifier () == ParamSpecifier::Consuming)
387
+ return false ; // Parameter already declares 'consuming'.
388
+
389
+ return true ;
390
+ }
391
+
392
+ default :
393
+ return true ;
394
+ }
395
+ }
396
+
358
397
namespace {
359
398
360
399
// / Rewrites an expression by applying the solution of a constraint
@@ -3241,10 +3280,12 @@ namespace {
3241
3280
}
3242
3281
3243
3282
private:
3244
- // / A list of "suspicious" optional injections that come from
3245
- // / forced downcasts.
3283
+ // / A list of "suspicious" optional injections.
3246
3284
SmallVector<InjectIntoOptionalExpr *, 4 > SuspiciousOptionalInjections;
3247
3285
3286
+ // / A list of implicit coercions of noncopyable types.
3287
+ SmallVector<Expr *, 4 > ConsumingCoercions;
3288
+
3248
3289
// / Create a member reference to the given constructor.
3249
3290
Expr *applyCtorRefExpr (Expr *expr, Expr *base, SourceLoc dotLoc,
3250
3291
DeclNameLoc nameLoc, bool implicit,
@@ -4466,9 +4507,9 @@ namespace {
4466
4507
if (choice == 0 ) {
4467
4508
// Convert the subexpression.
4468
4509
Expr *sub = expr->getSubExpr ();
4469
-
4470
- sub = solution. coerceToType (sub, expr-> getCastType (),
4471
- cs. getConstraintLocator (sub) );
4510
+ auto subLoc =
4511
+ cs. getConstraintLocator (sub, ConstraintLocator::CoercionOperand);
4512
+ sub = solution. coerceToType (sub, expr-> getCastType (), subLoc );
4472
4513
if (!sub)
4473
4514
return nullptr ;
4474
4515
@@ -5516,41 +5557,69 @@ namespace {
5516
5557
assert (OpenedExistentials.empty ());
5517
5558
5518
5559
auto &ctx = cs.getASTContext ();
5560
+ auto *module = dc->getParentModule ();
5519
5561
5520
5562
// Look at all of the suspicious optional injections
5521
5563
for (auto injection : SuspiciousOptionalInjections) {
5522
- auto *cast = findForcedDowncast (ctx, injection->getSubExpr ());
5523
- if (!cast)
5524
- continue ;
5525
-
5526
- if (isa<ParenExpr>(injection->getSubExpr ()))
5527
- continue ;
5564
+ if (auto *cast = findForcedDowncast (ctx, injection->getSubExpr ())) {
5565
+ if (!isa<ParenExpr>(injection->getSubExpr ())) {
5566
+ ctx.Diags .diagnose (
5567
+ injection->getLoc (), diag::inject_forced_downcast,
5568
+ cs.getType (injection->getSubExpr ())->getRValueType ());
5569
+ auto exclaimLoc = cast->getExclaimLoc ();
5570
+ ctx.Diags
5571
+ .diagnose (exclaimLoc, diag::forced_to_conditional_downcast,
5572
+ cs.getType (injection)->getOptionalObjectType ())
5573
+ .fixItReplace (exclaimLoc, " ?" );
5574
+ ctx.Diags
5575
+ .diagnose (cast->getStartLoc (),
5576
+ diag::silence_inject_forced_downcast)
5577
+ .fixItInsert (cast->getStartLoc (), " (" )
5578
+ .fixItInsertAfter (cast->getEndLoc (), " )" );
5579
+ }
5580
+ }
5581
+ }
5528
5582
5529
- ctx. Diags . diagnose (
5530
- injection-> getLoc (), diag::inject_forced_downcast,
5531
- cs. getType (injection-> getSubExpr ())-> getRValueType ());
5532
- auto exclaimLoc = cast-> getExclaimLoc ( );
5583
+ // Diagnose the implicit coercions of noncopyable values that happen in
5584
+ // a context where it isn't "obviously" consuming already.
5585
+ for ( auto *coercion : ConsumingCoercions) {
5586
+ assert (coercion-> isImplicit () );
5533
5587
ctx.Diags
5534
- .diagnose (exclaimLoc, diag::forced_to_conditional_downcast ,
5535
- cs. getType (injection)-> getOptionalObjectType ())
5536
- . fixItReplace (exclaimLoc, " ? " );
5588
+ .diagnose (coercion-> getLoc () ,
5589
+ diag::consume_expression_needed_for_cast,
5590
+ cs. getType (coercion) );
5537
5591
ctx.Diags
5538
- .diagnose (cast-> getStartLoc (), diag::silence_inject_forced_downcast)
5539
- . fixItInsert (cast-> getStartLoc (), " ( " )
5540
- .fixItInsertAfter (cast-> getEndLoc (), " ) " );
5592
+ .diagnose (coercion-> getLoc (),
5593
+ diag::add_consume_to_silence )
5594
+ .fixItInsert (coercion-> getStartLoc (), " consume " );
5541
5595
}
5542
5596
}
5543
5597
5544
5598
// / Diagnose an optional injection that is probably not what the
5545
- // / user wanted, because it comes from a forced downcast.
5546
- void diagnoseOptionalInjection (InjectIntoOptionalExpr *injection) {
5599
+ // / user wanted, because it comes from a forced downcast, or from an
5600
+ // / implicitly consumed noncopyable type.
5601
+ void diagnoseOptionalInjection (InjectIntoOptionalExpr *injection,
5602
+ ConstraintLocatorBuilder locator) {
5547
5603
// Check whether we have a forced downcast.
5548
- auto *cast =
5549
- findForcedDowncast (cs.getASTContext (), injection->getSubExpr ());
5550
- if (!cast)
5551
- return ;
5552
-
5553
- SuspiciousOptionalInjections.push_back (injection);
5604
+ if (findForcedDowncast (cs.getASTContext (), injection->getSubExpr ()))
5605
+ SuspiciousOptionalInjections.push_back (injection);
5606
+
5607
+ // / Check if it needs an explicit consume, due to this being a cast.
5608
+ auto *module = dc->getParentModule ();
5609
+ auto origType = cs.getType (injection->getSubExpr ());
5610
+ if (willHaveConfusingConsumption (origType, locator, cs) &&
5611
+ canAddExplicitConsume (module , injection->getSubExpr ()))
5612
+ ConsumingCoercions.push_back (injection);
5613
+ }
5614
+
5615
+ void diagnoseExistentialErasureOf (Expr *fromExpr, Expr *toExpr,
5616
+ ConstraintLocatorBuilder locator) {
5617
+ auto *module = dc->getParentModule ();
5618
+ auto fromType = cs.getType (fromExpr);
5619
+ if (willHaveConfusingConsumption (fromType, locator, cs) &&
5620
+ canAddExplicitConsume (module , fromExpr)) {
5621
+ ConsumingCoercions.push_back (toExpr);
5622
+ }
5554
5623
}
5555
5624
};
5556
5625
} // end anonymous namespace
@@ -5821,7 +5890,7 @@ Expr *ExprRewriter::coerceOptionalToOptional(Expr *expr, Type toType,
5821
5890
while (diff--) {
5822
5891
Type type = toOptionals[diff];
5823
5892
expr = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, type));
5824
- diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr));
5893
+ diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr), locator );
5825
5894
}
5826
5895
5827
5896
return expr;
@@ -6950,8 +7019,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
6950
7019
return coerceSuperclass (expr, toType);
6951
7020
6952
7021
case ConversionRestrictionKind::Existential:
6953
- case ConversionRestrictionKind::MetatypeToExistentialMetatype:
6954
- return coerceExistential (expr, toType, locator);
7022
+ case ConversionRestrictionKind::MetatypeToExistentialMetatype: {
7023
+ auto coerced = coerceExistential (expr, toType, locator);
7024
+ diagnoseExistentialErasureOf (expr, coerced, locator);
7025
+ return coerced;
7026
+ }
6955
7027
6956
7028
case ConversionRestrictionKind::ClassMetatypeToAnyObject: {
6957
7029
assert (ctx.LangOpts .EnableObjCInterop &&
@@ -6980,7 +7052,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
6980
7052
6981
7053
auto *result =
6982
7054
cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
6983
- diagnoseOptionalInjection (result);
7055
+ diagnoseOptionalInjection (result, locator );
6984
7056
return result;
6985
7057
}
6986
7058
@@ -7674,7 +7746,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
7674
7746
if (!expr) return nullptr ;
7675
7747
7676
7748
auto *result = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
7677
- diagnoseOptionalInjection (result);
7749
+ diagnoseOptionalInjection (result, locator );
7678
7750
return result;
7679
7751
}
7680
7752
0 commit comments