Skip to content

Commit ec2b841

Browse files
[Sema] Do not early exit before attempt to classify conformances if there are any
1 parent be20c7a commit ec2b841

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

Diff for: lib/Sema/TypeCheckEffects.cpp

+10-6
Original file line numberDiff line numberDiff line change
@@ -752,25 +752,29 @@ class ApplyClassifier {
752752

753753
if (auto *SAE = dyn_cast<SelfApplyExpr>(E)) {
754754
assert(!E->isImplicitlyAsync());
755-
return Classification();
756755
}
757756

758757
auto type = E->getFn()->getType();
759758
if (!type) return Classification::forInvalidCode();
760759
auto fnType = type->getAs<AnyFunctionType>();
761760
if (!fnType) return Classification::forInvalidCode();
762761

763-
// If the function doesn't have any effects, we're done here.
762+
auto fnRef = AbstractFunction::getAppliedFn(E);
763+
auto conformances = fnRef.getSubstitutions().getConformances();
764+
const auto hasAnyConformances = !conformances.empty();
765+
766+
// If the function doesn't have any effects or conformances, we're done
767+
// here.
764768
if (!fnType->isThrowing() &&
765769
!E->implicitlyThrows() &&
766770
!fnType->isAsync() &&
767-
!E->isImplicitlyAsync()) {
771+
!E->isImplicitlyAsync() &&
772+
!hasAnyConformances) {
768773
return Classification();
769774
}
770775

771776
// Decompose the application.
772777
auto *args = E->getArgs();
773-
auto fnRef = AbstractFunction::getAppliedFn(E);
774778

775779
// If any of the arguments didn't type check, fail.
776780
for (auto arg : *args) {
@@ -2964,6 +2968,6 @@ void TypeChecker::checkPropertyWrapperEffects(
29642968

29652969
bool TypeChecker::canThrow(Expr *expr) {
29662970
ApplyClassifier classifier;
2967-
return (classifier.classifyExpr(expr, EffectKind::Throws) ==
2968-
ConditionalEffectKind::Always);
2971+
auto effect = classifier.classifyExpr(expr, EffectKind::Throws);
2972+
return (effect != ConditionalEffectKind::None);
29692973
}

Diff for: test/Concurrency/sr15049.swift

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,43 @@
11
// RUN: %target-typecheck-verify-swift -disable-availability-checking -strict-concurrency=targeted
22
// REQUIRES: concurrency
33

4-
// FIXME: Those cases should compile, but currently ApplyClassifier doesn't handle throws/no-throws properly.
5-
64
func testAsyncSequenceTypedPatternSendable<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int, Seq: Sendable {
7-
async let result: Int = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
5+
async let result: Int = seq.reduce(0) { $0 + $1 } // OK
86
// expected-warning@-1{{immutable value 'result' was never used; consider replacing with '_' or removing it}}
97
}
108

119
func testAsyncSequenceTypedPattern1Sendable<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int, Seq: Sendable {
12-
async let _: Int = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
10+
async let _: Int = seq.reduce(0) { $0 + $1 } // OK
1311
}
1412

1513
func testAsyncSequenceSendable<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int, Seq: Sendable {
16-
async let result = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
14+
async let result = seq.reduce(0) { $0 + $1 } // OK
1715
// expected-warning@-1{{initialization of immutable value 'result' was never used; consider replacing with assignment to '_' or removing it}}
1816
}
1917

2018
func testAsyncSequence1Sendable<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int, Seq: Sendable {
21-
async let _ = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
19+
async let _ = seq.reduce(0) { $0 + $1 } // OK
2220
}
2321

2422
func testAsyncSequenceTypedPattern<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{54-54=, Sendable}}
25-
async let result: Int = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
23+
async let result: Int = seq.reduce(0) { $0 + $1 } // OK
2624
// expected-warning@-1{{immutable value 'result' was never used; consider replacing with '_' or removing it}}
2725
// expected-warning@-2{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
2826
}
2927

3028
func testAsyncSequenceTypedPattern1<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{55-55=, Sendable}}
31-
async let _: Int = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
29+
async let _: Int = seq.reduce(0) { $0 + $1 } // OK
3230
// expected-warning@-1{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
3331
}
3432

3533
func testAsyncSequence<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{42-42=, Sendable}}
36-
async let result = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
34+
async let result = seq.reduce(0) { $0 + $1 } // OK
3735
// expected-warning@-1{{initialization of immutable value 'result' was never used; consider replacing with assignment to '_' or removing it}}
3836
// expected-warning@-2{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
3937
}
4038

4139
func testAsyncSequence1<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{43-43=, Sendable}}
42-
async let _ = seq.reduce(0) { $0 + $1 } // expected-error{{call can throw, but it is executed in a non-throwing autoclosure}} expected-note{{call is to 'rethrows' function, but a conformance has a throwing witness}}
40+
async let _ = seq.reduce(0) { $0 + $1 } // OK
4341
// expected-warning@-1{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
4442
}
4543

@@ -56,3 +54,11 @@ func search(query: String, entities: [String]) async throws -> [String] {
5654
async let r = entities.filter { $0.contains(query) }.map { String($0) }
5755
return await r // OK
5856
}
57+
58+
// https://github.com/apple/swift/issues/60351
59+
func foo() async {
60+
let stream = AsyncStream<Int>{ _ in }
61+
async let bar = stream.first { _ in true}
62+
63+
_ = await bar // OK
64+
}

0 commit comments

Comments
 (0)