Skip to content

Commit 0bc3dec

Browse files
committed
Sema: New TypeBase::adjustSuperclassMemberDeclType() method
This generalizes some code in Sema to fix the problem where generic method overrides don't work if the base class is more or less generic than the derived class. The problem here was that we were checking types for equality when matching overrides, which failed if generic parameters had different depths. Now, map the generic parameters of the base class member to the generic signature of the derived member, so that the equality check can succeed. Since SIL type lowering needs to perform a similar check, move this from Sema to a method on TypeBase to complement the existing getTypeOfMember(). Note that getTypeOfMember() still does a superclass walk, but ideally this will go away soon.
1 parent af8d13e commit 0bc3dec

File tree

3 files changed

+58
-34
lines changed

3 files changed

+58
-34
lines changed

include/swift/AST/Types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,14 @@ class alignas(1 << TypeAlignInBits) TypeBase {
866866
Type getTypeOfMember(ModuleDecl *module, Type memberType,
867867
const DeclContext *memberDC);
868868

869+
/// Get the type of a superclass member as seen from the subclass,
870+
/// substituting generic parameters, dynamic Self return, and the
871+
/// 'self' argument type as appropriate.
872+
Type adjustSuperclassMemberDeclType(const ValueDecl *decl,
873+
const ValueDecl *parentDecl,
874+
Type memberType,
875+
LazyResolver *resolver);
876+
869877
/// Return T if this type is Optional<T>; otherwise, return the null type.
870878
Type getOptionalObjectType();
871879

lib/AST/Type.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3053,14 +3053,56 @@ Type TypeBase::getTypeOfMember(Module *module, Type memberType,
30533053
return memberType;
30543054

30553055
// Compute the set of member substitutions to apply.
3056-
TypeSubstitutionMap substitutions = getMemberSubstitutions(memberDC);
3056+
auto substitutions = getMemberSubstitutions(memberDC);
30573057
if (substitutions.empty())
30583058
return memberType;
30593059

30603060
// Perform the substitutions.
30613061
return memberType.subst(module, substitutions, None);
30623062
}
30633063

3064+
Type TypeBase::adjustSuperclassMemberDeclType(const ValueDecl *decl,
3065+
const ValueDecl *parentDecl,
3066+
Type memberType,
3067+
LazyResolver *resolver) {
3068+
auto *DC = parentDecl->getDeclContext();
3069+
auto superclass = getSuperclassForDecl(
3070+
DC->getAsClassOrClassExtensionContext(), resolver);
3071+
auto subs = superclass->getMemberSubstitutions(DC);
3072+
3073+
if (auto *parentFunc = dyn_cast<AbstractFunctionDecl>(parentDecl)) {
3074+
if (auto *func = dyn_cast<AbstractFunctionDecl>(decl)) {
3075+
auto *genericParams = func->getGenericParams();
3076+
auto *parentParams = parentFunc->getGenericParams();
3077+
if (genericParams && parentParams &&
3078+
genericParams->size() == parentParams->size()) {
3079+
for (unsigned i = 0, e = genericParams->size(); i < e; i++) {
3080+
auto paramTy = parentParams->getParams()[i]->getDeclaredInterfaceType()
3081+
->getCanonicalType().getPointer();
3082+
subs[paramTy] = genericParams->getParams()[i]
3083+
->getDeclaredInterfaceType();
3084+
}
3085+
}
3086+
}
3087+
}
3088+
3089+
auto type = memberType.subst(parentDecl->getModuleContext(), subs);
3090+
3091+
if (isa<AbstractFunctionDecl>(parentDecl)) {
3092+
type = type->replaceSelfParameterType(this);
3093+
if (auto func = dyn_cast<FuncDecl>(parentDecl)) {
3094+
if (func->hasDynamicSelf()) {
3095+
type = type->replaceCovariantResultType(this,
3096+
func->getNumParameterLists());
3097+
}
3098+
} else if (isa<ConstructorDecl>(parentDecl)) {
3099+
type = type->replaceCovariantResultType(this, /*uncurryLevel=*/2);
3100+
}
3101+
}
3102+
3103+
return type;
3104+
}
3105+
30643106
Identifier DependentMemberType::getName() const {
30653107
if (NameOrAssocType.is<Identifier>())
30663108
return NameOrAssocType.get<Identifier>();

lib/Sema/TypeCheckDecl.cpp

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5014,32 +5014,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
50145014

50155015
void visitModuleDecl(ModuleDecl *) { }
50165016

5017-
/// Adjust the type of the given declaration to appear as if it were
5018-
/// in the given subclass of its actual declared class.
5019-
static Type adjustSuperclassMemberDeclType(TypeChecker &TC,
5020-
const ValueDecl *decl,
5021-
Type subclass) {
5022-
ClassDecl *superclassDecl =
5023-
decl->getDeclContext()->getDeclaredTypeInContext()
5024-
->getClassOrBoundGenericClass();
5025-
auto superclass = subclass;
5026-
while (superclass->getClassOrBoundGenericClass() != superclassDecl)
5027-
superclass = TC.getSuperClassOf(superclass);
5028-
auto type = TC.substMemberTypeWithBase(decl->getModuleContext(), decl,
5029-
superclass,
5030-
/*isTypeReference=*/false);
5031-
if (auto func = dyn_cast<FuncDecl>(decl)) {
5032-
if (func->hasDynamicSelf()) {
5033-
type = type->replaceCovariantResultType(subclass,
5034-
func->getNumParameterLists());
5035-
}
5036-
} else if (isa<ConstructorDecl>(decl)) {
5037-
type = type->replaceCovariantResultType(subclass, /*uncurryLevel=*/2);
5038-
}
5039-
5040-
return type;
5041-
}
5042-
50435017
/// Perform basic checking to determine whether a declaration can override a
50445018
/// declaration in a superclass.
50455019
static bool areOverrideCompatibleSimple(ValueDecl *decl,
@@ -5093,15 +5067,15 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
50935067

50945068
static bool
50955069
diagnoseMismatchedOptionals(TypeChecker &TC,
5096-
const Decl *member,
5070+
const ValueDecl *member,
50975071
const ParameterList *params,
50985072
TypeLoc resultTL,
50995073
const ValueDecl *parentMember,
51005074
Type owningTy,
51015075
bool treatIUOResultAsError) {
51025076
bool emittedError = false;
5103-
Type plainParentTy = adjustSuperclassMemberDeclType(TC, parentMember,
5104-
owningTy);
5077+
Type plainParentTy = owningTy->adjustSuperclassMemberDeclType(
5078+
member, parentMember, parentMember->getInterfaceType(), &TC);
51055079
const auto *parentTy = plainParentTy->castTo<AnyFunctionType>();
51065080
if (isa<AbstractFunctionDecl>(parentMember))
51075081
parentTy = parentTy->getResult()->castTo<AnyFunctionType>();
@@ -5538,8 +5512,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
55385512

55395513
// Check whether the types are identical.
55405514
// FIXME: It's wrong to use the uncurried types here for methods.
5541-
auto parentDeclTy = adjustSuperclassMemberDeclType(TC, parentDecl,
5542-
owningTy);
5515+
auto parentDeclTy = owningTy->adjustSuperclassMemberDeclType(
5516+
decl, parentDecl, parentDecl->getInterfaceType(), &TC);
55435517
parentDeclTy = parentDeclTy->getUnlabeledType(TC.Context);
55445518
if (method) {
55455519
parentDeclTy = parentDeclTy->castTo<AnyFunctionType>()->getResult();
@@ -5807,8 +5781,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
58075781
}
58085782
} else if (auto property = dyn_cast_or_null<VarDecl>(abstractStorage)) {
58095783
auto propertyTy = property->getInterfaceType();
5810-
auto parentPropertyTy = adjustSuperclassMemberDeclType(TC, matchDecl,
5811-
superclass);
5784+
auto parentPropertyTy = superclass->adjustSuperclassMemberDeclType(
5785+
decl, matchDecl, matchDecl->getInterfaceType(), &TC);
58125786

58135787
if (!propertyTy->canOverride(parentPropertyTy,
58145788
OverrideMatchMode::Strict,

0 commit comments

Comments
 (0)