Skip to content

[GSB] Keep track of all layout constraints. #8241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 21, 2017
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
12 changes: 8 additions & 4 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1591,11 +1591,15 @@ NOTE(superclass_redundancy_here,none,
"superclass constraint %1 : %2 %select{written here|implied here}0",
(bool, Type, Type))

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

ERROR(generic_param_access,none,
"%0 %select{must be declared %select{"
Expand Down
25 changes: 15 additions & 10 deletions include/swift/AST/GenericSignatureBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ class GenericSignatureBuilder {
/// Superclass constraints written within this equivalence class.
std::vector<ConcreteConstraint> superclassConstraints;

/// \The layout constraint for this equivalence class.
LayoutConstraint layout;

/// Layout constraints written within this equivalence class.
std::vector<Constraint<LayoutConstraint>> layoutConstraints;

/// The members of the equivalence class.
TinyPtrVector<PotentialArchetype *> members;

Expand Down Expand Up @@ -474,6 +480,11 @@ class GenericSignatureBuilder {
ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *pa);

/// Check layout constraints within the equivalence class of the given
/// potential archetype.
void checkLayoutConstraints(ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *pa);

/// Check same-type constraints within the equivalence class of the
/// given potential archetype.
void checkSameTypeConstraints(
Expand Down Expand Up @@ -1029,12 +1040,6 @@ class GenericSignatureBuilder::PotentialArchetype {
mutable llvm::PointerUnion<PotentialArchetype *, EquivalenceClass *>
representativeOrEquivClass;

/// \brief The layout constraint of this archetype, if specified.
LayoutConstraint Layout;

/// The source of the layout constraint requirement.
const RequirementSource *LayoutSource = nullptr;

/// A stored nested type.
struct StoredNestedType {
/// The potential archetypes describing this nested type, all of which
Expand Down Expand Up @@ -1254,11 +1259,11 @@ class GenericSignatureBuilder::PotentialArchetype {
}

/// Retrieve the layout constraint of this archetype.
LayoutConstraint getLayout() const { return Layout; }
LayoutConstraint getLayout() const {
if (auto equivClass = getEquivalenceClassIfPresent())
return equivClass->layout;

/// Retrieve the requirement source for the layout constraint requirement.
const RequirementSource *getLayoutSource() const {
return LayoutSource;
return LayoutConstraint();
}

/// Retrieve the set of nested types.
Expand Down
72 changes: 46 additions & 26 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2069,30 +2069,19 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
return false;
}

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

if (T->Layout) {
if (T->Layout == Layout) {
// Update the source.
T->LayoutSource = Source;
return false;
}
// There is an existing layout constraint for this archetype.
Diags.diagnose(Source->getLoc(), diag::mutiple_layout_constraints,
Layout, T->Layout);
Diags.diagnose(T->LayoutSource->getLoc(),
diag::previous_layout_constraint, T->Layout);
T->setInvalid();
// Record this layout constraint.
equivClass->layoutConstraints.push_back({PAT, Layout, Source});

return true;
}

T->Layout = Layout;
T->LayoutSource = Source;
// Update the layout in the equivalence class, if we didn't have one already.
// FIXME: Layouts can probably be merged sensibly.
if (!equivClass->layout)
equivClass->layout = Layout;

return false;
}
Expand Down Expand Up @@ -3052,6 +3041,7 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
}

checkConformanceConstraints(genericParams, archetype);
checkLayoutConstraints(genericParams, archetype);
checkSameTypeConstraints(genericParams, archetype);
});

Expand Down Expand Up @@ -3457,6 +3447,28 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
}
}

void GenericSignatureBuilder::checkLayoutConstraints(
ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *pa) {
auto equivClass = pa->getEquivalenceClassIfPresent();
if (!equivClass || !equivClass->layout) return;

checkConstraintList<LayoutConstraint>(
genericParams, equivClass->layoutConstraints,
[&](const Constraint<LayoutConstraint> &constraint) {
return constraint.value == equivClass->layout;
},
[&](LayoutConstraint layout) {
if (layout == equivClass->layout)
return ConstraintRelation::Redundant;

return ConstraintRelation::Conflicting;
},
diag::conflicting_layout_constraints,
diag::redundant_layout_constraint,
diag::previous_layout_constraint);
}

template<typename F>
void GenericSignatureBuilder::visitPotentialArchetypes(F f) {
// Stack containing all of the potential archetypes to visit.
Expand Down Expand Up @@ -3748,16 +3760,24 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
if (archetype != archetype->getArchetypeAnchor(*this))
continue;

auto equivClass = rep->getEquivalenceClassIfPresent();

// If we have a layout constraint, produce a layout requirement.
if (LayoutConstraint Layout = archetype->getLayout()) {
f(RequirementKind::Layout, archetype, Layout,
archetype->getLayoutSource());
if (equivClass && equivClass->layout) {
// Find the best source among the constraints that describe the layout
// of this type.
auto bestSource = equivClass->layoutConstraints.front().source;
for (const auto &constraint : equivClass->layoutConstraints) {
if (constraint.source->compare(bestSource) < 0)
bestSource = constraint.source;
}

f(RequirementKind::Layout, archetype, equivClass->layout, bestSource);
}

// Enumerate conformance requirements.
SmallVector<ProtocolDecl *, 4> protocols;
DenseMap<ProtocolDecl *, const RequirementSource *> protocolSources;
auto equivClass = rep->getEquivalenceClassIfPresent();
if (equivClass) {
for (const auto &conforms : equivClass->conformsTo) {
protocols.push_back(conforms.first);
Expand Down
6 changes: 5 additions & 1 deletion test/attr/attr_specialize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ public func anotherFuncWithTwoGenericParameters<X: P, Y>(x: X, y: Y) {
func funcWithForbiddenSpecializeRequirement<T>(_ t: T) {
}

@_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}}
@_specialize(where T: _Trivial(32), T: _Trivial(64), T: _Trivial, T: _RefCountedObject)
// expected-error@-1{{generic parameter 'T' has conflicting layout constraints '_Trivial(64)' and '_Trivial(32)'}}
// expected-error@-2{{generic parameter 'T' has conflicting layout constraints '_RefCountedObject' and '_Trivial(32)'}}
// expected-error@-3{{generic parameter 'T' has conflicting layout constraints '_Trivial' and '_Trivial(32)'}}
// expected-note@-4 3{{layout constraint constraint 'T' : '_Trivial(32)' written here}}
@_specialize(where Array<T> == Int) // expected-error{{Only requirements on generic parameters are supported by '_specialize' attribute}}
// expected-error@-1{{generic signature requires types 'Array<T>' and 'Int' to be the same}}
@_specialize(where T.Element == Int) // expected-error{{Only requirements on generic parameters are supported by '_specialize' attribute}}
Expand Down