Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -2893,12 +2893,13 @@ BridgedGenericParamList BridgedGenericParamList_createParsed(

SWIFT_NAME(
"BridgedGenericTypeParamDecl.createParsed(_:declContext:specifierLoc:"
"name:nameLoc:inheritedType:index:paramKind:)")
"name:nameLoc:inheritedType:defaultType:index:paramKind:)")
BridgedGenericTypeParamDecl BridgedGenericTypeParamDecl_createParsed(
BridgedASTContext cContext, BridgedDeclContext cDeclContext,
swift::SourceLoc specifierLoc, swift::Identifier name,
swift::SourceLoc nameLoc, BridgedNullableTypeRepr opaqueInheritedType,
size_t index, swift::GenericTypeParamKind paramKind);
BridgedNullableTypeRepr defaultType, size_t index,
swift::GenericTypeParamKind paramKind);

SWIFT_NAME(
"BridgedTrailingWhereClause.createParsed(_:whereKeywordLoc:requirements:)")
Expand Down
41 changes: 37 additions & 4 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
ParamKind : 3,

/// Whether this generic parameter represents an opaque type.
IsOpaqueType : 1
IsOpaqueType : 1,

/// Whether we have computed the default type.
IsDefaultTypeComputed : 1
);

SWIFT_INLINE_BITFIELD_FULL(AssociatedTypeDecl, TypeDecl, 1,
Expand Down Expand Up @@ -3888,6 +3891,10 @@ class GenericTypeParamDecl final
: public TypeDecl,
private llvm::TrailingObjects<GenericTypeParamDecl, TypeRepr *,
SourceLoc> {
// The default type.
TypeLoc DefaultType;

friend class GenericTypeParamDeclDefaultTypeRequest;
friend TrailingObjects;

size_t numTrailingObjects(OverloadToken<TypeRepr *>) const {
Expand All @@ -3902,6 +3909,9 @@ class GenericTypeParamDecl final
return 0;
}

/// Set the computed default type.
void setDefaultType(Type ty);

/// Construct a new generic type parameter.
///
/// \param dc The DeclContext in which the generic type parameter's owner
Expand All @@ -3920,7 +3930,8 @@ class GenericTypeParamDecl final
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
///
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
SourceLoc specifierLoc, unsigned depth, unsigned index,
SourceLoc specifierLoc, TypeLoc defaultType,
unsigned depth, unsigned index,
GenericTypeParamKind paramKind, bool isOpaqueType,
TypeRepr *opaqueTypeRepr);

Expand All @@ -3943,6 +3954,7 @@ class GenericTypeParamDecl final
///
static GenericTypeParamDecl *create(DeclContext *dc, Identifier name,
SourceLoc nameLoc, SourceLoc specifierLoc,
TypeLoc defaultType,
unsigned depth, unsigned index,
GenericTypeParamKind paramKind,
bool isOpaqueType,
Expand All @@ -3956,8 +3968,8 @@ class GenericTypeParamDecl final
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
SourceLoc specifierLoc, unsigned depth, unsigned index,
GenericTypeParamKind paramKind)
: GenericTypeParamDecl(dc, name, nameLoc, specifierLoc, depth, index,
paramKind, false, nullptr) {
: GenericTypeParamDecl(dc, name, nameLoc, specifierLoc, TypeLoc(),
depth, index, paramKind, false, nullptr) {
}

/// Construct a deserialized generic type parameter.
Expand Down Expand Up @@ -3994,6 +4006,7 @@ class GenericTypeParamDecl final
static GenericTypeParamDecl *createParsed(DeclContext *dc, Identifier name,
SourceLoc nameLoc,
SourceLoc specifierLoc,
TypeLoc defaultType,
unsigned index,
GenericTypeParamKind paramKind);

Expand Down Expand Up @@ -4092,6 +4105,26 @@ class GenericTypeParamDecl final
return *getTrailingObjects<TypeRepr *>();
}

/// Check to see if we have a default type.
bool hasDefaultType() const {
// If we have a TypeRepr, return true immediately without kicking off
// a request.
return DefaultType.getTypeRepr() || getDefaultType();
}

/// Retrieve the default type as written in the source.
TypeRepr *getDefaultTypeRepr() const {
return DefaultType.getTypeRepr();
}

/// Retrieve the default type.
Type getDefaultType() const;

/// Retrieve the default type if computed, `None` otherwise.
///
/// \Note Should only be used for dumping.
std::optional<Type> getCachedDefaultType() const;

/// The index of this generic type parameter within its generic parameter
/// list.
///
Expand Down
14 changes: 14 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -8925,5 +8925,19 @@ ERROR(invalid_redecl_of_file_isolation,none,
NOTE(invalid_redecl_of_file_isolation_prev,none,
"default isolation was previously declared here", ())

//===----------------------------------------------------------------------===//
// MARK: Default generics
//===----------------------------------------------------------------------===//

ERROR(default_generic_not_trailing,none,
"generic parameter %0 with default type %1 must be trailing",
(const GenericTypeParamDecl *, Type))
ERROR(default_generic_not_type,none,
"generic parameter %0 can only have a default type on type declarations",
(const GenericTypeParamDecl *))
ERROR(default_generic_parameter_pack,none,
"declaration %0 cannot have both parameter packs and generic parameters with default types",
(const Decl *))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
21 changes: 21 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -5386,6 +5386,27 @@ class GenericTypeParamDeclGetValueTypeRequest
bool isCached() const { return true; }
};

/// Compute the default type of a generic type param.
class GenericTypeParamDeclDefaultTypeRequest
: public SimpleRequest<GenericTypeParamDeclDefaultTypeRequest,
Type(GenericTypeParamDecl *decl),
RequestFlags::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
Type evaluate(Evaluator &evaluator, GenericTypeParamDecl *decl) const;

public:
// Caching.
bool isCached() const { return true; }
std::optional<Type> getCachedResult() const;
void cacheResult(Type value) const;
};

