Skip to content

Commit d2de21a

Browse files
author
Benjamin Driscoll
committed
[Frontend][Parse] Parse new named opaque return type syntax
In order to put constraints on opaque types in function returns, we want to support naming them like 'func f() -> <T> T { }'. This commit parses that syntax into the new `OpaqueReturnParameteriedTypeRepr`. This is hidden behind the new flag --enable-experimental-opaque-return-types.
1 parent 2ff13e3 commit d2de21a

File tree

12 files changed

+124
-11
lines changed

12 files changed

+124
-11
lines changed

include/swift/AST/TypeRepr.h

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,13 +1061,13 @@ class SILBoxTypeReprField {
10611061
TypeRepr *getFieldType() const { return FieldTypeAndMutable.getPointer(); }
10621062
bool isMutable() const { return FieldTypeAndMutable.getInt(); }
10631063
};
1064-
1065-
/// TypeRepr for opaque return types.
1064+
1065+
/// A TypeRepr for anonymous opaque return types.
10661066
///
1067-
/// This can occur in the return position of a function declaration, or the
1068-
/// top-level type of a property, to specify that the concrete return type
1069-
/// should be abstracted from callers, given a set of generic constraints that
1070-
/// the concrete return type satisfies:
1067+
/// This can occur in the return type of a function declaration, or the type of
1068+
/// a property, to specify that the concrete return type should be abstracted
1069+
/// from callers, given a set of generic constraints that the concrete return
1070+
/// type satisfies:
10711071
///
10721072
/// func foo() -> some Collection { return [1,2,3] }
10731073
/// var bar: some SignedInteger = 1
@@ -1101,6 +1101,42 @@ class OpaqueReturnTypeRepr : public TypeRepr {
11011101
friend class TypeRepr;
11021102
};
11031103

1104+
/// A TypeRepr for a type with a generic parameter list of named opaque return
1105+
/// types.
1106+
///
1107+
/// This can occur only as the return type of a function declaration, to specify
1108+
/// subtypes which should be abstracted from callers, given a set of generic
1109+
/// constraints that the concrete types satisfy:
1110+
///
1111+
/// func foo() -> <T: Collection> T { return [1] }
1112+
class OpaqueReturnParameterizedTypeRepr : public TypeRepr {
1113+
TypeRepr *Base;
1114+
GenericParamList *GenericParams;
1115+
1116+
public:
1117+
OpaqueReturnParameterizedTypeRepr(TypeRepr *Base,
1118+
GenericParamList *GenericParams)
1119+
: TypeRepr(TypeReprKind::OpaqueReturnParameterized), Base(Base),
1120+
GenericParams(GenericParams) {}
1121+
1122+
TypeRepr *getBase() const { return Base; }
1123+
GenericParamList *getGenericParams() const { return GenericParams; }
1124+
1125+
static bool classof(const TypeRepr *T) {
1126+
return T->getKind() == TypeReprKind::OpaqueReturnParameterized;
1127+
}
1128+
static bool classof(const OpaqueReturnParameterizedTypeRepr *T) {
1129+
return true;
1130+
}
1131+
1132+
private:
1133+
SourceLoc getStartLocImpl() const;
1134+
SourceLoc getEndLocImpl() const;
1135+
SourceLoc getLocImpl() const;
1136+
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
1137+
friend class TypeRepr;
1138+
};
1139+
11041140
/// TypeRepr for a user-specified placeholder (essentially, a user-facing
11051141
/// representation of an anonymous type variable.
11061142
///
@@ -1245,6 +1281,8 @@ inline bool TypeRepr::isSimple() const {
12451281
case TypeReprKind::Isolated:
12461282
case TypeReprKind::Placeholder:
12471283
return true;
1284+
case TypeReprKind::OpaqueReturnParameterized:
1285+
return cast<OpaqueReturnParameterizedTypeRepr>(this)->getBase()->isSimple();
12481286
}
12491287
llvm_unreachable("bad TypeRepr kind");
12501288
}

