Skip to content

Commit a34fe9a

Browse files
committed
[Diagnostics] Extend missing & diagnostic to cover pointer conversions
Example: ```swift func foo(_: UnsafePointer<Int>) {} var x: Int = 0 foo(x) <- should suggest adding `&` ```
1 parent 1533a84 commit a34fe9a

File tree

6 files changed

+64
-53
lines changed

6 files changed

+64
-53
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,17 +2266,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
22662266
return true;
22672267
}
22682268
}
2269-
} else if (contextDecl == CS.TC.Context.getUnsafePointerDecl() ||
2270-
contextDecl == CS.TC.Context.getUnsafeMutablePointerDecl() ||
2271-
contextDecl == CS.TC.Context.getUnsafeRawPointerDecl() ||
2272-
contextDecl == CS.TC.Context.getUnsafeMutableRawPointerDecl()) {
2273-
for (Type arg : genericType->getGenericArgs()) {
2274-
if (arg->isEqual(exprType) && CS.getType(expr)->hasLValueType()) {
2275-
diagnose(expr->getLoc(), diagID, exprType, contextualType).
2276-
fixItInsert(expr->getStartLoc(), "&");
2277-
return true;
2278-
}
2279-
}
22802269
}
22812270
}
22822271

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -886,9 +886,17 @@ bool MissingAddressOfFailure::diagnoseAsError() {
886886
return false;
887887

888888
auto *anchor = getAnchor();
889-
auto type = getType(anchor)->getRValueType();
890-
emitDiagnostic(anchor->getLoc(), diag::missing_address_of, type)
891-
.fixItInsert(anchor->getStartLoc(), "&");
889+
auto argTy = getFromType();
890+
auto paramTy = getToType();
891+
892+
if (paramTy->getAnyPointerElementType()) {
893+
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value, argTy,
894+
paramTy)
895+
.fixItInsert(anchor->getStartLoc(), "&");
896+
} else {
897+
emitDiagnostic(anchor->getLoc(), diag::missing_address_of, argTy)
898+
.fixItInsert(anchor->getStartLoc(), "&");
899+
}
892900
return true;
893901
}
894902

lib/Sema/CSDiagnostics.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -544,17 +544,6 @@ class MissingForcedDowncastFailure final : public FailureDiagnostic {
544544
bool diagnoseAsError() override;
545545
};
546546

547-
/// Diagnose failures related to passing value of some type
548-
/// to `inout` parameter, without explicitly specifying `&`.
549-
class MissingAddressOfFailure final : public FailureDiagnostic {
550-
public:
551-
MissingAddressOfFailure(Expr *expr, ConstraintSystem &cs,
552-
ConstraintLocator *locator)
553-
: FailureDiagnostic(expr, cs, locator) {}
554-
555-
bool diagnoseAsError() override;
556-
};
557-
558547
/// Diagnose failures related attempt to implicitly convert types which
559548
/// do not support such implicit converstion.
560549
/// "as" or "as!" has to be specified explicitly in cases like that.
@@ -750,6 +739,17 @@ class ContextualFailure : public FailureDiagnostic {
750739
void tryComputedPropertyFixIts(Expr *expr) const;
751740
};
752741

