Skip to content

Commit 5aa51e9

Browse files
committed
[GSB] Keep track of all layout constraints.
As we've done with all of the other kinds of constraints, keep track of all of the layout constraints on the equivalence class. Use the normal mechanism to diagnose conflicts between different layout constraints, warn about duplicate layout constraints, etc.
1 parent 0f4c14b commit 5aa51e9

File tree

4 files changed

+74
-41
lines changed

4 files changed

+74
-41
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,11 +1591,15 @@ NOTE(superclass_redundancy_here,none,
15911591
"superclass constraint %1 : %2 %select{written here|implied here}0",
15921592
(bool, Type, Type))
15931593

1594-
ERROR(mutiple_layout_constraints,none,
1595-
"multiple layout constraints cannot be used at the same time: %0 and %1",
1596-
(LayoutConstraint, LayoutConstraint))
1594+
ERROR(conflicting_layout_constraints,none,
1595+
"%select{generic parameter |protocol |}0%1 has conflicting layout "
1596+
"constraints %2 and %3",
1597+
(unsigned, Type, LayoutConstraint, LayoutConstraint))
1598+
WARNING(redundant_layout_constraint,none,
1599+
"redundant layout constraint %0 : %1", (Type, LayoutConstraint))
15971600
NOTE(previous_layout_constraint, none,
1598-
"previous layout constraint declaration %0 was here", (LayoutConstraint))
1601+
"layout constraint constraint %1 : %2 %select{written here|implied here}0",
1602+
(bool, Type, LayoutConstraint))
15991603