include/swift/AST/TypeReprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ TYPEREPR(Composition, TypeRepr)
5454
TYPEREPR(Metatype, TypeRepr)
5555
TYPEREPR(Protocol, TypeRepr)
5656
TYPEREPR(OpaqueReturn, TypeRepr)
57+
TYPEREPR(OpaqueReturnParameterized, TypeRepr)
5758
TYPEREPR(Placeholder, TypeRepr)
5859
ABSTRACT_TYPEREPR(Specifier, TypeRepr)
5960
TYPEREPR(InOut, SpecifierTypeRepr)

include/swift/Basic/LangOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ namespace swift {
286286
/// Enable experimental concurrency model.
287287
bool EnableExperimentalConcurrency = false;
288288

289+
/// Enable experimental support for additional opaque return type features,
290+
/// i.e. named opaque return types (with 'where' clause support), and opaque
291+
/// types in nested position within the function return type.
292+
bool EnableExperimentalOpaqueReturnTypes = false;
293+
289294
/// Enable experimental flow-sensitive concurrent captures.
290295
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
291296

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ def enable_experimental_static_assert :
437437
Flag<["-"], "enable-experimental-static-assert">,
438438
HelpText<"Enable experimental #assert">;
439439

440+
def enable_experimental_opaque_return_types :
441+
Flag<["-"], "enable-experimental-opaque-return-types">,
442+
HelpText<"Enable experimental extensions to opaque return type support">;
443+
440444
def enable_deserialization_recovery :
441445
Flag<["-"], "enable-deserialization-recovery">,
442446
HelpText<"Attempt to recover from missing xrefs (etc) in swiftmodules">;

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,6 +3139,13 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr> {
31393139
PrintWithColorRAII(OS, ParenthesisColor) << ')';
31403140
}
31413141

3142+
void
3143+
visitOpaqueReturnParameterizedTypeRepr(OpaqueReturnParameterizedTypeRepr *T) {
3144+
printCommon("type_opaque_return_parameterized") << '\n';
3145+
printRec(T->getBase());
3146+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
3147+
}
3148+
31423149
void visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) {
31433150
printCommon("type_placeholder");
31443151
PrintWithColorRAII(OS, ParenthesisColor) << ')';

lib/AST/ASTWalker.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,11 @@ bool Traversal::visitOpaqueReturnTypeRepr(OpaqueReturnTypeRepr *T) {
18581858
return doIt(T->getConstraint());
18591859
}
18601860

1861+
bool Traversal::visitOpaqueReturnParameterizedTypeRepr(
1862+
OpaqueReturnParameterizedTypeRepr *T) {
1863+
return doIt(T->getBase());
1864+
}
1865+
18611866
bool Traversal::visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) {
18621867
return false;
18631868
}

