@@ -355,6 +355,45 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
355355 return true ;
356356}
357357
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+
358397namespace {
359398
360399 // / Rewrites an expression by applying the solution of a constraint
@@ -3200,10 +3239,12 @@ namespace {
32003239 }
32013240
32023241 private:
3203- // / A list of "suspicious" optional injections that come from
3204- // / forced downcasts.
3242+ // / A list of "suspicious" optional injections.
32053243 SmallVector<InjectIntoOptionalExpr *, 4 > SuspiciousOptionalInjections;
32063244
3245+ // / A list of implicit coercions of noncopyable types.
3246+ SmallVector<Expr *, 4 > ConsumingCoercions;
3247+
32073248 // / Create a member reference to the given constructor.
32083249 Expr *applyCtorRefExpr (Expr *expr, Expr *base, SourceLoc dotLoc,
32093250 DeclNameLoc nameLoc, bool implicit,
@@ -4425,9 +4466,9 @@ namespace {
44254466 if (choice == 0 ) {
44264467 // Convert the subexpression.
44274468 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 );
44314472 if (!sub)
44324473 return nullptr ;
44334474
@@ -5475,41 +5516,69 @@ namespace {
54755516 assert (OpenedExistentials.empty ());
54765517
54775518 auto &ctx = cs.getASTContext ();
5519+ auto *module = dc->getParentModule ();
54785520
54795521 // Look at all of the suspicious optional injections
54805522 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+ }
54875541
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 () );
54925546 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) );
54965550 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 " );
55005554 }
55015555 }
55025556
55035557 // / 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) {
55065562 // 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+ }
55135582 }
55145583 };
55155584} // end anonymous namespace
@@ -5780,7 +5849,7 @@ Expr *ExprRewriter::coerceOptionalToOptional(Expr *expr, Type toType,
57805849 while (diff--) {
57815850 Type type = toOptionals[diff];
57825851 expr = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, type));
5783- diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr));
5852+ diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr), locator );
57845853 }
57855854
57865855 return expr;
@@ -6909,8 +6978,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69096978 return coerceSuperclass (expr, toType);
69106979
69116980 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+ }
69146986
69156987 case ConversionRestrictionKind::ClassMetatypeToAnyObject: {
69166988 assert (ctx.LangOpts .EnableObjCInterop &&
@@ -6939,7 +7011,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69397011
69407012 auto *result =
69417013 cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
6942- diagnoseOptionalInjection (result);
7014+ diagnoseOptionalInjection (result, locator );
69437015 return result;
69447016 }
69457017
@@ -7633,7 +7705,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
76337705 if (!expr) return nullptr ;
76347706
76357707 auto *result = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
7636- diagnoseOptionalInjection (result);
7708+ diagnoseOptionalInjection (result, locator );
76377709 return result;
76387710 }
76397711
0 commit comments