Skip to content

Add Sugar for Variadics #38787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 6, 2021
Merged
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
3 changes: 2 additions & 1 deletion include/swift/AST/TypeNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ ABSTRACT_SUGARED_TYPE(Sugar, Type)
ABSTRACT_SUGARED_TYPE(UnarySyntaxSugar, SyntaxSugarType)
SUGARED_TYPE(ArraySlice, UnarySyntaxSugarType)
SUGARED_TYPE(Optional, UnarySyntaxSugarType)
TYPE_RANGE(UnarySyntaxSugar, ArraySlice, Optional)
SUGARED_TYPE(VariadicSequence, UnarySyntaxSugarType)
TYPE_RANGE(UnarySyntaxSugar, ArraySlice, VariadicSequence)
SUGARED_TYPE(Dictionary, SyntaxSugarType)
TYPE_RANGE(SyntaxSugar, ArraySlice, Dictionary)
TYPE_RANGE(Sugar, Paren, Dictionary)
Expand Down
17 changes: 16 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5045,6 +5045,21 @@ class DictionaryType : public SyntaxSugarType {
}
};

/// The type T..., which is sugar for a sequence of argument values.
class VariadicSequenceType : public UnarySyntaxSugarType {
VariadicSequenceType(const ASTContext &ctx, Type base,
RecursiveTypeProperties properties)
: UnarySyntaxSugarType(TypeKind::VariadicSequence, ctx, base, properties) {}

public:
/// Return a uniqued variadic sequence type with the specified base type.
static VariadicSequenceType *get(Type baseTy);

static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::VariadicSequence;
}
};

