Skip to content

Commit e76f5f1

Browse files
committed
[Diagnostics] Improve the diagnostic for invalid pointer conversion for an autoclosure result type.
Add constraint fix `AllowAutoClosurePointerConversion` and corresponding diagnostic `AutoClosurePointerConversionFailure`. When we discover that we're trying to do an inout-to-pointer conversion in `matchTypes`, add the constraint fix, which tries to do the conversion as if the pointer type is a regular function argument.
1 parent 2cfcdf4 commit e76f5f1

File tree

7 files changed

+96
-10
lines changed

7 files changed

+96
-10
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,10 @@ ERROR(c_function_pointer_from_generic_function,none,
11331133
"function", ())
11341134
ERROR(invalid_autoclosure_forwarding,none,
11351135
"add () to forward @autoclosure parameter", ())
1136+
ERROR(invalid_autoclosure_pointer_conversion,none,
1137+
"cannot perform pointer conversion of value of type %0 to autoclosure "
1138+
"result type %1",
1139+
(Type, Type))
11361140

11371141
//------------------------------------------------------------------------------
11381142
// MARK: Type Check Declarations

lib/Sema/CSDiagnostics.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,14 @@ bool AutoClosureForwardingFailure::diagnoseAsError() {
19781978
return true;
19791979
}
19801980