742+
/// Diagnose failures related to passing value of some type
743+
/// to `inout` or pointer parameter, without explicitly specifying `&`.
744+
class MissingAddressOfFailure final : public ContextualFailure {
745+
public:
746+
MissingAddressOfFailure(Expr *expr, ConstraintSystem &cs, Type argTy,
747+
Type paramTy, ConstraintLocator *locator)
748+
: ContextualFailure(expr, cs, argTy, paramTy, locator) {}
749+
750+
bool diagnoseAsError() override;
751+
};
752+
753753
/// Diagnose mismatches relating to tuple destructuring.
754754
class TupleContextualFailure final : public ContextualFailure {
755755
public:

lib/Sema/CSFix.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ UnwrapOptionalBase *UnwrapOptionalBase::createWithOptionalResult(
100100
}
101101

102102
bool AddAddressOf::diagnose(Expr *root, bool asNote) const {
103-
MissingAddressOfFailure failure(root, getConstraintSystem(), getLocator());
103+
auto &cs = getConstraintSystem();
104+
MissingAddressOfFailure failure(root, cs, getFromType(), getToType(),
105+
getLocator());
104106
return failure.diagnose(asNote);
105107
}
106108

107-
AddAddressOf *AddAddressOf::create(ConstraintSystem &cs,
108-
ConstraintLocator *locator) {
109-
return new (cs.getAllocator()) AddAddressOf(cs, locator);
109+
AddAddressOf *AddAddressOf::create(ConstraintSystem &cs, Type argTy,
110+
Type paramTy, ConstraintLocator *locator) {
111+
return new (cs.getAllocator()) AddAddressOf(cs, argTy, paramTy, locator);
110112
}
111113

112114
bool TreatRValueAsLValue::diagnose(Expr *root, bool asNote) const {

lib/Sema/CSFix.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -307,19 +307,6 @@ class UnwrapOptionalBase final : public ConstraintFix {
307307
ConstraintLocator *locator);
308308
};
309309

310-
/// Introduce a '&' to take the address of an lvalue.
311-
class AddAddressOf final : public ConstraintFix {
312-
AddAddressOf(ConstraintSystem &cs, ConstraintLocator *locator)
313-
: ConstraintFix(cs, FixKind::AddressOf, locator) {}
314-
315-
public:
316-
std::string getName() const override { return "add address-of"; }
317-
318-
bool diagnose(Expr *root, bool asNote = false) const override;
319-
320-
static AddAddressOf *create(ConstraintSystem &cs, ConstraintLocator *locator);
321-
};
322-
323310
// Treat rvalue as if it was an lvalue
324311
class TreatRValueAsLValue final : public ConstraintFix {
325312
TreatRValueAsLValue(ConstraintSystem &cs, ConstraintLocator *locator)
@@ -523,6 +510,21 @@ class ContextualMismatch : public ConstraintFix {
523510
ConstraintLocator *locator);
524511
};
525512

513+
/// Introduce a '&' to take the address of an lvalue.
514+
class AddAddressOf final : public ContextualMismatch {
515+
AddAddressOf(ConstraintSystem &cs, Type argTy, Type paramTy,
516+
ConstraintLocator *locator)
517+
: ContextualMismatch(cs, FixKind::AddressOf, argTy, paramTy, locator) {}
518+
519+
public:
520+
std::string getName() const override { return "add address-of"; }
521+
522+
bool diagnose(Expr *root, bool asNote = false) const override;
523+
524+
static AddAddressOf *create(ConstraintSystem &cs, Type argTy, Type paramTy,
525+
ConstraintLocator *locator);
526+
};
527+
526528
/// Detect situations where two type's generic arguments must
527529
/// match but are not convertible e.g.
528530
///

lib/Sema/CSSimplify.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,20 @@ bool ConstraintSystem::repairFailures(
23482348
rhs)) {
23492349
conversionsOrFixes.push_back(fix);
23502350
}
2351+
2352+
// If argument in l-value type and parameter is `inout` or a pointer,
2353+
// let's see if it's generic parameter matches and suggest adding explicit
2354+
// `&`.
2355+
if (lhs->is<LValueType>() &&
2356+
(rhs->is<InOutType>() || rhs->getAnyPointerElementType())) {
2357+
auto result = matchTypes(InOutType::get(lhs->getRValueType()), rhs,
2358+
ConstraintKind::ArgumentConversion,
2359+
TypeMatchFlags::TMF_ApplyingFix, locator);
2360+
2361+
if (result.isSuccess())
2362+
conversionsOrFixes.push_back(AddAddressOf::create(
2363+
*this, lhs, rhs, getConstraintLocator(locator)));
2364+
}
23512365
break;
23522366
}
23532367

@@ -2924,8 +2938,10 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
29242938
// T1 is convertible to T2 (by loading the value). Note that we cannot get
29252939
// a value of inout type as an lvalue though.
29262940
if (type1->is<LValueType>() && !type2->is<InOutType>()) {
2927-
return matchTypes(type1->getWithoutSpecifierType(), type2,
2928-
kind, subflags, locator);
2941+
auto result = matchTypes(type1->getWithoutSpecifierType(), type2, kind,
2942+
subflags, locator);
2943+
if (result.isSuccess() || !shouldAttemptFixes())
2944+
return result;
29292945
}
29302946
}
29312947

@@ -3315,16 +3331,10 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
33153331
ForceDowncast::create(*this, type2, getConstraintLocator(locator)));
33163332
}
33173333

3318-
if (type2->is<InOutType>()) {
3319-
if (type1->is<LValueType>()) {
3320-
// If we're converting an lvalue to an inout type, add the missing '&'.
3321-
conversionsOrFixes.push_back(
3322-
AddAddressOf::create(*this, getConstraintLocator(locator)));
3323-
} else {
3324-
// If we have a concrete type that's an rvalue, "fix" it.
3325-
conversionsOrFixes.push_back(
3334+
if (!type1->is<LValueType>() && type2->is<InOutType>()) {
3335+
// If we have a concrete type that's an rvalue, "fix" it.
3336+
conversionsOrFixes.push_back(
33263337
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
3327-
}
33283338
}
33293339
}
33303340

0 commit comments

Comments
 (0)