Skip to content

Commit b26c599

Browse files
committed
Sema: Fix handling of getter typed throws in associated type inference
We must replace type parameters with archetypes in the thrown error type of the witness. The requirement type remains an interface type.
1 parent de3cf4d commit b26c599

File tree

2 files changed

+95
-29
lines changed

2 files changed

+95
-29
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,27 +1908,16 @@ static Type getWithoutProtocolTypeAliases(Type type) {
19081908
///
19091909
/// Also see simplifyCurrentTypeWitnesses().
19101910
static Type getWitnessTypeForMatching(NormalProtocolConformance *conformance,
1911-
ValueDecl *witness) {
1912-
if (witness->isRecursiveValidation()) {
1913-
LLVM_DEBUG(llvm::dbgs() << "Recursive validation\n";);
1914-
return Type();
1915-
}
1916-
1917-
if (witness->isInvalid()) {
1918-
LLVM_DEBUG(llvm::dbgs() << "Invalid witness\n";);
1919-
return Type();
1920-
}
1921-
1911+
ValueDecl *witness, Type type) {
19221912
if (!witness->getDeclContext()->isTypeContext()) {
19231913
// FIXME: Could we infer from 'Self' to make these work?
1924-
return witness->getInterfaceType();
1914+
return type;
19251915
}
19261916

19271917
// Retrieve the set of substitutions to be applied to the witness.
19281918
Type model =
19291919
conformance->getDeclContext()->mapTypeIntoContext(conformance->getType());
19301920
TypeSubstitutionMap substitutions = model->getMemberSubstitutions(witness);
1931-
Type type = witness->getInterfaceType()->getReferenceStorageReferent();
19321921

19331922
type = getWithoutProtocolTypeAliases(type);
19341923

@@ -2082,14 +2071,20 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType(
20822071
!witnessHasImplementsAttrForRequiredName(typeDecl, assocType))
20832072
continue;
20842073

2085-
// Determine the witness type.
2086-
Type witnessType = getWitnessTypeForMatching(conformance, typeDecl);
2087-
if (!witnessType) continue;
2074+
if (typeDecl->isInvalid()) {
2075+
LLVM_DEBUG(llvm::dbgs() << "Recursive validation\n";);
2076+
continue;
2077+
}
20882078

2089-
if (auto witnessMetaType = witnessType->getAs<AnyMetatypeType>())
2090-
witnessType = witnessMetaType->getInstanceType();
2091-
else
2079+
if (typeDecl->isRecursiveValidation()) {
2080+
LLVM_DEBUG(llvm::dbgs() << "Recursive validation\n";);
20922081
continue;
2082+
}
2083+
2084+
// Determine the witness type.
2085+
Type witnessType = getWitnessTypeForMatching(conformance, typeDecl,
2086+
typeDecl->getDeclaredInterfaceType());
2087+
if (!witnessType) continue;
20932088

20942089
if (result.empty()) {
20952090
// If we found at least one default candidate, we must allow for the
@@ -2177,18 +2172,29 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
21772172
InferredAssociatedTypesByWitness inferred;
21782173
inferred.Witness = witness;
21792174

2180-
// Compute the requirement and witness types we'll use for matching.
2181-
Type fullWitnessType = getWitnessTypeForMatching(conformance, witness);
2182-
if (!fullWitnessType) {
2175+
auto reqType = removeSelfParam(req, req->getInterfaceType());
2176+
Type witnessType;
2177+
2178+
if (witness->isRecursiveValidation()) {
2179+
LLVM_DEBUG(llvm::dbgs() << "Recursive validation\n";);
21832180
return inferred;
21842181
}
21852182

2186-
LLVM_DEBUG(llvm::dbgs() << "Witness type for matching is "
2187-
<< fullWitnessType << "\n";);
2183+
if (witness->isInvalid()) {
2184+
LLVM_DEBUG(llvm::dbgs() << "Invalid witness\n";);
2185+
return inferred;
2186+
}
21882187

21892188
auto setup =
21902189
[&]() -> std::tuple<std::optional<RequirementMatch>, Type, Type, Type, Type> {
2191-
fullWitnessType = removeSelfParam(witness, fullWitnessType);
2190+
// Compute the requirement and witness types we'll use for matching.
2191+
witnessType = witness->getInterfaceType()->getReferenceStorageReferent();
2192+
witnessType = getWitnessTypeForMatching(conformance, witness, witnessType);
2193+
2194+
LLVM_DEBUG(llvm::dbgs() << "Witness type for matching is "
2195+
<< witnessType << "\n";);
2196+
2197+
witnessType = removeSelfParam(witness, witnessType);
21922198

21932199
Type reqThrownError;
21942200
Type witnessThrownError;
@@ -2211,12 +2217,15 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
22112217
};
22122218

22132219
reqThrownError = getThrownErrorType(reqASD);
2220+
22142221
witnessThrownError = getThrownErrorType(witnessASD);
2222+
witnessThrownError = getWitnessTypeForMatching(conformance, witness,
2223+
witnessThrownError);
22152224
}
22162225

22172226
return std::make_tuple(std::nullopt,
2218-
removeSelfParam(req, req->getInterfaceType()),
2219-
fullWitnessType, reqThrownError, witnessThrownError);
2227+
reqType, witnessType,
2228+
reqThrownError, witnessThrownError);
22202229
};
22212230

22222231
/// Visits a requirement type to match it to a potential witness for
@@ -2352,7 +2361,7 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
23522361
Type witnessType) -> std::optional<RequirementMatch> {
23532362
if (!matchVisitor.match(reqType, witnessType)) {
23542363
return RequirementMatch(witness, MatchKind::TypeConflict,
2355-
fullWitnessType);
2364+
witnessType);
23562365
}
23572366

23582367
return std::nullopt;
@@ -2365,7 +2374,7 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
23652374
return RequirementMatch(witness,
23662375
anyRenaming ? MatchKind::RenamedMatch
23672376
: MatchKind::ExactMatch,
2368-
fullWitnessType);
2377+
witnessType);
23692378

23702379
};
23712380

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P {
4+
associatedtype E: Error
5+
var prop: Int { get throws(E) } // expected-note {{protocol requires property 'prop' with type 'Int'}}
6+
}
7+
8+
struct S0: P {
9+
var prop: Int {
10+
get {}
11+
}
12+
}
13+
14+
struct S1: P {
15+
var prop: Int {
16+
get throws(Never) {}
17+
}
18+
}
19+
20+
struct S2: P {
21+
var prop: Int {
22+
get throws {}
23+
}
24+
}
25+
26+
struct S3: P {
27+
var prop: Int {
28+
get throws(any Error) {}
29+
}
30+
}
31+
32+
struct MyError: Error {}
33+
34+
struct S4: P {
35+
var prop: Int {
36+
get throws(MyError) {}
37+
}
38+
}
39+
40+
struct S5<E: Error>: P {
41+
var prop: Int {
42+
get throws(E) {}
43+
}
44+
}
45+
46+
// Invalid example
47+
48+
struct S6: P { // expected-error {{type 'S6' does not conform to protocol 'P'}}
49+
// expected-note@-1 {{add stubs for conformance}}
50+
51+
typealias E = MyError
52+
var prop: Int { // expected-note {{candidate has non-matching type 'Int'}}
53+
get throws(any Error) {
54+
fatalError()
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)