@@ -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
@@ -3200,10 +3239,12 @@ namespace {
3200
3239
}
3201
3240
3202
3241
private:
3203
- // / A list of "suspicious" optional injections that come from
3204
- // / forced downcasts.
3242
+ // / A list of "suspicious" optional injections.
3205
3243
SmallVector<InjectIntoOptionalExpr *, 4 > SuspiciousOptionalInjections;
3206
3244
3245
+ // / A list of implicit coercions of noncopyable types.
3246
+ SmallVector<Expr *, 4 > ConsumingCoercions;
3247
+
3207
3248
// / Create a member reference to the given constructor.
3208
3249
Expr *applyCtorRefExpr (Expr *expr, Expr *base, SourceLoc dotLoc,
3209
3250
DeclNameLoc nameLoc, bool implicit,
@@ -4425,9 +4466,9 @@ namespace {
4425
4466
if (choice == 0 ) {
4426
4467
// Convert the subexpression.
4427
4468
Expr *sub = expr->getSubExpr ();
4428
-
4429
- sub = solution. coerceToType (sub, expr-> getCastType (),
4430
- cs. getConstraintLocator (sub) );
4469
+ auto subLoc =
4470
+ cs. getConstraintLocator (sub, ConstraintLocator::CoercionOperand);
4471
+ sub = solution. coerceToType (sub, expr-> getCastType (), subLoc );
4431
4472
if (!sub)
4432
4473
return nullptr ;
4433
4474
@@ -5475,41 +5516,69 @@ namespace {
5475
5516
assert (OpenedExistentials.empty ());
5476
5517
5477
5518
auto &ctx = cs.getASTContext ();
5519
+ auto *module = dc->getParentModule ();
5478
5520
5479
5521
// Look at all of the suspicious optional injections
5480
5522
for (auto injection : SuspiciousOptionalInjections) {
5481
- auto *cast = findForcedDowncast (ctx, injection->getSubExpr ());
5482
- if (!cast)
5483
- continue ;
5484
-
5485
- if (isa<ParenExpr>(injection->getSubExpr ()))
5486
- continue ;
5523
+ if (auto *cast = findForcedDowncast (ctx, injection->getSubExpr ())) {
5524
+ if (!isa<ParenExpr>(injection->getSubExpr ())) {
5525
+ ctx.Diags .diagnose (
5526
+ injection->getLoc (), diag::inject_forced_downcast,
5527
+ cs.getType (injection->getSubExpr ())->getRValueType ());
5528
+ auto exclaimLoc = cast->getExclaimLoc ();
5529
+ ctx.Diags
5530
+ .diagnose (exclaimLoc, diag::forced_to_conditional_downcast,
5531
+ cs.getType (injection)->getOptionalObjectType ())
5532
+ .fixItReplace (exclaimLoc, " ?" );
5533
+ ctx.Diags
5534
+ .diagnose (cast->getStartLoc (),
5535
+ diag::silence_inject_forced_downcast)
5536
+ .fixItInsert (cast->getStartLoc (), " (" )
5537
+ .fixItInsertAfter (cast->getEndLoc (), " )" );
5538
+ }
5539
+ }
5540
+ }
5487
5541
5488
- ctx. Diags . diagnose (
5489
- injection-> getLoc (), diag::inject_forced_downcast,
5490
- cs. getType (injection-> getSubExpr ())-> getRValueType ());
5491
- auto exclaimLoc = cast-> getExclaimLoc ( );
5542
+ // Diagnose the implicit coercions of noncopyable values that happen in
5543
+ // a context where it isn't "obviously" consuming already.
5544
+ for ( auto *coercion : ConsumingCoercions) {
5545
+ assert (coercion-> isImplicit () );
5492
5546
ctx.Diags
5493
- .diagnose (exclaimLoc, diag::forced_to_conditional_downcast ,
5494
- cs. getType (injection)-> getOptionalObjectType ())
5495
- . fixItReplace (exclaimLoc, " ? " );
5547
+ .diagnose (coercion-> getLoc () ,
5548
+ diag::consume_expression_needed_for_cast,
5549
+ cs. getType (coercion) );
5496
5550
ctx.Diags
5497
- .diagnose (cast-> getStartLoc (), diag::silence_inject_forced_downcast)
5498
- . fixItInsert (cast-> getStartLoc (), " ( " )
5499
- .fixItInsertAfter (cast-> getEndLoc (), " ) " );
5551
+ .diagnose (coercion-> getLoc (),
5552
+ diag::add_consume_to_silence )
5553
+ .fixItInsert (coercion-> getStartLoc (), " consume " );
5500
5554
}
5501
5555
}
5502
5556
5503
5557
// / Diagnose an optional injection that is probably not what the
5504
- // / user wanted, because it comes from a forced downcast.
5505
- void diagnoseOptionalInjection (InjectIntoOptionalExpr *injection) {
5558
+ // / user wanted, because it comes from a forced downcast, or from an
5559
+ // / implicitly consumed noncopyable type.
5560
+ void diagnoseOptionalInjection (InjectIntoOptionalExpr *injection,
5561
+ ConstraintLocatorBuilder locator) {
5506
5562
// Check whether we have a forced downcast.
5507
- auto *cast =
5508
- findForcedDowncast (cs.getASTContext (), injection->getSubExpr ());
5509
- if (!cast)
5510
- return ;
5511
-
5512
- SuspiciousOptionalInjections.push_back (injection);
5563
+ if (findForcedDowncast (cs.getASTContext (), injection->getSubExpr ()))
5564
+ SuspiciousOptionalInjections.push_back (injection);
5565
+
5566
+ // / Check if it needs an explicit consume, due to this being a cast.
5567
+ auto *module = dc->getParentModule ();
5568
+ auto origType = cs.getType (injection->getSubExpr ());
5569
+ if (willHaveConfusingConsumption (origType, locator, cs) &&
5570
+ canAddExplicitConsume (module , injection->getSubExpr ()))
5571
+ ConsumingCoercions.push_back (injection);
5572
+ }
5573
+
5574
+ void diagnoseExistentialErasureOf (Expr *fromExpr, Expr *toExpr,
5575
+ ConstraintLocatorBuilder locator) {
5576
+ auto *module = dc->getParentModule ();
5577
+ auto fromType = cs.getType (fromExpr);
5578
+ if (willHaveConfusingConsumption (fromType, locator, cs) &&
5579
+ canAddExplicitConsume (module , fromExpr)) {
5580
+ ConsumingCoercions.push_back (toExpr);
5581
+ }
5513
5582
}
5514
5583
};
5515
5584
} // end anonymous namespace
@@ -5780,7 +5849,7 @@ Expr *ExprRewriter::coerceOptionalToOptional(Expr *expr, Type toType,
5780
5849
while (diff--) {
5781
5850
Type type = toOptionals[diff];
5782
5851
expr = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, type));
5783
- diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr));
5852
+ diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr), locator );
5784
5853
}
5785
5854
5786
5855
return expr;
@@ -6909,8 +6978,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
6909
6978
return coerceSuperclass (expr, toType);
6910
6979
6911
6980
case ConversionRestrictionKind::Existential:
6912
- case ConversionRestrictionKind::MetatypeToExistentialMetatype:
6913
- return coerceExistential (expr, toType, locator);
6981
+ case ConversionRestrictionKind::MetatypeToExistentialMetatype: {
6982
+ auto coerced = coerceExistential (expr, toType, locator);
6983
+ diagnoseExistentialErasureOf (expr, coerced, locator);
6984
+ return coerced;
6985
+ }
6914
6986
6915
6987
case ConversionRestrictionKind::ClassMetatypeToAnyObject: {
6916
6988
assert (ctx.LangOpts .EnableObjCInterop &&
@@ -6939,7 +7011,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
6939
7011
6940
7012
auto *result =
6941
7013
cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
6942
- diagnoseOptionalInjection (result);
7014
+ diagnoseOptionalInjection (result, locator );
6943
7015
return result;
6944
7016
}
6945
7017
@@ -7633,7 +7705,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
7633
7705
if (!expr) return nullptr ;
7634
7706
7635
7707
auto *result = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
7636
- diagnoseOptionalInjection (result);
7708
+ diagnoseOptionalInjection (result, locator );
7637
7709
return result;
7638
7710
}
7639
7711
0 commit comments