@@ -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
@@ -3241,10 +3280,12 @@ namespace {
32413280 }
32423281
32433282 private:
3244- // / A list of "suspicious" optional injections that come from
3245- // / forced downcasts.
3283+ // / A list of "suspicious" optional injections.
32463284 SmallVector<InjectIntoOptionalExpr *, 4 > SuspiciousOptionalInjections;
32473285
3286+ // / A list of implicit coercions of noncopyable types.
3287+ SmallVector<Expr *, 4 > ConsumingCoercions;
3288+
32483289 // / Create a member reference to the given constructor.
32493290 Expr *applyCtorRefExpr (Expr *expr, Expr *base, SourceLoc dotLoc,
32503291 DeclNameLoc nameLoc, bool implicit,
@@ -4466,9 +4507,9 @@ namespace {
44664507 if (choice == 0 ) {
44674508 // Convert the subexpression.
44684509 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 );
44724513 if (!sub)
44734514 return nullptr ;
44744515
@@ -5516,41 +5557,69 @@ namespace {
55165557 assert (OpenedExistentials.empty ());
55175558
55185559 auto &ctx = cs.getASTContext ();
5560+ auto *module = dc->getParentModule ();
55195561
55205562 // Look at all of the suspicious optional injections
55215563 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+ }
55285582
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 () );
55335587 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) );
55375591 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 " );
55415595 }
55425596 }
55435597
55445598 // / 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) {
55475603 // 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+ }
55545623 }
55555624 };
55565625} // end anonymous namespace
@@ -5821,7 +5890,7 @@ Expr *ExprRewriter::coerceOptionalToOptional(Expr *expr, Type toType,
58215890 while (diff--) {
58225891 Type type = toOptionals[diff];
58235892 expr = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, type));
5824- diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr));
5893+ diagnoseOptionalInjection (cast<InjectIntoOptionalExpr>(expr), locator );
58255894 }
58265895
58275896 return expr;
@@ -6950,8 +7019,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69507019 return coerceSuperclass (expr, toType);
69517020
69527021 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+ }
69557027
69567028 case ConversionRestrictionKind::ClassMetatypeToAnyObject: {
69577029 assert (ctx.LangOpts .EnableObjCInterop &&
@@ -6980,7 +7052,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69807052
69817053 auto *result =
69827054 cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
6983- diagnoseOptionalInjection (result);
7055+ diagnoseOptionalInjection (result, locator );
69847056 return result;
69857057 }
69867058
@@ -7674,7 +7746,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
76747746 if (!expr) return nullptr ;
76757747
76767748 auto *result = cs.cacheType (new (ctx) InjectIntoOptionalExpr (expr, toType));
7677- diagnoseOptionalInjection (result);
7749+ diagnoseOptionalInjection (result, locator );
76787750 return result;
76797751 }
76807752
0 commit comments