Skip to content

Commit 75dfab0

Browse files
committed
RequirementMachine: Eliminate layout requirement implied by concrete type requirement
A type parameter subject to an AnyObject requirement might also be subject to a concrete type requirement. There are two cases to handle here: - If the concrete type is a class, the layout requirement is redundant. - If the concrete type is not a class, we have a conflict. There is an existing test that's good enough; I just changed it to run with -requirement-machine-inferred-signatures=verify.
1 parent 41e3292 commit 75dfab0

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ static void recordRelation(Term key,
6767
(lhsProperty.getKind() == Symbol::Kind::Superclass &&
6868
rhsProperty.getKind() == Symbol::Kind::Layout) ||
6969
(lhsProperty.getKind() == Symbol::Kind::ConcreteType &&
70-
rhsProperty.getKind() == Symbol::Kind::Superclass));
70+
rhsProperty.getKind() == Symbol::Kind::Superclass) ||
71+
(lhsProperty.getKind() == Symbol::Kind::ConcreteType &&
72+
rhsProperty.getKind() == Symbol::Kind::Layout));
7173

7274
if (debug) {
7375
llvm::dbgs() << "%% Recording relation: ";
@@ -484,7 +486,7 @@ void PropertyMap::checkConcreteTypeRequirements() {
484486
bool debug = Debug.contains(DebugFlags::ConcreteUnification);
485487

486488
for (auto *props : Entries) {
487-
if (props->ConcreteTypeRule && props->SuperclassRule) {
489+
if (props->ConcreteTypeRule) {
488490
auto concreteType = props->ConcreteType->getConcreteType();
489491

490492
// A rule (T.[concrete: C] => T) where C is a class type induces a rule
@@ -497,12 +499,42 @@ void PropertyMap::checkConcreteTypeRequirements() {
497499
recordRelation(props->getKey(), *props->ConcreteTypeRule,
498500
superclassSymbol, System, debug);
499501

500-
// Otherwise, we have a concrete vs superclass conflict.
501-
} else {
502+
// If the concrete type is not a class and we have a superclass
503+
// requirement, we have a conflict.
504+
} else if (props->SuperclassRule) {
502505
recordConflict(props->getKey(),
503506
*props->ConcreteTypeRule,
504507
*props->SuperclassRule, System);
505508
}
509+
510+
// A rule (T.[concrete: C] => T) where C is a class type induces a rule
511+
// (T.[layout: L] => T), where L is either AnyObject or _NativeObject.
512+
if (concreteType->satisfiesClassConstraint()) {
513+
Type superclassType = concreteType;
514+
if (!concreteType->getClassOrBoundGenericClass())
515+
superclassType = concreteType->getSuperclass();
516+
517+
auto layoutConstraint = LayoutConstraintKind::Class;
518+
if (superclassType)
519+
if (auto *classDecl = superclassType->getClassOrBoundGenericClass())
520+
layoutConstraint = classDecl->getLayoutConstraintKind();
521+
522+
auto layout =
523+
LayoutConstraint::getLayoutConstraint(
524+
layoutConstraint, Context.getASTContext());
525+
auto layoutSymbol = Symbol::forLayout(layout, Context);
526+
527+
recordRelation(props->getKey(), *props->ConcreteTypeRule,
528+
layoutSymbol, System, debug);
529+
530+
// If the concrete type does not satisfy a class layout constraint and
531+
// we have such a layout requirement, we have a conflict.
532+
} else if (props->LayoutRule &&
533+
props->Layout->isClass()) {
534+
recordConflict(props->getKey(),
535+
*props->ConcreteTypeRule,
536+
*props->LayoutRule, System);
537+
}
506538
}
507539
}
508540
}

test/Generics/concrete_same_type_versus_anyobject.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
2-
// RUN: not %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
2+
// RUN: not %target-swift-frontend -typecheck -debug-generic-signatures -requirement-machine-inferred-signatures=verify %s 2>&1 | %FileCheck %s
33
struct S {}
44
class C {}
55

0 commit comments

Comments
 (0)