1981+
bool AutoClosurePointerConversionFailure::diagnoseAsError() {
1982+
auto *anchor = getAnchor();
1983+
auto diagnostic = diag::invalid_autoclosure_pointer_conversion;
1984+
emitDiagnostic(anchor->getLoc(), diagnostic, PointeeType, PointerType)
1985+
.highlight(anchor->getSourceRange());
1986+
return true;
1987+
}
1988+
19811989
bool NonOptionalUnwrapFailure::diagnoseAsError() {
19821990
auto *anchor = getAnchor();
19831991

lib/Sema/CSDiagnostics.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,28 @@ class AutoClosureForwardingFailure final : public FailureDiagnostic {
777777
bool diagnoseAsError() override;
778778
};
779779

780+
/// Diagnose invalid pointer conversions for an autoclosure result type.
781+
///
782+
/// \code
783+
/// func foo(_ x: @autoclosure () -> UnsafePointer<Int>) {}
784+
///
785+
/// var i = 0
786+
/// foo(&i) // Invalid conversion to UnsafePointer
787+
/// \endcode
788+
class AutoClosurePointerConversionFailure final : public FailureDiagnostic {
789+
Type PointeeType;
790+
Type PointerType;
791+
792+
public:
793+
AutoClosurePointerConversionFailure(Expr *root, ConstraintSystem &cs,
794+
Type pointeeType, Type pointerType,
795+
ConstraintLocator *locator)
796+
: FailureDiagnostic(root, cs, locator), PointeeType(pointeeType),
797+
PointerType(pointerType) {}
798+
799+
bool diagnoseAsError() override;
800+
};
801+
780802
/// Diagnose situations when there was an attempt to unwrap entity
781803
/// of non-optional type e.g.
782804
///

lib/Sema/CSFix.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,20 @@ AutoClosureForwarding *AutoClosureForwarding::create(ConstraintSystem &cs,
269269
return new (cs.getAllocator()) AutoClosureForwarding(cs, locator);
270270
}
271271

272+
bool AllowAutoClosurePointerConversion::diagnose(Expr *root, bool asNote) const {
273+
auto failure = AutoClosurePointerConversionFailure(root, getConstraintSystem(),
274+
PointeeType, PointerType, getLocator());
275+
return failure.diagnose(asNote);
276+
}
277+
278+
AllowAutoClosurePointerConversion *
279+
AllowAutoClosurePointerConversion::create(ConstraintSystem &cs, Type pointeeType,
280+
Type pointerType,
281+
ConstraintLocator *locator) {
282+
return new (cs.getAllocator())
283+
AllowAutoClosurePointerConversion(cs, pointeeType, pointerType, locator);
284+
}
285+
272286
bool RemoveUnwrap::diagnose(Expr *root, bool asNote) const {
273287
auto failure = NonOptionalUnwrapFailure(root, getConstraintSystem(), BaseType,
274288
getLocator());

lib/Sema/CSFix.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ enum class FixKind : uint8_t {
9898
/// Swift version 5.
9999
AutoClosureForwarding,
100100

101+
/// Allow invalid pointer conversions for autoclosure result types as if the
102+
/// pointer type is a function parameter rather than an autoclosure result.
103+
AllowAutoClosurePointerConversion,
104+
101105
/// Remove `!` or `?` because base is not an optional type.
102106
RemoveUnwrap,
103107

@@ -621,6 +625,28 @@ class AutoClosureForwarding final : public ConstraintFix {
621625
ConstraintLocator *locator);
622626
};
623627

628+
class AllowAutoClosurePointerConversion final : public ConstraintFix {
629+
Type PointeeType;
630+
Type PointerType;
631+
632+
AllowAutoClosurePointerConversion(ConstraintSystem &cs, Type pointeeType,
633+
Type pointerType, ConstraintLocator *locator)
634+
: ConstraintFix(cs, FixKind::AllowAutoClosurePointerConversion, locator),
635+
PointeeType(pointeeType), PointerType(pointerType) {}
636+
637+
public:
638+
std::string getName() const override {
639+
return "allow pointer conversion for autoclosure result type";
640+
}
641+
642+
bool diagnose(Expr *root, bool asNote = false) const override;
643+
644+
static AllowAutoClosurePointerConversion *create(ConstraintSystem &cs,
645+
Type pointeeType,
646+
Type pointerType,
647+
ConstraintLocator *locator);
648+
};
649+
624650
class RemoveUnwrap final : public ConstraintFix {
625651
Type BaseType;
626652

lib/Sema/CSSimplify.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3055,8 +3055,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
30553055
case PTK_UnsafeMutablePointer:
30563056
// UnsafeMutablePointer can be converted from an inout reference to a
30573057
// scalar or array.
3058-
if (!isAutoClosureArgument) {
3059-
if (auto inoutType1 = dyn_cast<InOutType>(desugar1)) {
3058+
if (auto inoutType1 = dyn_cast<InOutType>(desugar1)) {
3059+
if (!isAutoClosureArgument) {
30603060
auto inoutBaseType = inoutType1->getInOutObjectType();
30613061

30623062
Type simplifiedInoutBaseType = getFixedTypeRecursive(
@@ -3071,6 +3071,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
30713071
}
30723072
conversionsOrFixes.push_back(
30733073
ConversionRestrictionKind::InoutToPointer);
3074+
} else {
3075+
Type pointeeType = inoutType1->getObjectType();
3076+
auto *fix = AllowAutoClosurePointerConversion::create(*this,
3077+
pointeeType, type2, getConstraintLocator(locator));
3078+
conversionsOrFixes.push_back(fix);
30743079
}
30753080
}
30763081

@@ -6966,6 +6971,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
69666971
return matchTupleTypes(matchingType, smaller, matchKind, subflags, locator);
69676972
}
69686973

6974+
case FixKind::AllowAutoClosurePointerConversion: {
6975+
if (recordFix(fix))
6976+
return SolutionKind::Error;
6977+
return matchTypes(type1, type2, matchKind, subflags,
6978+
locator.withPathElement(ConstraintLocator::FunctionArgument));
6979+
}
6980+
69696981
case FixKind::InsertCall:
69706982
case FixKind::RemoveReturn:
69716983
case FixKind::AddConformance:

test/Constraints/invalid_implicit_conversions.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ func test(
1515
var a: [Int] = [0]
1616
let s = "string"
1717

18-
takesAutoclosure(rawPtr, &i) // expected-error {{'&' used with non-inout argument of type 'Int'}}
19-
takesAutoclosure(mutRawPtr, &i) // expected-error {{'&' used with non-inout argument of type 'Int'}}
20-
takesAutoclosure(mutPtr, &i) // expected-error {{'&' used with non-inout argument of type 'Int'}}
21-
takesAutoclosure(ptr, &i) // expected-error {{'&' used with non-inout argument of type 'Int'}}
22-
takesAutoclosure(rawPtr, &a) // expected-error {{'&' used with non-inout argument of type '[Int]'}}
23-
takesAutoclosure(mutRawPtr, &a) // expected-error {{'&' used with non-inout argument of type '[Int]'}}
24-
takesAutoclosure(mutPtr, &a) // expected-error {{'&' used with non-inout argument of type '[Int]'}}
25-
takesAutoclosure(ptr, &a) // expected-error {{'&' used with non-inout argument of type '[Int]'}}
18+
takesAutoclosure(rawPtr, &i) // expected-error {{cannot perform pointer conversion of value of type 'Int' to autoclosure result type 'UnsafeRawPointer'}}
19+
takesAutoclosure(mutRawPtr, &i) // expected-error {{cannot perform pointer conversion of value of type 'Int' to autoclosure result type 'UnsafeMutableRawPointer'}}
20+
takesAutoclosure(mutPtr, &i) // expected-error {{cannot perform pointer conversion of value of type 'Int' to autoclosure result type 'UnsafeMutablePointer<Int>'}}
21+
takesAutoclosure(ptr, &i) // expected-error {{cannot perform pointer conversion of value of type 'Int' to autoclosure result type 'UnsafePointer<Int>'}}
22+
takesAutoclosure(rawPtr, &a) // expected-error {{cannot perform pointer conversion of value of type '[Int]' to autoclosure result type 'UnsafeRawPointer'}}
23+
takesAutoclosure(mutRawPtr, &a) // expected-error {{cannot perform pointer conversion of value of type '[Int]' to autoclosure result type 'UnsafeMutableRawPointer'}}
24+
takesAutoclosure(mutPtr, &a) // expected-error {{cannot perform pointer conversion of value of type '[Int]' to autoclosure result type 'UnsafeMutablePointer<Int>'}}
25+
takesAutoclosure(ptr, &a) // expected-error {{cannot perform pointer conversion of value of type '[Int]' to autoclosure result type 'UnsafePointer<Int>'}}
2626

2727
takesAutoclosure(rawPtr, a) // expected-error {{cannot invoke 'takesAutoclosure' with an argument list of type '(UnsafeRawPointer, [Int])'}}
2828
// expected-note@-1 {{expected an argument list of type '(T, @autoclosure () throws -> T)'}}

0 commit comments

Comments
 (0)