Distinguish conformance and superclass generic requirements.

As part of this, use a different enum for parsed generic requirements.

NFC except that I noticed that ASTWalker wasn't visiting the second
type in a conformance constraint; fixing this seems to have no effect
beyond producing better IDE annotations.
This commit is contained in:
John McCall
2016-01-11 16:02:48 -08:00
parent 0b8468d36b
commit 1f3b3142b4
25 changed files with 246 additions and 196 deletions

View File

@@ -885,6 +885,20 @@ void *allocateMemoryForDecl(AllocatorTy &allocator, size_t baseSize,
return mem;
}
enum class RequirementReprKind : unsigned int {
/// A type bound T : P, where T is a type that depends on a generic
/// parameter and P is some type that should bound T, either as a concrete
/// supertype or a protocol to which T must conform.
TypeConstraint,
/// A same-type requirement T == U, where T and U are types that shall be
/// equivalent.
SameType,
// Note: there is code that packs this enum in a 2-bit bitfield. Audit users
// when adding enumerators.
};
/// \brief A single requirement in a 'where' clause, which places additional
/// restrictions on the generic parameters or associated types of a generic
/// function, type, or protocol.
@@ -895,14 +909,14 @@ void *allocateMemoryForDecl(AllocatorTy &allocator, size_t baseSize,
/// \c GenericParamList assumes these are POD-like.
class RequirementRepr {
SourceLoc SeparatorLoc;
RequirementKind Kind : 2;
RequirementReprKind Kind : 2;
bool Invalid : 1;
TypeLoc Types[2];
/// Set during deserialization; used to print out the requirements accurately
/// for the generated interface.
StringRef AsWrittenString;
RequirementRepr(SourceLoc SeparatorLoc, RequirementKind Kind,
RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind,
TypeLoc FirstType, TypeLoc SecondType)
: SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false),
Types{FirstType, SecondType} { }
@@ -910,7 +924,7 @@ class RequirementRepr {
void printImpl(raw_ostream &OS, bool AsWritten) const;
public:
/// \brief Construct a new conformance requirement.
/// \brief Construct a new type-constraint requirement.
///
/// \param Subject The type that must conform to the given protocol or
/// composition, or be a subclass of the given class type.
@@ -918,10 +932,10 @@ public:
/// this requirement was implied.
/// \param Constraint The protocol or protocol composition to which the
/// subject must conform, or superclass from which the subject must inherit.
static RequirementRepr getConformance(TypeLoc Subject,
SourceLoc ColonLoc,
TypeLoc Constraint) {
return { ColonLoc, RequirementKind::Conformance, Subject, Constraint };
static RequirementRepr getTypeConstraint(TypeLoc Subject,
SourceLoc ColonLoc,
TypeLoc Constraint) {
return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint };
}
/// \brief Construct a new same-type requirement.
@@ -931,13 +945,13 @@ public:
/// an invalid location if this requirement was implied.
/// \param SecondType The second type.
static RequirementRepr getSameType(TypeLoc FirstType,
SourceLoc EqualLoc,
TypeLoc SecondType) {
return { EqualLoc, RequirementKind::SameType, FirstType, SecondType };
SourceLoc EqualLoc,
TypeLoc SecondType) {
return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType };
}
/// \brief Determine the kind of requirement
RequirementKind getKind() const { return Kind; }
RequirementReprKind getKind() const { return Kind; }
/// \brief Determine whether this requirement is invalid.
bool isInvalid() const { return Invalid; }
@@ -945,98 +959,98 @@ public:
/// \brief Mark this requirement invalid.
void setInvalid() { Invalid = true; }
/// \brief For a conformance requirement, return the subject of the
/// \brief For a type-bound requirement, return the subject of the
/// conformance relationship.
Type getSubject() const {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[0].getType();
}
TypeRepr *getSubjectRepr() const {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[0].getTypeRepr();
}
TypeLoc &getSubjectLoc() {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[0];
}
const TypeLoc &getSubjectLoc() const {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[0];
}
/// \brief For a conformance requirement, return the protocol or to which
/// \brief For a type-bound requirement, return the protocol or to which
/// the subject conforms or superclass it inherits.
Type getConstraint() const {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[1].getType();
}
TypeLoc &getConstraintLoc() {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[1];
}
const TypeLoc &getConstraintLoc() const {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return Types[1];
}
/// \brief Retrieve the location of the ':' in an explicitly-written
/// conformance requirement.
SourceLoc getColonLoc() const {
assert(getKind() == RequirementKind::Conformance);
assert(getKind() == RequirementReprKind::TypeConstraint);
return SeparatorLoc;
}
/// \brief Retrieve the first type of a same-type requirement.
Type getFirstType() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[0].getType();
}
TypeRepr *getFirstTypeRepr() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[0].getTypeRepr();
}
TypeLoc &getFirstTypeLoc() {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[0];
}
const TypeLoc &getFirstTypeLoc() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[0];
}
/// \brief Retrieve the second type of a same-type requirement.
Type getSecondType() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[1].getType();
}
TypeRepr *getSecondTypeRepr() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[1].getTypeRepr();
}
TypeLoc &getSecondTypeLoc() {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[1];
}
const TypeLoc &getSecondTypeLoc() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return Types[1];
}
/// \brief Retrieve the location of the '==' in an explicitly-written
/// same-type requirement.
SourceLoc getEqualLoc() const {
assert(getKind() == RequirementKind::SameType);
assert(getKind() == RequirementReprKind::SameType);
return SeparatorLoc;
}