class CustomDerivativesRequest
: public SimpleRequest<CustomDerivativesRequest,
evaluator::SideEffect(SourceFile *),
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,8 @@ SWIFT_REQUEST(TypeChecker, CustomDerivativesRequest,

SWIFT_REQUEST(TypeChecker, GenericTypeParamDeclGetValueTypeRequest,
Type(const GenericTypeParamDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, GenericTypeParamDeclDefaultTypeRequest,
Type(GenericTypeParamDecl *), SeparatelyCached, NoLocationInfo)

SWIFT_REQUEST(TypeChecker, SemanticAvailableAttrRequest,
std::optional<SemanticAvailableAttr>
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,9 @@ EXPERIMENTAL_FEATURE(ImportMacroAliases, true)
/// Enable borrow/mutate accessors
EXPERIMENTAL_FEATURE(BorrowAndMutateAccessors, false)

/// Allow generics to have a default type, e.g. `<T = Int>`.
EXPERIMENTAL_FEATURE(DefaultGenerics, false)

#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2204,6 +2204,11 @@ namespace {
printRec(decl->getValueType(), Label::always("value_type"));
break;
}

if (decl->hasDefaultType()) {
printRec(decl->getDefaultType(), Label::always("default_type"));
}

printAttributes(decl);

printFoot();
Expand Down
21 changes: 21 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2022,6 +2022,11 @@ void PrintAST::printSingleDepthOfGenericSignature(
printType(param->getValueType());
}

if (GP->hasDefaultType()) {
Printer << " = ";
printType(GP->getDefaultType());
}

Printer.printStructurePost(PrintStructureKind::GenericParameter,
GP);
} else {
Expand Down Expand Up @@ -3660,6 +3665,11 @@ void PrintAST::visitGenericTypeParamDecl(GenericTypeParamDecl *decl) {
});

printInherited(decl);

if (decl->hasDefaultType()) {
Printer << " = ";
decl->getDefaultType().print(Printer, Options);
}
}

void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
Expand Down Expand Up @@ -8388,6 +8398,17 @@ void GenericParamList::print(ASTPrinter &Printer,
} else {
loc.getType()->print(Printer, PO);
}