/// ProtocolType - A protocol type describes an abstract interface implemented
/// by another type.
class ProtocolType : public NominalType {
Expand Down Expand Up @@ -6239,7 +6254,7 @@ inline bool CanType::isActuallyCanonicalOrNull() const {

inline Type TupleTypeElt::getVarargBaseTy() const {
TypeBase *T = getType().getPointer();
if (auto *AT = dyn_cast<ArraySliceType>(T))
if (auto *AT = dyn_cast<VariadicSequenceType>(T))
return AT->getBaseType();
if (auto *BGT = dyn_cast<BoundGenericType>(T)) {
// It's the stdlib Array<T>.
Expand Down
16 changes: 15 additions & 1 deletion lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ struct ASTContext::Implementation {
llvm::DenseMap<llvm::PointerIntPair<TypeBase*, 3, unsigned>,
ExistentialMetatypeType*> ExistentialMetatypeTypes;
llvm::DenseMap<Type, ArraySliceType*> ArraySliceTypes;
llvm::DenseMap<Type, VariadicSequenceType*> VariadicSequenceTypes;
llvm::DenseMap<std::pair<Type, Type>, DictionaryType *> DictionaryTypes;
llvm::DenseMap<Type, OptionalType*> OptionalTypes;
llvm::DenseMap<Type, ParenType*> SimpleParenTypes; // Most are simple
Expand Down Expand Up @@ -2569,6 +2570,7 @@ size_t ASTContext::Implementation::Arena::getTotalMemory() const {
llvm::capacity_in_bytes(ArraySliceTypes) +
llvm::capacity_in_bytes(DictionaryTypes) +
llvm::capacity_in_bytes(OptionalTypes) +
llvm::capacity_in_bytes(VariadicSequenceTypes) +
llvm::capacity_in_bytes(SimpleParenTypes) +
llvm::capacity_in_bytes(ParenTypes) +
llvm::capacity_in_bytes(ReferenceStorageTypes) +
Expand Down Expand Up @@ -3452,7 +3454,7 @@ Type AnyFunctionType::Param::getParameterType(bool forCanonical,
else if (forCanonical)
type = BoundGenericType::get(arrayDecl, Type(), {type});
else
type = ArraySliceType::get(type);
type = VariadicSequenceType::get(type);
}
return type;
}
Expand Down Expand Up @@ -4024,6 +4026,18 @@ ArraySliceType *ArraySliceType::get(Type base) {
return entry = new (C, arena) ArraySliceType(C, base, properties);
}

VariadicSequenceType *VariadicSequenceType::get(Type base) {
auto properties = base->getRecursiveProperties();
auto arena = getArena(properties);

const ASTContext &C = base->getASTContext();

VariadicSequenceType *&entry = C.getImpl().getArena(arena).VariadicSequenceTypes[base];
if (entry) return entry;

return entry = new (C, arena) VariadicSequenceType(C, base, properties);
}

DictionaryType *DictionaryType::get(Type keyType, Type valueType) {
auto properties = keyType->getRecursiveProperties()
| valueType->getRecursiveProperties();
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3840,6 +3840,12 @@ namespace {
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitVariadicSequenceType(VariadicSequenceType *T, StringRef label) {
printCommon(label, "variadic_sequence_type");
printRec(T->getBaseType());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitProtocolCompositionType(ProtocolCompositionType *T,
StringRef label) {
printCommon(label, "protocol_composition_type");
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,12 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
appendOperator("XSa");
return;

case TypeKind::VariadicSequence:
assert(DWARFMangling && "sugared types are only legal for the debugger");
appendType(cast<VariadicSequenceType>(tybase)->getBaseType());
appendOperator("XSa");
return;

case TypeKind::Optional:
assert(DWARFMangling && "sugared types are only legal for the debugger");
appendType(cast<OptionalType>(tybase)->getBaseType());
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5128,6 +5128,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
Printer << "?";
}

void visitVariadicSequenceType(VariadicSequenceType *T) {
visit(T->getBaseType());
Printer << "...";
}

void visitProtocolType(ProtocolType *T) {
printQualifiedType(T);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6528,7 +6528,7 @@ void ParamDecl::setNonEphemeralIfPossible() {

Type ParamDecl::getVarargBaseTy(Type VarArgT) {
TypeBase *T = VarArgT.getPointer();
if (auto *AT = dyn_cast<ArraySliceType>(T))
if (auto *AT = dyn_cast<VariadicSequenceType>(T))
return AT->getBaseType();
if (auto *BGT = dyn_cast<BoundGenericType>(T)) {
// It's the stdlib Array<T>.
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,7 @@ Type SugarType::getSinglyDesugaredTypeSlow() {
case TypeKind::TypeAlias:
llvm_unreachable("bound type alias types always have an underlying type");
case TypeKind::ArraySlice:
case TypeKind::VariadicSequence:
implDecl = Context->getArrayDecl();
break;
case TypeKind::Optional:
Expand Down Expand Up @@ -4974,6 +4975,18 @@ case TypeKind::Id:
return OptionalType::get(baseTy);
}

case TypeKind::VariadicSequence: {
auto seq = cast<VariadicSequenceType>(base);
auto baseTy = seq->getBaseType().transformRec(fn);
if (!baseTy)
return Type();

if (baseTy.getPointer() == seq->getBaseType().getPointer())
return *this;

return VariadicSequenceType::get(baseTy);
}

case TypeKind::Dictionary: {
auto dict = cast<DictionaryType>(base);
auto keyTy = dict->getKeyType().transformRec(fn);
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1629,7 +1629,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
// SyntaxSugarType derivations.
case TypeKind::Dictionary:
case TypeKind::ArraySlice:
case TypeKind::Optional: {
case TypeKind::Optional:
case TypeKind::VariadicSequence: {
auto *SyntaxSugarTy = cast<SyntaxSugarType>(BaseTy);
auto *CanTy = SyntaxSugarTy->getSinglyDesugaredType();
return getOrCreateDesugaredType(CanTy, DbgTy);
Expand Down
7 changes: 3 additions & 4 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2623,14 +2623,13 @@ namespace {

// Try to build the appropriate type for a variadic argument list of
// the fresh element type. If that failed, just bail out.
auto array = TypeChecker::getArraySliceType(expr->getLoc(), element);
if (array->hasError()) return element;
auto variadicSeq = VariadicSequenceType::get(element);

// Require the operand to be convertible to the array type.
CS.addConstraint(ConstraintKind::Conversion,
CS.getType(expr->getSubExpr()), array,
CS.getType(expr->getSubExpr()), variadicSeq,
CS.getConstraintLocator(expr));
return array;
return variadicSeq;
}

Type visitDynamicTypeExpr(DynamicTypeExpr *expr) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8900,7 +8900,7 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
// If external parameter is variadic it translates into an array in
// the body of the closure.
internalType =
param.isVariadic() ? ArraySliceType::get(typeVar) : Type(typeVar);
param.isVariadic() ? VariadicSequenceType::get(typeVar) : Type(typeVar);

auto externalType = param.getOldType();

Expand Down
7 changes: 4 additions & 3 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2166,9 +2166,10 @@ static Type validateParameterType(ParamDecl *decl) {
}

if (decl->isVariadic()) {
Ty = TypeChecker::getArraySliceType(decl->getStartLoc(), Ty);
if (Ty->hasError()) {
decl->setInvalid();
Ty = VariadicSequenceType::get(Ty);
if (!ctx.getArrayDecl()) {
ctx.Diags.diagnose(decl->getTypeRepr()->getLoc(),
diag::sugar_type_not_found, 0);
return ErrorType::get(ctx);
}

Expand Down
25 changes: 10 additions & 15 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,16 +359,6 @@ bool TypeResolution::areSameType(Type type1, Type type2) const {
return areSameType(depMem1->getBase(), depMem2->getBase());
}

Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) {
ASTContext &ctx = elementType->getASTContext();
if (!ctx.getArrayDecl()) {
ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 0);
return ErrorType::get(ctx);
}

return ArraySliceType::get(elementType);
}

Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) {
ASTContext &ctx = elementType->getASTContext();
if (!ctx.getOptionalDecl()) {
Expand Down Expand Up @@ -3604,12 +3594,17 @@ NeverNullType TypeResolver::resolveArrayType(ArrayTypeRepr *repr,
return ErrorType::get(getASTContext());
}

auto sliceTy =
TypeChecker::getArraySliceType(repr->getBrackets().Start, baseTy);
if (sliceTy->hasError())
return ErrorType::get(getASTContext());
ASTContext &ctx = baseTy->getASTContext();
// If the standard library isn't loaded, we ought to let the user know
// something has gone terribly wrong, since the rest of the compiler is going
// to assume it can canonicalize [T] to Array<T>.
if (!ctx.getArrayDecl()) {
ctx.Diags.diagnose(repr->getBrackets().Start,
diag::sugar_type_not_found, 0);
return ErrorType::get(ctx);
}

return sliceTy;
return ArraySliceType::get(baseTy);
}

NeverNullType
Expand Down
1 change: 0 additions & 1 deletion lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ enum class CheckedCastContextKind {
};

namespace TypeChecker {
Type getArraySliceType(SourceLoc loc, Type elementType);
Type getOptionalType(SourceLoc loc, Type elementType);

/// Bind an UnresolvedDeclRefExpr by performing name lookup and
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/DeclTypeRecordNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ TYPE(DICTIONARY)
TYPE(REFERENCE_STORAGE)
TYPE(UNBOUND_GENERIC)
TYPE(OPTIONAL)
TYPE(VARIADIC_SEQUENCE)
TYPE(SIL_FUNCTION)
TYPE(DYNAMIC_SELF)
TYPE(OPENED_EXISTENTIAL)
Expand Down
13 changes: 13 additions & 0 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5901,6 +5901,18 @@ class TypeDeserializer {
return OptionalType::get(baseTy.get());
}

Expected<Type> deserializeVariadicSequenceType(ArrayRef<uint64_t> scratch,
StringRef blobData) {
TypeID baseID;
decls_block::VariadicSequenceTypeLayout::readRecord(scratch, baseID);

auto baseTy = MF.getTypeChecked(baseID);
if (!baseTy)
return baseTy.takeError();

return VariadicSequenceType::get(baseTy.get());
}

Expected<Type> deserializeUnboundGenericType(ArrayRef<uint64_t> scratch,
StringRef blobData) {
DeclID genericID;
Expand Down Expand Up @@ -6024,6 +6036,7 @@ Expected<Type> TypeDeserializer::getTypeCheckedImpl() {
CASE(ArraySlice)
CASE(Dictionary)
CASE(Optional)
CASE(VariadicSequence)
CASE(UnboundGeneric)
CASE(Error)

Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ namespace decls_block {

using ArraySliceTypeLayout = SyntaxSugarTypeLayout<ARRAY_SLICE_TYPE>;
using OptionalTypeLayout = SyntaxSugarTypeLayout<OPTIONAL_TYPE>;
using VariadicSequenceTypeLayout = SyntaxSugarTypeLayout<VARIADIC_SEQUENCE_TYPE>;

using DictionaryTypeLayout = BCRecordLayout<
DICTIONARY_TYPE,
Expand Down
6 changes: 6 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4544,6 +4544,11 @@ class Serializer::TypeSerializer : public TypeVisitor<TypeSerializer> {
S.addTypeRef(dictTy->getValueType()));
}

void visitVariadicSequenceType(const VariadicSequenceType *seqTy) {
using namespace decls_block;
serializeSimpleWrapper<VariadicSequenceTypeLayout>(seqTy->getBaseType());
}

void visitOptionalType(const OptionalType *optionalTy) {
using namespace decls_block;
serializeSimpleWrapper<OptionalTypeLayout>(optionalTy->getBaseType());
Expand Down Expand Up @@ -4747,6 +4752,7 @@ void Serializer::writeAllDeclsAndTypes() {
registerDeclTypeAbbr<SILFunctionTypeLayout>();
registerDeclTypeAbbr<ArraySliceTypeLayout>();
registerDeclTypeAbbr<DictionaryTypeLayout>();
registerDeclTypeAbbr<VariadicSequenceTypeLayout>();
registerDeclTypeAbbr<ReferenceStorageTypeLayout>();
registerDeclTypeAbbr<UnboundGenericTypeLayout>();
registerDeclTypeAbbr<OptionalTypeLayout>();
Expand Down
6 changes: 3 additions & 3 deletions test/Constraints/keypath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ func testVariadicKeypathAsFunc() {
takesVariadicFnWithGenericRet(\Array.i)

// These are not okay, the KeyPath should have a base that matches the
// internal parameter type of the function, i.e [S].
let _: (S...) -> Int = \S.i // expected-error {{key path value type 'S' cannot be converted to contextual type '[S]'}}
takesVariadicFnWithGenericRet(\S.i) // expected-error {{key path value type 'S' cannot be converted to contextual type '[S]'}}
// internal parameter type of the function, i.e (S...).
let _: (S...) -> Int = \S.i // expected-error {{key path value type 'S' cannot be converted to contextual type 'S...'}}
takesVariadicFnWithGenericRet(\S.i) // expected-error {{key path value type 'S' cannot be converted to contextual type 'S...'}}
}

// rdar://problem/54322807
Expand Down