mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -4018,25 +4018,12 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
|
||||
return elements;
|
||||
}
|
||||
|
||||
/// Implement the special @_opaqueReturnTypeOf attribute syntax in
|
||||
/// module interface files.
|
||||
NeverNullType
|
||||
TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName,
|
||||
unsigned ordinal,
|
||||
TypeResolutionOptions options) {
|
||||
// The type representation should be an unqualified identifier. We don't
|
||||
// really use the identifier for anything, but we do resolve any generic
|
||||
// arguments to instantiate the possibly-generic opaque type.
|
||||
SmallVector<Type, 4> TypeArgsBuf;
|
||||
if (auto *unqualIdentRepr = dyn_cast<UnqualifiedIdentTypeRepr>(repr)) {
|
||||
for (auto argRepr : unqualIdentRepr->getGenericArgs()) {
|
||||
auto argTy = resolveType(argRepr, options);
|
||||
// If we cannot resolve the generic parameter, propagate the error out.
|
||||
if (argTy->hasError()) {
|
||||
return ErrorType::get(getASTContext());
|
||||
}
|
||||
TypeArgsBuf.push_back(argTy);
|
||||
}
|
||||
}
|
||||
|
||||
// Use type reconstruction to summon the opaque type decl.
|
||||
Demangler demangle;
|
||||
auto definingDeclNode = demangle.demangleSymbol(mangledName);
|
||||
@@ -4050,14 +4037,98 @@ TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName,
|
||||
auto opaqueNode =
|
||||
builder.getNodeFactory().createNode(Node::Kind::OpaqueReturnTypeOf);
|
||||
opaqueNode->addChild(definingDeclNode, builder.getNodeFactory());
|
||||
|
||||
auto TypeArgs = ArrayRef<Type>(TypeArgsBuf);
|
||||
auto ty = builder.resolveOpaqueType(opaqueNode, TypeArgs, ordinal);
|
||||
if (!ty || ty->hasError()) {
|
||||
auto *opaqueDecl = builder.resolveOpaqueTypeDecl(opaqueNode);
|
||||
|
||||
auto *ownerDecl = opaqueDecl->getNamingDecl();
|
||||
if (!ownerDecl) {
|
||||
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
|
||||
return ErrorType::get(getASTContext());
|
||||
}
|
||||
return ty;
|
||||
|
||||
auto genericSig = ownerDecl->getInnermostDeclContext()
|
||||
->getGenericSignatureOfContext();
|
||||
|
||||
SubstitutionMap subs;
|
||||
if (genericSig) {
|
||||
SmallVector<Type, 2> args;
|
||||
|
||||
// The type representation should either be a single identifier, or a
|
||||
// series of member references. We don't use the identifiers for
|
||||
// anything, but we do resolve the generic arguments at each level
|
||||
// to instantiate the possibly-generic opaque type.
|
||||
if (isa<UnqualifiedIdentTypeRepr>(repr) &&
|
||||
!genericSig->hasParameterPack()) {
|
||||
// When there are no parameter packs and we just have a single
|
||||
// unqualified identifier, we fall back to the legacy behavior,
|
||||
// which collects the generic arguments for all levels of nesting
|
||||
// in a flat list.
|
||||
//
|
||||
// This matches the old behavior of the ASTPrinter.
|
||||
auto *unqualIdentRepr = cast<UnqualifiedIdentTypeRepr>(repr);
|
||||
|
||||
for (auto argRepr : unqualIdentRepr->getGenericArgs()) {
|
||||
auto argTy = resolveType(argRepr, options);
|
||||
// If we cannot resolve the generic parameter, propagate the error out.
|
||||
if (argTy->hasError()) {
|
||||
return ErrorType::get(getASTContext());
|
||||
}
|
||||
args.push_back(argTy);
|
||||
}
|
||||
|
||||
if (args.size() != genericSig.getGenericParams().size()) {
|
||||
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
|
||||
return ErrorType::get(getASTContext());
|
||||
}
|
||||
} else {
|
||||
// Correct handling of nested types. We interpret a qualified
|
||||
// TypeRepr with a generic argument list at each level, like
|
||||
// __<OuterArgs, ...>.__<InnerArgs, ...>.
|
||||
SmallVector<SmallVector<Type, 2>, 2> nestedArgs;
|
||||
|
||||
auto *dc = ownerDecl->getInnermostDeclContext();
|
||||
while (!dc->isModuleScopeContext()) {
|
||||
if (dc->isInnermostContextGeneric()) {
|
||||
if (repr == nullptr || !isa<DeclRefTypeRepr>(repr)) {
|
||||
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
|
||||
return ErrorType::get(getASTContext());
|
||||
}
|
||||
|
||||
auto *identRepr = cast<DeclRefTypeRepr>(repr);
|
||||
nestedArgs.emplace_back();
|
||||
|
||||
auto *decl = dyn_cast<ValueDecl>(dc->getAsDecl());
|
||||
if (decl == nullptr)
|
||||
decl = dc->getSelfNominalTypeDecl();
|
||||
ASSERT(decl);
|
||||
|
||||
resolveGenericArguments(decl,
|
||||
decl->getAsGenericContext(),
|
||||
resolution,
|
||||
silContext,
|
||||
identRepr,
|
||||
nestedArgs.back());
|
||||
repr = identRepr->getBase();
|
||||
}
|
||||
|
||||
dc = dc->getParent();
|
||||
}
|
||||
|
||||
for (auto &subArgs : llvm::reverse(nestedArgs)) {
|
||||
args.append(subArgs.begin(), subArgs.end());
|
||||
}
|
||||
}
|
||||
|
||||
subs = SubstitutionMap::get(genericSig, args,
|
||||
LookUpConformanceInModule());
|
||||
}
|
||||
|
||||
if (ordinal >= opaqueDecl->getOpaqueGenericParams().size()) {
|
||||
diagnose(repr->getLoc(), diag::no_opaque_return_type_of);
|
||||
return ErrorType::get(getASTContext());
|
||||
}
|
||||
|
||||
Type interfaceType = opaqueDecl->getOpaqueGenericParams()[ordinal];
|
||||
return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs);
|
||||
}
|
||||
|
||||
NeverNullType TypeResolver::resolveASTFunctionType(
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
//
|
||||
// RUN: not %target-swift-frontend -typecheck %s -I %t 2>&1 | %FileCheck %s
|
||||
|
||||
// CHECK: cannot find type 'InvalidParameter' in scope
|
||||
// CHECK: unable to resolve type for _opaqueReturnTypeOf attribute
|
||||
// CHECK: failed to build module 'InvalidOpaqueResultType' for importation
|
||||
import InvalidOpaqueResultType
|
||||
|
||||
Reference in New Issue
Block a user