lib/AST/NameLookup.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2261,8 +2261,9 @@ directReferencesForTypeRepr(Evaluator &evaluator,
22612261
case TypeReprKind::SILBox:
22622262
case TypeReprKind::Placeholder:
22632263
return { };
2264-
2264+
22652265
case TypeReprKind::OpaqueReturn:
2266+
case TypeReprKind::OpaqueReturnParameterized:
22662267
return { };
22672268

22682269
case TypeReprKind::Fixed:

lib/AST/TypeRepr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,23 @@ void ProtocolTypeRepr::printImpl(ASTPrinter &Printer,
435435
Printer << ".Protocol";
436436
}
437437

438+
SourceLoc OpaqueReturnParameterizedTypeRepr::getStartLocImpl() const {
439+
return GenericParams->getLAngleLoc();
440+
}
441+
442+
SourceLoc OpaqueReturnParameterizedTypeRepr::getEndLocImpl() const {
443+
return Base->getEndLoc();
444+
}
445+
446+
SourceLoc OpaqueReturnParameterizedTypeRepr::getLocImpl() const {
447+
return Base->getLoc();
448+
}
449+
450+
void OpaqueReturnParameterizedTypeRepr::printImpl(
451+
ASTPrinter &Printer, const PrintOptions &Opts) const {
452+
printTypeRepr(Base, Printer, Opts);
453+
}
454+
438455
void OpaqueReturnTypeRepr::printImpl(ASTPrinter &Printer,
439456
const PrintOptions &Opts) const {
440457
Printer.printKeyword("some", Opts, /*Suffix=*/" ");

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
420420
Opts.EnableExperimentalConcurrency |=
421421
Args.hasArg(OPT_enable_experimental_concurrency);
422422

423+
Opts.EnableExperimentalOpaqueReturnTypes |=
424+
Args.hasArg(OPT_enable_experimental_opaque_return_types);
425+
423426
Opts.EnableExperimentalDistributed |=
424427
Args.hasArg(OPT_enable_experimental_distributed);
425428

lib/Parse/ParsePattern.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/Parse/Parser.h"
1818

1919
#include "swift/AST/ASTWalker.h"
20+
#include "swift/AST/GenericParamList.h"
2021
#include "swift/AST/Initializer.h"
2122
#include "swift/AST/Module.h"
2223
#include "swift/AST/SourceFile.h"
@@ -823,7 +824,7 @@ Parser::parseFunctionArguments(SmallVectorImpl<Identifier> &NamePieces,
823824
/// func-signature:
824825
/// func-arguments ('async'|'reasync')? func-throws? func-signature-result?
825826
/// func-signature-result:
826-
/// '->' type
827+
/// '->' generic-params? type
827828
///
828829
/// Note that this leaves retType as null if unspecified.
829830
ParserStatus
@@ -864,17 +865,39 @@ Parser::parseFunctionSignature(Identifier SimpleName,
864865
arrowLoc = consumeToken(tok::colon);
865866
}
866867

867-
// Check for effect specifiers after the arrow, but before the type, and
868-
// correct it.
868+
// Check for effect specifiers after the arrow, but before the generic
869+
// parameters, and correct it.
869870
parseEffectsSpecifiers(arrowLoc, asyncLoc, &reasync, throwsLoc, &rethrows);
870871

872+
GenericParamList *GenericParams = nullptr;
873+
if (Context.LangOpts.EnableExperimentalOpaqueReturnTypes) {
874+
auto GenericParamsResult = maybeParseGenericParams();
875+
GenericParams = GenericParamsResult.getPtrOrNull();
876+
Status |= GenericParamsResult;
877+
878+
// Check for effect specifiers after the generic parameters, but before
879+
// the return type, and correct it.
880+
parseEffectsSpecifiers(arrowLoc, asyncLoc, &reasync, throwsLoc,
881+
&rethrows);
882+
}
883+
871884
ParserResult<TypeRepr> ResultType =
872885
parseDeclResultType(diag::expected_type_function_result);
873886
retType = ResultType.getPtrOrNull();
874887
Status |= ResultType;
875888
if (Status.isErrorOrHasCompletion())
876889
return Status;
877890

891+
if (GenericParams != nullptr) {
892+
// The `Base` for our `OpaqueReturnParameterizedTypeRepr` should not be
893+
// `nullptr`
894+
assert(
895+
retType != nullptr &&
896+
"Expected non-null return type if `parseDeclReturnType` succeeded");
897+
retType = new (Context)
898+
OpaqueReturnParameterizedTypeRepr(retType, GenericParams);
899+
}
900+
878901
// Check for effect specifiers after the type and correct it.
879902
parseEffectsSpecifiers(arrowLoc, asyncLoc, &reasync, throwsLoc, &rethrows);
880903
} else {

lib/Sema/TypeCheckType.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2065,7 +2065,7 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
20652065

20662066
case TypeReprKind::Protocol:
20672067
return resolveProtocolType(cast<ProtocolTypeRepr>(repr), options);
2068-
2068+
20692069
case TypeReprKind::OpaqueReturn: {
20702070
// Only valid as the return type of a function, which should be handled
20712071
// during function decl type checking.
@@ -2084,6 +2084,10 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
20842084
: ErrorType::get(getASTContext());
20852085
}
20862086

2087+
case TypeReprKind::OpaqueReturnParameterized:
2088+
return resolveType(cast<OpaqueReturnParameterizedTypeRepr>(repr)->getBase(),
2089+
options);
2090+
20872091
case TypeReprKind::Placeholder: {
20882092
auto &ctx = getASTContext();
20892093
// Fill in the placeholder if there's an appropriate handler.

test/type/opaque_experimental.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %target-swift-frontend -enable-experimental-opaque-return-types -disable-availability-checking -typecheck -verify %s
2+
3+
// Tests for experimental extensions to opaque return type support.
4+
5+
func f0() -> <T> () { }

0 commit comments

Comments
 (0)