if (P->hasDefaultType()) {
Printer << " = ";

auto loc = P->getDefaultTypeRepr();
if (loc && willUseTypeReprPrinting(loc, nullptr, PO)) {
loc->print(Printer, PO);
} else {
P->getDefaultType()->print(Printer, PO);
}
}
}
},
[&] { Printer << ", "; });
Expand Down
12 changes: 10 additions & 2 deletions lib/AST/Bridging/GenericsBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,18 @@ BridgedGenericParamList BridgedGenericParamList_createParsed(
BridgedGenericTypeParamDecl BridgedGenericTypeParamDecl_createParsed(
BridgedASTContext cContext, BridgedDeclContext cDeclContext,
SourceLoc specifierLoc, Identifier name, SourceLoc nameLoc,
BridgedNullableTypeRepr bridgedInheritedType, size_t index,
BridgedNullableTypeRepr bridgedInheritedType,
BridgedNullableTypeRepr bridgedDefaultType, size_t index,
swift::GenericTypeParamKind paramKind) {
TypeLoc defaultType;

if (auto *defaultTypeRepr = bridgedDefaultType.unbridged()) {
defaultType = TypeLoc(defaultTypeRepr);
}

auto *decl = GenericTypeParamDecl::createParsed(
cDeclContext.unbridged(), name, nameLoc, specifierLoc, index, paramKind);
cDeclContext.unbridged(), name, nameLoc, specifierLoc, defaultType,
index, paramKind);

if (auto *inheritedType = bridgedInheritedType.unbridged()) {
auto entry = InheritedEntry(inheritedType);
Expand Down
42 changes: 33 additions & 9 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6088,11 +6088,13 @@ Type TypeAliasDecl::getStructuralType() const {
GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
SourceLoc nameLoc,
SourceLoc specifierLoc,
TypeLoc defaultType,
unsigned depth, unsigned index,
GenericTypeParamKind paramKind,
bool isOpaqueType,
TypeRepr *opaqueTypeRepr)
: TypeDecl(DeclKind::GenericTypeParam, dc, name, nameLoc, {}) {
: TypeDecl(DeclKind::GenericTypeParam, dc, name, nameLoc, {}),
DefaultType(defaultType) {
ASSERT(!(specifierLoc &&
!(paramKind == GenericTypeParamKind::Pack || paramKind == GenericTypeParamKind::Value)) &&
"'each' or 'let' keyword imply a parameter pack or value generic parameter");
Expand All @@ -6104,6 +6106,7 @@ GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
assert(Bits.GenericTypeParamDecl.Index == index && "Truncation");
Bits.GenericTypeParamDecl.ParamKind = (uint8_t) paramKind;
Bits.GenericTypeParamDecl.IsOpaqueType = isOpaqueType;
Bits.GenericTypeParamDecl.IsDefaultTypeComputed = false;

if (this->isOpaqueType())
*getTrailingObjects<TypeRepr *>() = opaqueTypeRepr;
Expand All @@ -6117,8 +6120,9 @@ GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,

GenericTypeParamDecl *GenericTypeParamDecl::create(
DeclContext *dc, Identifier name, SourceLoc nameLoc, SourceLoc specifierLoc,
unsigned depth, unsigned index, GenericTypeParamKind paramKind,
bool isOpaqueType, TypeRepr *opaqueTypeRepr) {
TypeLoc defaultType, unsigned depth, unsigned index,
GenericTypeParamKind paramKind, bool isOpaqueType,
TypeRepr *opaqueTypeRepr) {
auto &ctx = dc->getASTContext();

auto numTypeReprs = 0;
Expand All @@ -6136,37 +6140,39 @@ GenericTypeParamDecl *GenericTypeParamDecl::create(
numSourceLocs);
auto mem = ctx.Allocate(allocSize, alignof(GenericTypeParamDecl));
return new (mem)
GenericTypeParamDecl(dc, name, nameLoc, specifierLoc, depth, index,
paramKind, isOpaqueType, opaqueTypeRepr);
GenericTypeParamDecl(dc, name, nameLoc, specifierLoc, defaultType, depth,
index, paramKind, isOpaqueType, opaqueTypeRepr);
}

GenericTypeParamDecl *GenericTypeParamDecl::createDeserialized(
DeclContext *dc, Identifier name, unsigned depth, unsigned index,
GenericTypeParamKind paramKind, bool isOpaqueType) {
return GenericTypeParamDecl::create(dc, name, SourceLoc(), SourceLoc(),
depth, index, paramKind,
TypeLoc(), depth, index, paramKind,
isOpaqueType,
/*opaqueRepr*/ nullptr);
}

GenericTypeParamDecl *
GenericTypeParamDecl::createParsed(DeclContext *dc, Identifier name,
SourceLoc nameLoc, SourceLoc specifierLoc,
unsigned index,
TypeLoc defaultType, unsigned index,
GenericTypeParamKind paramKind) {
// We always create generic type parameters with an invalid depth.
// Semantic analysis fills in the depth when it processes the generic
// parameter list.
return GenericTypeParamDecl::create(
dc, name, nameLoc, specifierLoc, GenericTypeParamDecl::InvalidDepth,
index, paramKind, /*isOpaqueType*/ false, /*opaqueTypeRepr*/ nullptr);
dc, name, nameLoc, specifierLoc, defaultType,
GenericTypeParamDecl::InvalidDepth, index, paramKind,
/*isOpaqueType*/ false, /*opaqueTypeRepr*/ nullptr);
}

GenericTypeParamDecl *GenericTypeParamDecl::createImplicit(
DeclContext *dc, Identifier name, unsigned depth, unsigned index,
GenericTypeParamKind paramKind, TypeRepr *opaqueTypeRepr, SourceLoc nameLoc,
SourceLoc specifierLoc) {
auto *param = GenericTypeParamDecl::create(dc, name, nameLoc, specifierLoc,
TypeLoc(),
depth, index, paramKind,
(bool)opaqueTypeRepr,
opaqueTypeRepr);
Expand All @@ -6184,6 +6190,24 @@ Type GenericTypeParamDecl::getValueType() const {
return ty ? ty : ErrorType::get(ctx);
}

Type GenericTypeParamDecl::getDefaultType() const {
auto &ctx = getASTContext();
GenericTypeParamDeclDefaultTypeRequest req(const_cast<GenericTypeParamDecl *>(this));
return evaluateOrDefault(ctx.evaluator, req, Type());
}

std::optional<Type> GenericTypeParamDecl::getCachedDefaultType() const {
if (Bits.GenericTypeParamDecl.IsDefaultTypeComputed)
return DefaultType.getType();

return std::nullopt;
}

void GenericTypeParamDecl::setDefaultType(Type ty) {
DefaultType.setType(ty);
Bits.GenericTypeParamDecl.IsDefaultTypeComputed = true;
}

SourceRange GenericTypeParamDecl::getSourceRange() const {
auto startLoc = getNameLoc();
auto endLoc = getNameLoc();
Expand Down
16 changes: 16 additions & 0 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,22 @@ static bool usesFeatureDefaultIsolationPerFile(Decl *D) {
return isa<UsingDecl>(D);
}

static bool usesFeatureDefaultGenerics(Decl *decl) {
auto genericContext = decl->getAsGenericContext();

if (!genericContext || !genericContext->getGenericParams()) {
return false;
}

for (auto arg : *genericContext->getGenericParams()) {
if (arg->hasDefaultType()) {
return true;
}
}

return false;
}

UNINTERESTING_FEATURE(BuiltinSelect)
UNINTERESTING_FEATURE(BuiltinInterleave)
UNINTERESTING_FEATURE(BuiltinVectorsExternC)
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/GenericParamList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ GenericParamList::clone(DeclContext *dc) const {
GenericTypeParamDeclGetValueTypeRequest{newParam},
param->getValueType());

ctx.evaluator.cacheOutput(
GenericTypeParamDeclDefaultTypeRequest{newParam},
param->getDefaultType());

params.push_back(newParam);
}

Expand Down
Loading