AST: Lazily map archetype superclass into context

We don't really want to support this, at least not yet, but there
are ways to sneak it past the diagnostic that are hard to close.

Fixes rdar://problem/135348472.
This commit is contained in:
Slava Pestov
2024-09-13 13:51:42 -04:00
parent 08bb0017f5
commit 4afdc9d0bf
4 changed files with 71 additions and 20 deletions

View File

@@ -6580,11 +6580,7 @@ public:
bool requiresClass() const;
/// Retrieve the superclass of this type, if such a requirement exists.
Type getSuperclass() const {
if (!Bits.ArchetypeType.HasSuperclass) return Type();
return *getSubclassTrailingObjects<Type>();
}
Type getSuperclass() const;
/// Retrieve the layout constraint of this type, if such a requirement exists.
LayoutConstraint getLayoutConstraint() const {

View File

@@ -404,14 +404,6 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
// requirements.
auto requirements = genericSig->getLocalRequirements(reducedType);
// Substitute into the superclass.
Type superclass = requirements.superclass;
if (superclass && superclass->hasTypeParameter()) {
superclass = mapTypeIntoContext(superclass);
if (superclass->is<ErrorType>())
superclass = Type();
}
Type result;
auto sugaredType = genericSig->getSugaredType(reducedType);
@@ -422,11 +414,13 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
if (rootGP->isParameterPack()) {
result = PackArchetypeType::get(ctx, this, sugaredType,
requirements.packShape,
requirements.protos, superclass,
requirements.protos,
requirements.superclass,
requirements.layout);
} else {
result = PrimaryArchetypeType::getNew(ctx, this, sugaredType,
requirements.protos, superclass,
requirements.protos,
requirements.superclass,
requirements.layout);
}
@@ -442,7 +436,8 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
}
result = OpaqueTypeArchetypeType::getNew(this, sugaredType,
requirements.protos, superclass,
requirements.protos,
requirements.superclass,
requirements.layout);
break;
}
@@ -468,10 +463,12 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
protos.push_back(proto);
result = OpenedArchetypeType::getNew(this, sugaredType, protos,
superclass, requirements.layout);
requirements.superclass,
requirements.layout);
} else {
result = OpenedArchetypeType::getNew(this, sugaredType,
requirements.protos, superclass,
requirements.protos,
requirements.superclass,
requirements.layout);
}
@@ -485,7 +482,8 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
}
result = ElementArchetypeType::getNew(this, sugaredType,
requirements.protos, superclass,
requirements.protos,
requirements.superclass,
requirements.layout);
break;
}

View File

@@ -3450,6 +3450,14 @@ bool ArchetypeType::requiresClass() const {
return false;
}
Type ArchetypeType::getSuperclass() const {
if (!Bits.ArchetypeType.HasSuperclass) return Type();
auto *genericEnv = getGenericEnvironment();
return genericEnv->mapTypeIntoContext(
*getSubclassTrailingObjects<Type>());
}
Type ArchetypeType::getValueType() const {
if (auto gp = getInterfaceType()->getAs<GenericTypeParamType>())
return gp->getValueType();
@@ -3506,7 +3514,12 @@ static RecursiveTypeProperties archetypeProperties(
}
}
if (superclass) properties |= superclass->getRecursiveProperties();
if (superclass) {
auto superclassProps = superclass->getRecursiveProperties();
superclassProps.removeHasTypeParameter();
superclassProps.removeHasDependentMember();
properties |= superclassProps;
}
return properties;
}

View File

@@ -0,0 +1,44 @@
// RUN: %target-typecheck-verify-swift
// While we disallow explicitly-stated requirements like
// `T: C<T>`, there are ways to sneak them past the
// diagnostic.
//
// We could relax the diagnostic eventually by rejecting
// the truly invalid cases, where the superclass contains
// a member type of a conformance made redundant by the
// superclass requirement itself.
class C<T> {
var t: T
init(t: T) {
self.t = t
}
}
protocol P1 {
associatedtype A: C<B.A>
associatedtype B: P1
}
func f<T: P1>(_: T, t: T.A) -> C<T.B.B.B.B.A> {
return t.t.t.t
}
protocol P2 {
associatedtype A: C<B>
associatedtype B
}
extension P2 where Self == A {
func f() -> C<B> {
return self
}
}
extension P2 where Self == A, A == B {
func g() -> C<Self> {
return self
}
}