Skip to content

Commit af78807

Browse files
committed
Sema: Generalize @_opaqueReturnTypeOf syntax to correctly handle parameter packs
We now allow the dummy identifier to be a qualified reference, so that we can reconstruct generic parameter lists from multiple levels: @_opaqueReturnTypeOf(...) __.<OuterArgs...>.__<InnerArgs...> This fixes an ambiguity with parameter packs, where flattening the packs from multiple levels of nested types no longer produced an unambiguous result. To maintain backward compatibility, we still accept the old "flat" form when no parameter packs are present.
1 parent bd3b3ea commit af78807

File tree

2 files changed

+91
-21
lines changed

2 files changed

+91
-21
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4018,25 +4018,12 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
40184018
return elements;
40194019
}
40204020

4021+
/// Implement the special @_opaqueReturnTypeOf attribute syntax in
4022+
/// module interface files.
40214023
NeverNullType
40224024
TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName,
40234025
unsigned ordinal,
40244026
TypeResolutionOptions options) {
4025-
// The type representation should be an unqualified identifier. We don't
4026-
// really use the identifier for anything, but we do resolve any generic
4027-
// arguments to instantiate the possibly-generic opaque type.
4028-
SmallVector<Type, 4> TypeArgsBuf;
4029-
if (auto *unqualIdentRepr = dyn_cast<UnqualifiedIdentTypeRepr>(repr)) {
4030-
for (auto argRepr : unqualIdentRepr->getGenericArgs()) {
4031-
auto argTy = resolveType(argRepr, options);
4032-
// If we cannot resolve the generic parameter, propagate the error out.
4033-
if (argTy->hasError()) {
4034-
return ErrorType::get(getASTContext());
4035-
}
4036-
TypeArgsBuf.push_back(argTy);
4037-
}
4038-
}
4039-
40404027
// Use type reconstruction to summon the opaque type decl.
40414028
Demangler demangle;
40424029
auto definingDeclNode = demangle.demangleSymbol(mangledName);
@@ -4050,14 +4037,98 @@ TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName,
40504037
auto opaqueNode =
40514038
builder.getNodeFactory().createNode(Node::Kind::OpaqueReturnTypeOf);
40524039
opaqueNode->addChild(definingDeclNode, builder.getNodeFactory());
4053-
4054-
auto TypeArgs = ArrayRef<Type>(TypeArgsBuf);
4055-
auto ty = builder.resolveOpaqueType(opaqueNode, TypeArgs, ordinal);
4056-
if (!ty || ty->hasError()) {
4040+
auto *opaqueDecl = builder.resolveOpaqueTypeDecl(opaqueNode);
4041+
4042+
auto *ownerDecl = opaqueDecl->getNamingDecl();
4043+
if (!ownerDecl) {
40574044
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
40584045
return ErrorType::get(getASTContext());
40594046
}
4060-
return ty;
4047+
4048+
auto genericSig = ownerDecl->getInnermostDeclContext()
4049+
->getGenericSignatureOfContext();
4050+
4051+
SubstitutionMap subs;
4052+
if (genericSig) {
4053+
SmallVector<Type, 2> args;
4054+
4055+
// The type representation should either be a single identifier, or a
4056+
// series of member references. We don't use the identifiers for
4057+
// anything, but we do resolve the generic arguments at each level
4058+
// to instantiate the possibly-generic opaque type.
4059+
if (isa<UnqualifiedIdentTypeRepr>(repr) &&
4060+
!genericSig->hasParameterPack()) {
4061+
// When there are no parameter packs and we just have a single
4062+
// unqualified identifier, we fall back to the legacy behavior,
4063+
// which collects the generic arguments for all levels of nesting
4064+
// in a flat list.
4065+
//
4066+
// This matches the old behavior of the ASTPrinter.
4067+
auto *unqualIdentRepr = cast<UnqualifiedIdentTypeRepr>(repr);
4068+
4069+
for (auto argRepr : unqualIdentRepr->getGenericArgs()) {
4070+
auto argTy = resolveType(argRepr, options);
4071+
// If we cannot resolve the generic parameter, propagate the error out.
4072+
if (argTy->hasError()) {
4073+
return ErrorType::get(getASTContext());
4074+
}
4075+
args.push_back(argTy);
4076+
}
4077+
4078+
if (args.size() != genericSig.getGenericParams().size()) {
4079+
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
4080+
return ErrorType::get(getASTContext());
4081+
}
4082+
} else {
4083+
// Correct handling of nested types. We interpret a qualified
4084+
// TypeRepr with a generic argument list at each level, like
4085+
// __<OuterArgs, ...>.__<InnerArgs, ...>.
4086+
SmallVector<SmallVector<Type, 2>, 2> nestedArgs;
4087+
4088+
auto *dc = ownerDecl->getInnermostDeclContext();
4089+
while (!dc->isModuleScopeContext()) {
4090+
if (dc->isInnermostContextGeneric()) {
4091+
if (repr == nullptr || !isa<DeclRefTypeRepr>(repr)) {
4092+
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
4093+
return ErrorType::get(getASTContext());
4094+
}
4095+
4096+
auto *identRepr = cast<DeclRefTypeRepr>(repr);
4097+
nestedArgs.emplace_back();
4098+
4099+
auto *decl = dyn_cast<ValueDecl>(dc->getAsDecl());
4100+
if (decl == nullptr)
4101+
decl = dc->getSelfNominalTypeDecl();
4102+
ASSERT(decl);
4103+
4104+
resolveGenericArguments(decl,
4105+
decl->getAsGenericContext(),
4106+
resolution,
4107+
silContext,
4108+
identRepr,
4109+
nestedArgs.back());
4110+
repr = identRepr->getBase();
4111+
}
4112+
4113+
dc = dc->getParent();
4114+
}
4115+
4116+
for (auto &subArgs : llvm::reverse(nestedArgs)) {
4117+
args.append(subArgs.begin(), subArgs.end());
4118+
}
4119+
}
4120+
4121+
subs = SubstitutionMap::get(genericSig, args,
4122+
LookUpConformanceInModule());
4123+
}
4124+
4125+
if (ordinal >= opaqueDecl->getOpaqueGenericParams().size()) {
4126+
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
4127+
return ErrorType::get(getASTContext());
4128+
}
4129+
4130+
Type interfaceType = opaqueDecl->getOpaqueGenericParams()[ordinal];
4131+
return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs);
40614132
}
40624133

40634134
NeverNullType TypeResolver::resolveASTFunctionType(

test/ModuleInterface/invalid-opaque-result-types.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
//
1818
// RUN: not %target-swift-frontend -typecheck %s -I %t 2>&1 | %FileCheck %s
1919

20-
// CHECK: cannot find type 'InvalidParameter' in scope
2120
// CHECK: unable to resolve type for _opaqueReturnTypeOf attribute
2221
// CHECK: failed to build module 'InvalidOpaqueResultType' for importation
2322
import InvalidOpaqueResultType

0 commit comments

Comments
 (0)