Skip to content

Commit caeb2a4

Browse files
authored
Merge pull request #26470 from hborla/autoclosure-pointer-conversion-diagnostic
[Diagnostics] Improve the diagnostic for invalid pointer conversion for an autoclosure result type.
2 parents dc6f9e2 + edcf405 commit caeb2a4

File tree

7 files changed

+89
-10
lines changed

7 files changed

+89
-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, getFromType(), getToType())
1985+
.highlight(anchor->getSourceRange());
1986+
return true;
1987+
}
1988+
19811989
bool NonOptionalUnwrapFailure::diagnoseAsError() {
19821990
auto *anchor = getAnchor();
19831991

lib/Sema/CSDiagnostics.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,24 @@ 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 ContextualFailure {
789+
public:
790+
AutoClosurePointerConversionFailure(Expr *root, ConstraintSystem &cs,
791+
Type pointeeType, Type pointerType,
792+
ConstraintLocator *locator)
793+
: ContextualFailure(root, cs, pointeeType, pointerType, locator) {}
794+
795+
bool diagnoseAsError() override;
796+
};
797+
780798
/// Diagnose situations when there was an attempt to unwrap entity
781799
/// of non-optional type e.g.
782800
///

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+
getFromType(), getToType(), 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: 23 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,25 @@ class AutoClosureForwarding final : public ConstraintFix {
621625
ConstraintLocator *locator);
622626
};
623627

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

lib/Sema/CSSimplify.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3087,8 +3087,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
30873087
case PTK_UnsafeMutablePointer:
30883088
// UnsafeMutablePointer can be converted from an inout reference to a
30893089
// scalar or array.
3090-
if (!isAutoClosureArgument) {
3091-
if (auto inoutType1 = dyn_cast<InOutType>(desugar1)) {
3090+
if (auto inoutType1 = dyn_cast<InOutType>(desugar1)) {
3091+
if (!isAutoClosureArgument) {
30923092
auto inoutBaseType = inoutType1->getInOutObjectType();
30933093

30943094
Type simplifiedInoutBaseType = getFixedTypeRecursive(
@@ -3103,6 +3103,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
31033103
}
31043104
conversionsOrFixes.push_back(
31053105
ConversionRestrictionKind::InoutToPointer);
3106+
} else {
3107+
Type pointeeType = inoutType1->getObjectType();
3108+
auto *fix = AllowAutoClosurePointerConversion::create(*this,
3109+
pointeeType, type2, getConstraintLocator(locator));
3110+
conversionsOrFixes.push_back(fix);
31063111
}
31073112
}
31083113

@@ -6998,6 +7003,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
69987003
return matchTupleTypes(matchingType, smaller, matchKind, subflags, locator);
69997004
}
70007005

7006+
case FixKind::AllowAutoClosurePointerConversion: {
7007+
if (recordFix(fix))
7008+
return SolutionKind::Error;
7009+
return matchTypes(type1, type2, matchKind, subflags,
7010+
locator.withPathElement(ConstraintLocator::FunctionArgument));
7011+
}
7012+
70017013
case FixKind::InsertCall:
70027014
case FixKind::RemoveReturn:
70037015
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)