16001604
ERROR(generic_param_access,none,
16011605
"%0 %select{must be declared %select{"

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ class GenericSignatureBuilder {
128128
/// Superclass constraints written within this equivalence class.
129129
std::vector<ConcreteConstraint> superclassConstraints;
130130

131+
/// \The layout constraint for this equivalence class.
132+
LayoutConstraint layout;
133+
134+
/// Layout constraints written within this equivalence class.
135+
std::vector<Constraint<LayoutConstraint>> layoutConstraints;
136+
131137
/// The members of the equivalence class.
132138
TinyPtrVector<PotentialArchetype *> members;
133139

@@ -474,6 +480,11 @@ class GenericSignatureBuilder {
474480
ArrayRef<GenericTypeParamType *> genericParams,
475481
PotentialArchetype *pa);
476482

483+
/// Check layout constraints within the equivalence class of the given
484+
/// potential archetype.
485+
void checkLayoutConstraints(ArrayRef<GenericTypeParamType *> genericParams,
486+
PotentialArchetype *pa);
487+
477488
/// Check same-type constraints within the equivalence class of the
478489
/// given potential archetype.
479490
void checkSameTypeConstraints(
@@ -1029,12 +1040,6 @@ class GenericSignatureBuilder::PotentialArchetype {
10291040
mutable llvm::PointerUnion<PotentialArchetype *, EquivalenceClass *>
10301041
representativeOrEquivClass;
10311042

1032-
/// \brief The layout constraint of this archetype, if specified.
1033-
LayoutConstraint Layout;
1034-
1035-
/// The source of the layout constraint requirement.
1036-
const RequirementSource *LayoutSource = nullptr;
1037-
10381043
/// A stored nested type.
10391044
struct StoredNestedType {
10401045
/// The potential archetypes describing this nested type, all of which
@@ -1254,11 +1259,11 @@ class GenericSignatureBuilder::PotentialArchetype {
12541259
}
12551260

12561261
/// Retrieve the layout constraint of this archetype.
1257-
LayoutConstraint getLayout() const { return Layout; }
1262+
LayoutConstraint getLayout() const {
1263+
if (auto equivClass = getEquivalenceClassIfPresent())
1264+
return equivClass->layout;
12581265

1259-
/// Retrieve the requirement source for the layout constraint requirement.
1260-
const RequirementSource *getLayoutSource() const {
1261-
return LayoutSource;
1266+
return LayoutConstraint();
12621267
}
12631268

12641269
/// Retrieve the set of nested types.

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,30 +2069,19 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
20692069
return false;
20702070
}
20712071

2072-
bool GenericSignatureBuilder::addLayoutRequirement(PotentialArchetype *PAT,
2073-
LayoutConstraint Layout,
2074-
const RequirementSource *Source) {
2075-
// Add the requirement to the representative.
2076-
auto T = PAT->getRepresentative();
2072+
bool GenericSignatureBuilder::addLayoutRequirement(
2073+
PotentialArchetype *PAT,
2074+
LayoutConstraint Layout,
2075+
const RequirementSource *Source) {
2076+
auto equivClass = PAT->getOrCreateEquivalenceClass();
20772077

2078-
if (T->Layout) {
2079-
if (T->Layout == Layout) {
2080-
// Update the source.
2081-
T->LayoutSource = Source;
2082-
return false;
2083-
}
2084-
// There is an existing layout constraint for this archetype.
2085-
Diags.diagnose(Source->getLoc(), diag::mutiple_layout_constraints,
2086-
Layout, T->Layout);
2087-
Diags.diagnose(T->LayoutSource->getLoc(),
2088-
diag::previous_layout_constraint, T->Layout);
2089-
T->setInvalid();
2078+
// Record this layout constraint.
2079+
equivClass->layoutConstraints.push_back({PAT, Layout, Source});
20902080

2091-
return true;
2092-
}
2093-
2094-
T->Layout = Layout;
2095-
T->LayoutSource = Source;
2081+
// Update the layout in the equivalence class, if we didn't have one already.
2082+
// FIXME: Layouts can probably be merged sensibly.
2083+
if (!equivClass->layout)
2084+
equivClass->layout = Layout;
20962085

20972086
return false;
20982087
}
@@ -3052,6 +3041,7 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
30523041
}
30533042

30543043
checkConformanceConstraints(genericParams, archetype);
3044+
checkLayoutConstraints(genericParams, archetype);
30553045
checkSameTypeConstraints(genericParams, archetype);
30563046
});
30573047

@@ -3457,6 +3447,28 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
34573447
}
34583448
}
34593449

3450+
void GenericSignatureBuilder::checkLayoutConstraints(
3451+
ArrayRef<GenericTypeParamType *> genericParams,
3452+
PotentialArchetype *pa) {
3453+
auto equivClass = pa->getEquivalenceClassIfPresent();
3454+
if (!equivClass || !equivClass->layout) return;
3455+
3456+
checkConstraintList<LayoutConstraint>(
3457+
genericParams, equivClass->layoutConstraints,
3458+
[&](const Constraint<LayoutConstraint> &constraint) {
3459+
return constraint.value == equivClass->layout;
3460+
},
3461+
[&](LayoutConstraint layout) {
3462+
if (layout == equivClass->layout)
3463+
return ConstraintRelation::Redundant;
3464+
3465+
return ConstraintRelation::Conflicting;
3466+
},
3467+
diag::conflicting_layout_constraints,
3468+
diag::redundant_layout_constraint,
3469+
diag::previous_layout_constraint);
3470+
}
3471+
34603472
template<typename F>
34613473
void GenericSignatureBuilder::visitPotentialArchetypes(F f) {
34623474
// Stack containing all of the potential archetypes to visit.
@@ -3748,16 +3760,24 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
37483760
if (archetype != archetype->getArchetypeAnchor(*this))
37493761
continue;
37503762

3763+
auto equivClass = rep->getEquivalenceClassIfPresent();
3764+
37513765
// If we have a layout constraint, produce a layout requirement.
3752-
if (LayoutConstraint Layout = archetype->getLayout()) {
3753-
f(RequirementKind::Layout, archetype, Layout,
3754-
archetype->getLayoutSource());
3766+
if (equivClass && equivClass->layout) {
3767+
// Find the best source among the constraints that describe the layout
3768+
// of this type.
3769+
auto bestSource = equivClass->layoutConstraints.front().source;
3770+
for (const auto &constraint : equivClass->layoutConstraints) {
3771+
if (constraint.source->compare(bestSource) < 0)
3772+
bestSource = constraint.source;
3773+
}
3774+
3775+
f(RequirementKind::Layout, archetype, equivClass->layout, bestSource);
37553776
}
37563777

37573778
// Enumerate conformance requirements.
37583779
SmallVector<ProtocolDecl *, 4> protocols;
37593780
DenseMap<ProtocolDecl *, const RequirementSource *> protocolSources;
3760-
auto equivClass = rep->getEquivalenceClassIfPresent();
37613781
if (equivClass) {
37623782
for (const auto &conforms : equivClass->conformsTo) {
37633783
protocols.push_back(conforms.first);

test/attr/attr_specialize.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,11 @@ public func anotherFuncWithTwoGenericParameters<X: P, Y>(x: X, y: Y) {
157157
func funcWithForbiddenSpecializeRequirement<T>(_ t: T) {
158158
}
159159

160-
@_specialize(where T: _Trivial(32), T: _Trivial(64), T: _Trivial, T: _RefCountedObject) // expected-error{{multiple layout constraints cannot be used at the same time: '_Trivial(64)' and '_Trivial(32)'}} expected-note{{previous layout constraint declaration '_Trivial(32)' was here}} expected-error{{multiple layout constraints cannot be used at the same time: '_Trivial' and '_Trivial(32)'}} expected-note{{previous layout constraint declaration '_Trivial(32)' was here}} expected-error{{multiple layout constraints cannot be used at the same time: '_RefCountedObject' and '_Trivial(32)'}} expected-note{{previous layout constraint declaration '_Trivial(32)' was here}}
160+
@_specialize(where T: _Trivial(32), T: _Trivial(64), T: _Trivial, T: _RefCountedObject)
161+
// expected-error@-1{{generic parameter 'T' has conflicting layout constraints '_Trivial(64)' and '_Trivial(32)'}}
162+
// expected-error@-2{{generic parameter 'T' has conflicting layout constraints '_RefCountedObject' and '_Trivial(32)'}}
163+
// expected-error@-3{{generic parameter 'T' has conflicting layout constraints '_Trivial' and '_Trivial(32)'}}
164+
// expected-note@-4 3{{layout constraint constraint 'T' : '_Trivial(32)' written here}}
161165
@_specialize(where Array<T> == Int) // expected-error{{Only requirements on generic parameters are supported by '_specialize' attribute}}
162166
// expected-error@-1{{generic signature requires types 'Array<T>' and 'Int' to be the same}}
163167
@_specialize(where T.Element == Int) // expected-error{{Only requirements on generic parameters are supported by '_specialize' attribute}}

0 commit comments

Comments
 (0)