Skip to content

Commit db58e02

Browse files
committed
Sema: Hook up layout constraints to the solver
There were various problems with layout constraints either being ignored or handled incorrectly. Now that I've exercised this support with an upcoming patch, there are some fixes here. Also, introduce a new ExistentialLayout::getLayoutConstriant() which returns a value for existentials which are class-constrained but don't have a superclass or any class-constrained protocols; an example would be AnyObject, or AnyObject & P for some non-class protocol P. NFC for now, since these layout-constrained existentials cannot be constructed yet.
1 parent d58f049 commit db58e02

File tree

14 files changed

+96
-68
lines changed

14 files changed

+96
-68
lines changed

include/swift/AST/ExistentialLayout.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ struct ExistentialLayout {
7171
return multipleProtocols;
7272
}
7373

74+
LayoutConstraint getLayoutConstraint() const;
75+
7476
private:
7577
// Inline storage for 'protocols' member above when computing
7678
// layout of a single ProtocolType

include/swift/AST/Type.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,6 @@ class CanType : public Type {
434434
NominalTypeDecl *getAnyNominal() const;
435435
GenericTypeDecl *getAnyGeneric() const;
436436

437-
/// Returns information about the layout constraint represented by
438-
/// this type. If this type does not represent a layout constraint,
439-
/// it returns an empty LayoutConstraint.
440-
LayoutConstraint getLayoutConstraint() const;
441-
442437
CanType getAnyOptionalObjectType() const {
443438
OptionalTypeKind kind;
444439
return getAnyOptionalObjectTypeImpl(*this, kind);

include/swift/AST/Types.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,6 @@ class alignas(1 << TypeAlignInBits) TypeBase {
717717
/// concrete types to form the argument type.
718718
bool isBindableTo(Type ty, LazyResolver *resolver);
719719

720-
/// \brief Retrieve the layout constraint of this type.
721-
///
722-
/// \returns The layout constraint of this type, or a null layout constraint
723-
/// if it has no layout constraint.
724-
LayoutConstraint getLayoutConstraint();
725-
726720
/// \brief Determines whether this type is permitted as a method override
727721
/// of the \p other.
728722
bool canOverride(Type other, OverrideMatchMode matchMode,

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3539,17 +3539,21 @@ CanArchetypeType ArchetypeType::getOpened(Type existential,
35393539
for (auto proto : layout.getProtocols())
35403540
protos.push_back(proto->getDecl());
35413541

3542+
auto layoutConstraint = layout.getLayoutConstraint();
3543+
35423544
auto arena = AllocationArena::Permanent;
35433545
void *mem = ctx.Allocate(
35443546
totalSizeToAlloc<ProtocolDecl *, Type, LayoutConstraint, UUID>(
3545-
protos.size(), layout.superclass ? 1 : 0, 0, 1),
3547+
protos.size(),
3548+
layout.superclass ? 1 : 0,
3549+
layoutConstraint ? 1 : 0, 1),
35463550
alignof(ArchetypeType), arena);
35473551

35483552
// FIXME: Pass in class layout constraint
35493553
auto result =
35503554
::new (mem) ArchetypeType(ctx, existential,
35513555
protos, layout.superclass,
3552-
existential->getLayoutConstraint(), *knownID);
3556+
layoutConstraint, *knownID);
35533557
openedExistentialArchetypes[*knownID] = result;
35543558

35553559
return CanArchetypeType(result);

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,8 +2564,12 @@ ConstraintResult GenericSignatureBuilder::addTypeRequirement(
25642564
bool anyErrors = false;
25652565
auto layout = constraintType->getExistentialLayout();
25662566

2567-
assert((!layout.requiresClass || layout.requiresClassImplied) &&
2568-
"explicit AnyObject not yet supported");
2567+
if (auto layoutConstraint = layout.getLayoutConstraint()) {
2568+
if (isErrorResult(addLayoutRequirementDirect(subjectPA,
2569+
layoutConstraint,
2570+
resolvedSource)))
2571+
anyErrors = true;
2572+
}
25692573

25702574
if (layout.superclass) {
25712575
if (isErrorResult(addSuperclassRequirementDirect(subjectPA,

lib/AST/Type.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -588,13 +588,6 @@ Type TypeBase::lookThroughAllAnyOptionalTypes(SmallVectorImpl<Type> &optionals){
588588
return type;
589589
}
590590

591-
LayoutConstraint CanType::getLayoutConstraint() const {
592-
if (auto archetypeTy = dyn_cast<ArchetypeType>(*this)) {
593-
return archetypeTy->getLayoutConstraint();
594-
}
595-
return LayoutConstraint();
596-
}
597-
598591
bool TypeBase::isAnyObject() {
599592
auto canTy = getCanonicalType();
600593

@@ -624,6 +617,15 @@ bool ExistentialLayout::isExistentialWithError(ASTContext &ctx) const {
624617
return false;
625618
}
626619

620+
LayoutConstraint ExistentialLayout::getLayoutConstraint() const {
621+
if (requiresClass && !requiresClassImplied) {
622+
return LayoutConstraint::getLayoutConstraint(
623+
LayoutConstraintKind::Class);
624+
}
625+
626+
return LayoutConstraint();
627+
}
628+
627629
bool TypeBase::isExistentialWithError() {
628630
auto canTy = getCanonicalType();
629631

@@ -1569,12 +1571,6 @@ bool TypeBase::isSpelledLike(Type other) {
15691571
llvm_unreachable("Unknown type kind");
15701572
}
15711573

1572-
LayoutConstraint TypeBase::getLayoutConstraint() {
1573-
if (auto archetype = getAs<ArchetypeType>())
1574-
return archetype->getLayoutConstraint();
1575-
return LayoutConstraint();
1576-
}
1577-
15781574
bool TypeBase::mayHaveSuperclass() {
15791575
if (getClassOrBoundGenericClass())
15801576
return true;
@@ -2614,6 +2610,9 @@ ArchetypeType::getNew(const ASTContext &Ctx,
26142610
bool ArchetypeType::requiresClass() const {
26152611
if (ArchetypeTypeBits.HasSuperclass)
26162612
return true;
2613+
if (auto layout = getLayoutConstraint())
2614+
if (layout->isClass())
2615+
return true;
26172616
for (ProtocolDecl *conformed : getConformsTo())
26182617
if (conformed->requiresClass())
26192618
return true;
@@ -3733,6 +3732,15 @@ case TypeKind::Id:
37333732
if (firstType.getPointer() != req.getFirstType().getPointer())
37343733
anyChanges = true;
37353734

3735+
if (req.getKind() == RequirementKind::Layout) {
3736+
if (!firstType->isTypeParameter())
3737+
continue;
3738+
3739+
requirements.push_back(Requirement(req.getKind(), firstType,
3740+
req.getLayoutConstraint()));
3741+
continue;
3742+
}
3743+
37363744
Type secondType = req.getSecondType();
37373745
if (secondType) {
37383746
secondType = secondType.transformRec(fn);

lib/AST/TypeWalker.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,12 @@ class Traversal : public TypeVisitor<Traversal, bool>
9090
switch (req.getKind()) {
9191
case RequirementKind::SameType:
9292
case RequirementKind::Conformance:
93-
case RequirementKind::Layout:
9493
case RequirementKind::Superclass:
9594
if (doIt(req.getSecondType()))
9695
return true;
9796
break;
97+
case RequirementKind::Layout:
98+
break;
9899
}
99100
}
100101

lib/SILOptimizer/IPO/EagerSpecializer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,10 @@ void EagerDispatch::emitDispatchTo(SILFunction *NewFunc) {
349349
if (!Replacement->hasArchetype()) {
350350
// Dispatch on concrete type.
351351
emitTypeCheck(FailedTypeCheckBB, ParamTy, Replacement);
352-
} else {
352+
} else if (auto Archetype = Replacement->getAs<ArchetypeType>()) {
353353
// If Replacement has a layout constraint, then dispatch based
354354
// on its size and the fact that it is trivial.
355-
auto LayoutInfo = Replacement->getLayoutConstraint();
355+
auto LayoutInfo = Archetype->getLayoutConstraint();
356356
if (LayoutInfo && LayoutInfo->isTrivial()) {
357357
// Emit a check that it is a trivial type of a certain size.
358358
emitTrivialAndSizeCheck(FailedTypeCheckBB, ParamTy,

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3261,7 +3261,8 @@ bool swift::isExtensionApplied(DeclContext &DC, Type BaseTy,
32613261
createMemberConstraint(Req, ConstraintKind::ConformsTo);
32623262
break;
32633263
case RequirementKind::Layout:
3264-
createMemberConstraint(Req, ConstraintKind::Layout);
3264+
// FIXME FIXME FIXME
3265+
createMemberConstraint(Req, ConstraintKind::ConformsTo);
32653266
break;
32663267
case RequirementKind::Superclass:
32673268
createMemberConstraint(Req, ConstraintKind::Subtype);

lib/Sema/CSSimplify.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,6 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
708708
case ConstraintKind::BindOverload:
709709
case ConstraintKind::CheckedCast:
710710
case ConstraintKind::ConformsTo:
711-
case ConstraintKind::Layout:
712711
case ConstraintKind::Defaultable:
713712
case ConstraintKind::Disjunction:
714713
case ConstraintKind::DynamicTypeOf:
@@ -834,7 +833,6 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
834833
case ConstraintKind::BindOverload:
835834
case ConstraintKind::CheckedCast:
836835
case ConstraintKind::ConformsTo:
837-
case ConstraintKind::Layout:
838836
case ConstraintKind::Defaultable:
839837
case ConstraintKind::Disjunction:
840838
case ConstraintKind::DynamicTypeOf:
@@ -950,7 +948,6 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
950948
case ConstraintKind::BindOverload:
951949
case ConstraintKind::CheckedCast:
952950
case ConstraintKind::ConformsTo:
953-
case ConstraintKind::Layout:
954951
case ConstraintKind::Defaultable:
955952
case ConstraintKind::Disjunction:
956953
case ConstraintKind::DynamicTypeOf:
@@ -1019,7 +1016,6 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
10191016
case ConstraintKind::BindOverload:
10201017
case ConstraintKind::CheckedCast:
10211018
case ConstraintKind::ConformsTo:
1022-
case ConstraintKind::Layout:
10231019
case ConstraintKind::Defaultable:
10241020
case ConstraintKind::Disjunction:
10251021
case ConstraintKind::DynamicTypeOf:
@@ -1156,10 +1152,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
11561152
if (type1->isTypeVariableOrMember()) {
11571153
if (flags.contains(TMF_GenerateConstraints)) {
11581154
addUnsolvedConstraint(
1159-
Constraint::createRestricted(*this, kind,
1160-
ConversionRestrictionKind::Existential,
1161-
type1, type2,
1162-
getConstraintLocator(locator)));
1155+
Constraint::create(*this, kind, type1, type2,
1156+
getConstraintLocator(locator)));
11631157
return SolutionKind::Solved;
11641158
}
11651159

@@ -1183,8 +1177,30 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
11831177

11841178
auto layout = type2->getExistentialLayout();
11851179

1186-
assert((!layout.requiresClass || layout.requiresClassImplied) &&
1187-
"explicit AnyObject not yet supported");
1180+
if (auto layoutConstraint = layout.getLayoutConstraint()) {
1181+
if (layoutConstraint->isClass()) {
1182+
if (kind == ConstraintKind::ConformsTo) {
1183+
// Conformance to AnyObject is defined by having a single
1184+
// retainable pointer representation:
1185+
//
1186+
// - @objc existentials
1187+
// - class constrained archetypes
1188+
// - classes
1189+
if (!type1->isObjCExistentialType() &&
1190+
!type1->mayHaveSuperclass())
1191+
return SolutionKind::Error;
1192+
} else {
1193+
// Subtype relation to AnyObject also allows class-bound
1194+
// existentials that are not @objc and therefore carry
1195+
// witness tables.
1196+
if (!type1->isClassExistentialType() &&
1197+
!type1->mayHaveSuperclass())
1198+
return SolutionKind::Error;
1199+
}
1200+
1201+
// Keep going.
1202+
}
1203+
}
11881204

11891205
if (layout.superclass) {
11901206
auto subKind = std::min(ConstraintKind::Subtype, kind);
@@ -1562,7 +1578,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
15621578
case ConstraintKind::BridgingConversion:
15631579
case ConstraintKind::CheckedCast:
15641580
case ConstraintKind::ConformsTo:
1565-
case ConstraintKind::Layout:
15661581
case ConstraintKind::Defaultable:
15671582
case ConstraintKind::Disjunction:
15681583
case ConstraintKind::DynamicTypeOf:
@@ -2390,6 +2405,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
23902405
locator, flags);
23912406
}
23922407

2408+
// Dig out the fixed type to which this type refers.
2409+
type = getFixedTypeRecursive(type, flags, /*wantRValue=*/true);
2410+
23932411
return matchExistentialTypes(type, protocol, kind, flags, locator);
23942412
}
23952413

@@ -4383,7 +4401,6 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
43834401
subflags, locator);
43844402

43854403
case ConstraintKind::ConformsTo:
4386-
case ConstraintKind::Layout:
43874404
case ConstraintKind::LiteralConformsTo:
43884405
case ConstraintKind::SelfObjectOfProtocol:
43894406
return simplifyConformsToConstraint(first, second, kind, locator,
@@ -4540,7 +4557,6 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
45404557
return SolutionKind::Solved;
45414558

45424559
case ConstraintKind::ConformsTo:
4543-
case ConstraintKind::Layout:
45444560
case ConstraintKind::LiteralConformsTo:
45454561
case ConstraintKind::SelfObjectOfProtocol:
45464562
return simplifyConformsToConstraint(

lib/Sema/CSSolver.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,6 @@ static bool shouldBindToValueType(Constraint *constraint)
692692
case ConstraintKind::BindParam:
693693
case ConstraintKind::BindToPointerType:
694694
case ConstraintKind::ConformsTo:
695-
case ConstraintKind::Layout:
696695
case ConstraintKind::LiteralConformsTo:
697696
case ConstraintKind::CheckedCast:
698697
case ConstraintKind::SelfObjectOfProtocol:
@@ -852,9 +851,11 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
852851
if (tc.Context.LangOpts.EffectiveLanguageVersion[0] >= 4)
853852
continue;
854853

854+
if (!constraint->getSecondType()->is<ProtocolType>())
855+
continue;
856+
855857
LLVM_FALLTHROUGH;
856858

857-
case ConstraintKind::Layout:
858859
case ConstraintKind::LiteralConformsTo: {
859860
// If there is a 'nil' literal constraint, we might need optional
860861
// supertype bindings.

lib/Sema/Constraint.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
6060
case ConstraintKind::OperatorArgumentTupleConversion:
6161
case ConstraintKind::OperatorArgumentConversion:
6262
case ConstraintKind::ConformsTo:
63-
case ConstraintKind::Layout:
6463
case ConstraintKind::LiteralConformsTo:
6564
case ConstraintKind::CheckedCast:
6665
case ConstraintKind::SelfObjectOfProtocol:
@@ -176,7 +175,6 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
176175
case ConstraintKind::OperatorArgumentTupleConversion:
177176
case ConstraintKind::OperatorArgumentConversion:
178177
case ConstraintKind::ConformsTo:
179-
case ConstraintKind::Layout:
180178
case ConstraintKind::LiteralConformsTo:
181179
case ConstraintKind::CheckedCast:
182180
case ConstraintKind::DynamicTypeOf:
@@ -247,7 +245,6 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
247245
case ConstraintKind::OperatorArgumentConversion:
248246
Out << " operator arg conv "; break;
249247
case ConstraintKind::ConformsTo: Out << " conforms to "; break;
250-
case ConstraintKind::Layout: Out << " layout of "; break;
251248
case ConstraintKind::LiteralConformsTo: Out << " literal conforms to "; break;
252249
case ConstraintKind::CheckedCast: Out << " checked cast to "; break;
253250
case ConstraintKind::SelfObjectOfProtocol: Out << " Self type of "; break;
@@ -484,21 +481,19 @@ gatherReferencedTypeVars(Constraint *constraint,
484481
case ConstraintKind::OpenedExistentialOf:
485482
case ConstraintKind::OptionalObject:
486483
case ConstraintKind::Defaultable:
487-
constraint->getSecondType()->getTypeVariables(typeVars);
488-
LLVM_FALLTHROUGH;
489-
490-
case ConstraintKind::BindOverload:
491484
case ConstraintKind::ConformsTo:
492-
case ConstraintKind::Layout:
493485
case ConstraintKind::LiteralConformsTo:
494486
case ConstraintKind::SelfObjectOfProtocol:
495487
constraint->getFirstType()->getTypeVariables(typeVars);
488+
constraint->getSecondType()->getTypeVariables(typeVars);
489+
break;
490+
491+
case ConstraintKind::BindOverload:
492+
constraint->getFirstType()->getTypeVariables(typeVars);
496493

497494
// Special case: the base type of an overloading binding.
498-
if (constraint->getKind() == ConstraintKind::BindOverload) {
499-
if (auto baseType = constraint->getOverloadChoice().getBaseType()) {
500-
baseType->getTypeVariables(typeVars);
501-
}
495+
if (auto baseType = constraint->getOverloadChoice().getBaseType()) {
496+
baseType->getTypeVariables(typeVars);
502497
}
503498

504499
break;
@@ -527,12 +522,15 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind,
527522
second->getTypeVariables(typeVars);
528523
uniqueTypeVariables(typeVars);
529524

530-
// Conformance constraints expect a protocol on the right-hand side, always.
525+
// Conformance constraints expect an existential on the right-hand side.
531526
assert((kind != ConstraintKind::ConformsTo &&
532-
kind != ConstraintKind::LiteralConformsTo &&
533527
kind != ConstraintKind::SelfObjectOfProtocol) ||
528+
second->isExistentialType());
529+
530+
// Literal protocol conformances expect a protocol.
531+
assert((kind != ConstraintKind::LiteralConformsTo) ||
534532
second->is<ProtocolType>());
535-
533+
536534
// Bridging constraints require bridging to be enabled.
537535
assert(kind != ConstraintKind::BridgingConversion
538536
|| cs.TC.Context.LangOpts.EnableObjCInterop);

0 commit comments

Comments
 (0)