Skip to content

Commit 6324314

Browse files
authored
[FixCode] Help users construct mutable pointer from a pointer by inserting 'mutating'. rdar://27500578 (#3971)
1 parent b5f90af commit 6324314

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ ERROR(cannot_call_with_params, none,
204204
"cannot invoke %select{|initializer for type }2'%0' with an argument list"
205205
" of type '%1'", (StringRef, StringRef, bool))
206206

207+
NOTE(pointer_init_add_mutating,none,
208+
"do you want to add 'mutating'", ())
207209
ERROR(expected_do_in_statement,none,
208210
"expected 'do' keyword to designate a block of statements", ())
209211

lib/Sema/CSDiag.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4913,6 +4913,25 @@ bool FailureDiagnosis::diagnoseNilLiteralComparison(
49134913
return true;
49144914
}
49154915

4916+
static bool shouldAddMutating(ASTContext &Ctx, const Expr *Fn,
4917+
const Expr* Arg) {
4918+
auto *TypeExp = dyn_cast<TypeExpr>(Fn);
4919+
auto *ParenExp = dyn_cast<ParenExpr>(Arg);
4920+
if (!TypeExp || !ParenExp)
4921+
return false;
4922+
auto InitType = TypeExp->getInstanceType();
4923+
auto ArgType = ParenExp->getSubExpr()->getType();
4924+
if (InitType.isNull() || ArgType.isNull())
4925+
return false;
4926+
if (auto *InitNom = InitType->getAnyNominal()) {
4927+
if (auto *ArgNom = ArgType->getAnyNominal()) {
4928+
return InitNom == Ctx.getUnsafeMutablePointerDecl() &&
4929+
ArgNom == Ctx.getUnsafePointerDecl();
4930+
}
4931+
}
4932+
return false;
4933+
}
4934+
49164935
bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
49174936
// Type check the function subexpression to resolve a type for it if possible.
49184937
auto fnExpr = typeCheckChildIndependently(callExpr->getFn());
@@ -5227,6 +5246,12 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
52275246
diagnose(fnExpr->getLoc(), diag::cannot_call_with_params,
52285247
overloadName, argString, isInitializer);
52295248
}
5249+
5250+
5251+
if (shouldAddMutating(CS->DC->getASTContext(), fnExpr, argExpr)) {
5252+
diagnose(fnExpr->getLoc(), diag::pointer_init_add_mutating).fixItInsert(
5253+
dyn_cast<ParenExpr>(argExpr)->getSubExpr()->getStartLoc(), "mutating: ");
5254+
}
52305255

52315256
// Did the user intend on invoking a different overload?
52325257
calleeInfo.suggestPotentialOverloads(fnExpr->getLoc());

test/Sema/diag_init.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
func foo(a : UnsafePointer<Void>)->UnsafeMutablePointer<Void> {
4+
return UnsafeMutablePointer(a) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<_>' with an argument list of type '(UnsafePointer<Void>)'}} // expected-note {{do you want to add 'mutating'}}{{31-31=mutating: }} // expected-note {{overloads for 'UnsafeMutablePointer<_>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
5+
}

0 commit comments

Comments
 (0)