Skip to content

Commit 6462b0d

Browse files
committed
[MiscDiagnostics] Fix a crash in OpaqueUnderlyingTypeChecker
Since opaque result type can reference generic parameters of context, it cannot reply purely on "index" of the opaque generic parameter while diagnosing a problem, it needs to perform a type substitution using a substitution map of a particular candidate to determine the underlying type. Resolves: rdar://90456579
1 parent 2392de1 commit 6462b0d

File tree

2 files changed

+30
-13
lines changed

2 files changed

+30
-13
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2646,15 +2646,19 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26462646
// TODO [OPAQUE SUPPORT]: diagnose multiple opaque types
26472647
SubstitutionMap underlyingSubs = Candidates.front().second;
26482648
if (Candidates.size() > 1) {
2649-
unsigned mismatchIndex = OpaqueDecl->getOpaqueGenericParams().size();
2650-
for (auto genericParam : OpaqueDecl->getOpaqueGenericParams()) {
2651-
unsigned index = genericParam->getIndex();
2652-
Type underlyingType = Candidates[0].second.getReplacementTypes()[index];
2649+
Optional<std::pair<unsigned, GenericTypeParamType *>> mismatch;
2650+
2651+
auto opaqueParams = OpaqueDecl->getOpaqueGenericParams();
2652+
for (auto index : indices(opaqueParams)) {
2653+
auto *genericParam = opaqueParams[index];
2654+
2655+
Type underlyingType = Type(genericParam).subst(underlyingSubs);
26532656
bool found = false;
26542657
for (const auto &candidate : Candidates) {
2655-
Type otherType = candidate.second.getReplacementTypes()[index];
2658+
Type otherType = Type(genericParam).subst(candidate.second);
2659+
26562660
if (!underlyingType->isEqual(otherType)) {
2657-
mismatchIndex = index;
2661+
mismatch.emplace(index, genericParam);
26582662
found = true;
26592663
break;
26602664
}
@@ -2663,28 +2667,27 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26632667
if (found)
26642668
break;
26652669
}
2666-
assert(mismatchIndex < OpaqueDecl->getOpaqueGenericParams().size());
2670+
assert(mismatch.hasValue());
26672671

26682672
if (auto genericParam =
2669-
OpaqueDecl->getExplicitGenericParam(mismatchIndex)) {
2673+
OpaqueDecl->getExplicitGenericParam(mismatch->first)) {
26702674
Implementation->diagnose(
26712675
diag::opaque_type_mismatched_underlying_type_candidates_named,
26722676
genericParam->getName())
26732677
.highlight(genericParam->getLoc());
26742678
} else {
26752679
TypeRepr *opaqueRepr =
2676-
OpaqueDecl->getOpaqueReturnTypeReprs()[mismatchIndex];
2680+
OpaqueDecl->getOpaqueReturnTypeReprs()[mismatch->first];
26772681
Implementation->diagnose(
26782682
diag::opaque_type_mismatched_underlying_type_candidates,
26792683
opaqueRepr)
26802684
.highlight(opaqueRepr->getSourceRange());
26812685
}
26822686

26832687
for (auto candidate : Candidates) {
2684-
Ctx.Diags.diagnose(
2685-
candidate.first->getLoc(),
2686-
diag::opaque_type_underlying_type_candidate_here,
2687-
candidate.second.getReplacementTypes()[mismatchIndex]);
2688+
Ctx.Diags.diagnose(candidate.first->getLoc(),
2689+
diag::opaque_type_underlying_type_candidate_here,
2690+
Type(mismatch->second).subst(candidate.second));
26882691
}
26892692
return;
26902693
}

test/type/opaque.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,17 @@ func takesOpaqueProtocol<T : OpaqueProtocol>(generic: T) {
519519

520520
func opaquePlaceholderFunc() -> some _ { 1 } // expected-error {{type placeholder not allowed here}}
521521
var opaquePlaceholderVar: some _ = 1 // expected-error {{type placeholder not allowed here}}
522+
523+
// rdar://90456579 - crash in `OpaqueUnderlyingTypeChecker`
524+
func test_diagnostic_with_contextual_generic_params() {
525+
struct S {
526+
func test<T: Q>(t: T) -> some Q {
527+
// expected-error@-1 {{function declares an opaque return type 'some Q', but the return statements in its body do not have matching underlying types}}
528+
if true {
529+
return t // expected-note {{return statement has underlying type 'T'}}
530+
}
531+
return "" // String conforms to `Q`
532+
// expected-note@-1 {{return statement has underlying type 'String'}}
533+
}
534+
}
535+
}

0 commit comments

Comments
 (0)