Skip to content

Commit 9ad340e

Browse files
authored
Merge pull request #8241 from DougGregor/all-layout-constraints
2 parents 7811dc7 + 5aa51e9 commit 9ad340e

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)