Skip to content
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
23 changes: 20 additions & 3 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,13 @@ class RecursiveTypeProperties {
/// This type contains an ElementArchetype.
HasElementArchetype = 0x4000,

Last_Property = HasElementArchetype
/// Whether the type is allocated in the constraint solver arena. This can
/// differ from \c HasTypeVariable for types such as placeholders, which do
/// not have type variables, but we still want to allocate in the solver if
/// they have a type variable originator.
SolverAllocated = 0x8000,

Last_Property = SolverAllocated
};
enum { BitWidth = countBitsUsed(Property::Last_Property) };

Expand Down Expand Up @@ -224,6 +230,12 @@ class RecursiveTypeProperties {
/// opened element archetype?
bool hasElementArchetype() const { return Bits & HasElementArchetype; }

/// Whether the type is allocated in the constraint solver arena. This can
/// differ from \c hasTypeVariable() for types such as placeholders, which
/// do not have type variables, but we still want to allocate in the solver if
/// they have a type variable originator.
bool isSolverAllocated() const { return Bits & SolverAllocated; }

/// Does a type with these properties structurally contain a local
/// archetype?
bool hasLocalArchetype() const {
Expand Down Expand Up @@ -501,6 +513,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
}

void setRecursiveProperties(RecursiveTypeProperties properties) {
assert(!(properties.hasTypeVariable() && !properties.isSolverAllocated()) &&
"type variables must be solver allocated!");
Bits.TypeBase.Properties = properties.getBits();
assert(Bits.TypeBase.Properties == properties.getBits() && "Bits dropped!");
}
Expand Down Expand Up @@ -6714,8 +6728,9 @@ TypeVariableType : public TypeBase {
// type is opaque.

TypeVariableType(const ASTContext &C, unsigned ID)
: TypeBase(TypeKind::TypeVariable, &C,
RecursiveTypeProperties::HasTypeVariable) {
: TypeBase(TypeKind::TypeVariable, &C,
RecursiveTypeProperties::HasTypeVariable |
RecursiveTypeProperties::SolverAllocated) {
// Note: the ID may overflow (current limit is 2^20 - 1).
Bits.TypeVariableType.ID = ID;
if (Bits.TypeVariableType.ID != ID) {
Expand Down Expand Up @@ -6774,6 +6789,8 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type)
/// because the expression is ambiguous. This type is only used by the
/// constraint solver and transformed into UnresolvedType to be used in AST.
class PlaceholderType : public TypeBase {
// NOTE: If you add a new Type-based originator, you'll need to update the
// recursive property logic in PlaceholderType::get.
using Originator =
llvm::PointerUnion<TypeVariableType *, DependentMemberType *, VarDecl *,
ErrorExpr *, PlaceholderTypeRepr *>;
Expand Down
46 changes: 37 additions & 9 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ struct ASTContext::Implementation {
llvm::DenseMap<Type, InOutType*> InOutTypes;
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
DependentMemberTypes;
llvm::DenseMap<void *, PlaceholderType *> PlaceholderTypes;
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
Expand Down Expand Up @@ -1811,9 +1812,8 @@ bool ASTContext::hadError() const {

/// Retrieve the arena from which we should allocate storage for a type.
static AllocationArena getArena(RecursiveTypeProperties properties) {
bool hasTypeVariable = properties.hasTypeVariable();
return hasTypeVariable ? AllocationArena::ConstraintSolver
: AllocationArena::Permanent;
return properties.isSolverAllocated() ? AllocationArena::ConstraintSolver
: AllocationArena::Permanent;
}

void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
Expand Down Expand Up @@ -3117,15 +3117,43 @@ Type ErrorType::get(Type originalType) {
void *mem = ctx.Allocate(sizeof(ErrorType) + sizeof(Type),
alignof(ErrorType), arena);
RecursiveTypeProperties properties = RecursiveTypeProperties::HasError;
if (originalProperties.hasTypeVariable())
properties |= RecursiveTypeProperties::HasTypeVariable;

// We need to preserve the solver allocated bit, to ensure any wrapping
// types are solver allocated too.
if (originalProperties.isSolverAllocated())
properties |= RecursiveTypeProperties::SolverAllocated;

return entry = new (mem) ErrorType(ctx, originalType, properties);
}

Type PlaceholderType::get(ASTContext &ctx, Originator originator) {
assert(originator);
return new (ctx, AllocationArena::Permanent)
PlaceholderType(ctx, originator, RecursiveTypeProperties::HasPlaceholder);

auto originatorProps = [&]() -> RecursiveTypeProperties {
if (auto *tv = originator.dyn_cast<TypeVariableType *>())
return tv->getRecursiveProperties();

if (auto *depTy = originator.dyn_cast<DependentMemberType *>())
return depTy->getRecursiveProperties();

return RecursiveTypeProperties();
}();
auto arena = getArena(originatorProps);

auto &cache = ctx.getImpl().getArena(arena).PlaceholderTypes;
auto &entry = cache[originator.getOpaqueValue()];
if (entry)
return entry;

RecursiveTypeProperties properties = RecursiveTypeProperties::HasPlaceholder;

// We need to preserve the solver allocated bit, to ensure any wrapping
// types are solver allocated too.
if (originatorProps.isSolverAllocated())
properties |= RecursiveTypeProperties::SolverAllocated;

entry = new (ctx, arena) PlaceholderType(ctx, originator, properties);
return entry;
}

BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,
Expand Down Expand Up @@ -3943,7 +3971,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
static RecursiveTypeProperties
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
Type result) {
static_assert(RecursiveTypeProperties::BitWidth == 15,
static_assert(RecursiveTypeProperties::BitWidth == 16,
"revisit this if you add new recursive type properties");
RecursiveTypeProperties properties;

Expand Down Expand Up @@ -4604,7 +4632,7 @@ CanSILFunctionType SILFunctionType::get(
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));

RecursiveTypeProperties properties;
static_assert(RecursiveTypeProperties::BitWidth == 15,
static_assert(RecursiveTypeProperties::BitWidth == 16,
"revisit this if you add new recursive type properties");
for (auto &param : params)
properties |= param.getInterfaceType()->getRecursiveProperties();
Expand Down
10 changes: 6 additions & 4 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8475,8 +8475,8 @@ namespace {
exprType = solution.simplifyType(exprType);
// assert((!expr->getType() || expr->getType()->isEqual(exprType)) &&
// "Mismatched types!");
assert(!exprType->hasTypeVariable() &&
"Should not write type variable into expression!");
assert(!exprType->getRecursiveProperties().isSolverAllocated() &&
"Should not write solver allocated type into expression!");
assert(!exprType->hasPlaceholder() &&
"Should not write type placeholders into expression!");
expr->setType(exprType);
Expand All @@ -8486,8 +8486,10 @@ namespace {
Type componentType;
if (cs.hasType(kp, i)) {
componentType = solution.simplifyType(cs.getType(kp, i));
assert(!componentType->hasTypeVariable() &&
"Should not write type variable into key-path component");
assert(
!componentType->getRecursiveProperties().isSolverAllocated() &&
"Should not write solver allocated type into key-path "
"component!");
assert(!componentType->hasPlaceholder() &&
"Should not write type placeholder into key-path component");
kp->getMutableComponents()[i].setComponentType(componentType);
Expand Down
6 changes: 5 additions & 1 deletion test/Constraints/rdar44770297.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ func foo<T: P>(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Neve
fatalError()
}

let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}}
let _ = foo() {fatalError()} & nil
// expected-error@-1 {{global function 'foo' requires that 'Never' conform to 'P'}}
// expected-error@-2 {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}}
// expected-note@-3 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
// expected-note@-4 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ let _: () -> Void = {
// expected-error@-1 {{cannot convert value of type 'Any?' to specified type '(_, _)}}
}

let _: () -> Void = { // expected-error {{unable to infer closure type in the current context}}
let _: () -> Void = {
for case (0)? in [a] {}
for case (0, 0) in [a] {}
// expected-error@-1 {{cannot convert value of type 'Any?' to expected element type '(_, _)'}}
}