Skip to content

Commit 7bf344e

Browse files
committed
[TypeResolver] Enable 'some' elision for opaque result types.
1 parent 61fa686 commit 7bf344e

File tree

3 files changed

+45
-76
lines changed

3 files changed

+45
-76
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,9 +727,11 @@ validateTypedPattern(TypedPattern *TP, DeclContext *dc,
727727
// property definition.
728728
auto &Context = dc->getASTContext();
729729
auto *Repr = TP->getTypeRepr();
730-
if (Repr && Repr->hasOpaque()) {
730+
if (Repr && (Repr->hasOpaque() ||
731+
(Context.LangOpts.hasFeature(Feature::ImplicitSome) &&
732+
Repr->isProtocol(dc)))) {
731733
auto named = dyn_cast<NamedPattern>(
732-
TP->getSubPattern()->getSemanticsProvidingPattern());
734+
TP->getSubPattern()->getSemanticsProvidingPattern());
733735
if (!named) {
734736
Context.Diags.diagnose(TP->getLoc(),
735737
diag::opaque_type_unsupported_pattern);

lib/Sema/TypeCheckType.cpp

Lines changed: 33 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,8 @@ namespace {
20452045
return diags.diagnose(std::forward<ArgTypes>(Args)...);
20462046
}
20472047

2048+
Type diagnoseDisallowedExistential(TypeRepr *repr, Type type);
2049+
20482050
NeverNullType resolveOpenedExistentialArchetype(
20492051
TypeAttributes &attrs, TypeRepr *repr,
20502052
TypeResolutionOptions options);
@@ -2201,6 +2203,23 @@ Type ResolveTypeRequest::evaluate(Evaluator &evaluator,
22012203
return result;
22022204
}
22032205

2206+
Type TypeResolver::diagnoseDisallowedExistential(TypeRepr *repr, Type type) {
2207+
auto options = resolution.getOptions();
2208+
if (!(options & TypeResolutionFlags::SilenceErrors) &&
2209+
options.contains(TypeResolutionFlags::DisallowOpaqueTypes)) {
2210+
// We're specifically looking at an existential type `any P<some Q>`,
2211+
// so emit a tailored diagnostic. We don't emit an ErrorType here
2212+
// for better recovery.
2213+
diagnose(repr->getLoc(),
2214+
diag::unsupported_opaque_type_in_existential);
2215+
// FIXME: We shouldn't have to invalid the type repr here, but not
2216+
// doing so causes a double-diagnostic.
2217+
repr->setInvalid();
2218+
}
2219+
2220+
return type;
2221+
}
2222+
22042223
NeverNullType TypeResolver::resolveType(TypeRepr *repr,
22052224
TypeResolutionOptions options) {
22062225
assert(repr && "Cannot validate null TypeReprs!");
@@ -2245,45 +2264,6 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
22452264
case TypeReprKind::SimpleIdent:
22462265
case TypeReprKind::GenericIdent:
22472266
case TypeReprKind::CompoundIdent: {
2248-
auto *DC = getDeclContext();
2249-
auto diagnoseDisallowedExistential = [&](Type ty) {
2250-
if (!(options & TypeResolutionFlags::SilenceErrors) &&
2251-
options.contains(TypeResolutionFlags::DisallowOpaqueTypes)) {
2252-
// We're specifically looking at an existential type `any P<some Q>`,
2253-
// so emit a tailored diagnostic. We don't emit an ErrorType here
2254-
// for better recovery.
2255-
diagnose(repr->getLoc(),
2256-
diag::unsupported_opaque_type_in_existential);
2257-
// FIXME: We shouldn't have to invalid the type repr here, but not
2258-
// doing so causes a double-diagnostic.
2259-
repr->setInvalid();
2260-
}
2261-
return ty;
2262-
};
2263-
2264-
if(getASTContext().LangOpts.hasFeature(Feature::ImplicitSome)){
2265-
if (auto opaqueDecl = dyn_cast<OpaqueTypeDecl>(DC)) {
2266-
if (auto ordinal = opaqueDecl->getAnonymousOpaqueParamOrdinal(repr))
2267-
return diagnoseDisallowedExistential(getIdentityOpaqueTypeArchetypeType(opaqueDecl, *ordinal));
2268-
}
2269-
2270-
// Check whether any of the generic parameters in the context represents
2271-
// this opaque type. If so, return that generic parameter.
2272-
if (options.isConstraintImplicitExistential()) {
2273-
if (auto declDC = DC->getAsDecl()) {
2274-
if (auto genericContext = declDC->getAsGenericContext()) {
2275-
if (auto genericParams = genericContext->getGenericParams()) {
2276-
for (auto genericParam : *genericParams) {
2277-
if (genericParam->getOpaqueTypeRepr() == repr)
2278-
return diagnoseDisallowedExistential(
2279-
genericParam->getDeclaredInterfaceType());
2280-
}
2281-
}
2282-
}
2283-
}
2284-
}
2285-
}
2286-
22872267
return resolveIdentifierType(cast<IdentTypeRepr>(repr), options);
22882268
}
22892269

@@ -2326,25 +2306,10 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
23262306

23272307
case TypeReprKind::Composition: {
23282308
auto *DC = getDeclContext();
2329-
auto diagnoseDisallowedExistential = [&](Type ty) {
2330-
if (!(options & TypeResolutionFlags::SilenceErrors) &&
2331-
options.contains(TypeResolutionFlags::DisallowOpaqueTypes)) {
2332-
// We're specifically looking at an existential type `any P<some Q>`,
2333-
// so emit a tailored diagnostic. We don't emit an ErrorType here
2334-
// for better recovery.
2335-
diagnose(repr->getLoc(),
2336-
diag::unsupported_opaque_type_in_existential);
2337-
// FIXME: We shouldn't have to invalid the type repr here, but not
2338-
// doing so causes a double-diagnostic.
2339-
repr->setInvalid();
2340-
}
2341-
return ty;
2342-
};
2343-
2344-
if(getASTContext().LangOpts.hasFeature(Feature::ImplicitSome)) {
2309+
if (getASTContext().LangOpts.hasFeature(Feature::ImplicitSome)) {
23452310
if (auto opaqueDecl = dyn_cast<OpaqueTypeDecl>(DC)) {
23462311
if (auto ordinal = opaqueDecl->getAnonymousOpaqueParamOrdinal(repr))
2347-
return diagnoseDisallowedExistential(
2312+
return diagnoseDisallowedExistential(repr,
23482313
getIdentityOpaqueTypeArchetypeType(opaqueDecl, *ordinal));
23492314
}
23502315
}
@@ -2364,25 +2329,10 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
23642329
// This decl is implicit in the source and is created in such contexts by
23652330
// evaluation of an `OpaqueResultTypeRequest`.
23662331
auto opaqueRepr = cast<OpaqueReturnTypeRepr>(repr);
2367-
auto diagnoseDisallowedExistential = [&](Type ty) {
2368-
if (!(options & TypeResolutionFlags::SilenceErrors) &&
2369-
options.contains(TypeResolutionFlags::DisallowOpaqueTypes)) {
2370-
// We're specifically looking at an existential type `any P<some Q>`,
2371-
// so emit a tailored diagnostic. We don't emit an ErrorType here
2372-
// for better recovery.
2373-
diagnose(opaqueRepr->getOpaqueLoc(),
2374-
diag::unsupported_opaque_type_in_existential);
2375-
// FIXME: We shouldn't have to invalid the type repr here, but not
2376-
// doing so causes a double-diagnostic.
2377-
opaqueRepr->setInvalid();
2378-
}
2379-
return ty;
2380-
};
2381-
23822332
auto *DC = getDeclContext();
23832333
if (auto opaqueDecl = dyn_cast<OpaqueTypeDecl>(DC)) {
23842334
if (auto ordinal = opaqueDecl->getAnonymousOpaqueParamOrdinal(opaqueRepr))
2385-
return diagnoseDisallowedExistential(
2335+
return diagnoseDisallowedExistential(opaqueRepr,
23862336
getIdentityOpaqueTypeArchetypeType(opaqueDecl, *ordinal));
23872337
}
23882338

@@ -2393,7 +2343,7 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
23932343
if (auto genericParams = genericContext->getGenericParams()) {
23942344
for (auto genericParam : *genericParams) {
23952345
if (genericParam->getOpaqueTypeRepr() == opaqueRepr)
2396-
return diagnoseDisallowedExistential(
2346+
return diagnoseDisallowedExistential(opaqueRepr,
23972347
genericParam->getDeclaredInterfaceType());
23982348
}
23992349
}
@@ -3898,7 +3848,16 @@ TypeResolver::resolveIdentifierType(IdentTypeRepr *IdType,
38983848
auto *dc = getDeclContext();
38993849
auto &ctx = getASTContext();
39003850

3901-
if (ctx.LangOpts.hasFeature(Feature::ImplicitSome) && options.isConstraintImplicitExistential()) {
3851+
if (ctx.LangOpts.hasFeature(Feature::ImplicitSome) &&
3852+
options.isConstraintImplicitExistential()) {
3853+
// Check whether this type is an implicit opaque result type.
3854+
if (auto *opaqueDecl = dyn_cast<OpaqueTypeDecl>(getDeclContext())) {
3855+
if (auto ordinal = opaqueDecl->getAnonymousOpaqueParamOrdinal(IdType)) {
3856+
return diagnoseDisallowedExistential(IdType,
3857+
getIdentityOpaqueTypeArchetypeType(opaqueDecl, *ordinal));
3858+
}
3859+
}
3860+
39023861
// Check whether any of the generic parameters in the context represents
39033862
// this opaque type. If so, return that generic parameter.
39043863
if (auto declDC = dc->getAsDecl()) {

test/type/implicit_some/opaque_return.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,11 @@ func eat(_ myfruit: inout Basket) -> Basket {
103103
return myfruit
104104
}
105105

106+
protocol P {
107+
associatedtype A: P
108+
var value: A { get }
109+
}
110+
111+
struct S: P {
112+
var value: P { self }
113+
}

0 commit comments

Comments
 (0)