Skip to content

VTableSpecializer: fix a crash for methods which have their own generic parameters #75836

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
Aug 22, 2024
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
34 changes: 33 additions & 1 deletion lib/SILOptimizer/Transforms/VTableSpecializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,26 @@ static bool specializeVTablesOfSuperclasses(SILModule &module,
return changed;
}

static SubstitutionMap getMethodSubs(SILFunction *method, SubstitutionMap classContextSubs) {
GenericSignature genericSig =
method->getLoweredFunctionType()->getInvocationGenericSignature();

if (!genericSig || genericSig->areAllParamsConcrete())
return SubstitutionMap();

return SubstitutionMap::get(genericSig,
QuerySubstitutionMap{classContextSubs},
LookUpConformanceInModule());
}

static bool hasInvalidConformance(SubstitutionMap subs) {
for (auto substConf : subs.getConformances()) {
if (substConf.isInvalid())
return true;
}
return false;
}

SILVTable *swift::specializeVTableForType(SILType classTy, SILModule &module,
SILTransform *transform) {
CanType astType = classTy.getASTType();
Expand Down Expand Up @@ -182,8 +202,20 @@ SILVTable *swift::specializeVTableForType(SILType classTy, SILModule &module,

for (const SILVTableEntry &entry : origVtable->getEntries()) {
SILFunction *origMethod = entry.getImplementation();

auto methodSubs = getMethodSubs(origMethod, subs);

// If the resulting substitution map is not valid this means that the method
// itself has generic parameters.
if (hasInvalidConformance(methodSubs)) {
module.getASTContext().Diags.diagnose(
entry.getMethod().getDecl()->getLoc(), diag::non_final_generic_class_function);
continue;
}

SILFunction *specializedMethod =
specializeVTableMethod(origMethod, subs, module, transform);
specializeVTableMethod(origMethod, methodSubs, module, transform);

newEntries.push_back(SILVTableEntry(entry.getMethod(), specializedMethod,
entry.getKind(),
entry.isNonOverridden()));
Expand Down
20 changes: 20 additions & 0 deletions test/embedded/classes-non-final-method-no-stdlib.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,23 @@ public class MyClass {
func foo<T>(t: T) { } // expected-error {{classes cannot have non-final generic fuctions in embedded Swift}}
func bar() { }
}

final class C2<Element> {
// TODO: this shouldn't be a problem because the class is final
init<T>(x: T) { } // expected-error {{classes cannot have non-final generic fuctions in embedded Swift}}
}

struct S {}

func testit2() -> C2<S> {
return C2(x: S())
}

open class C3<X> {
public func foo<T>(t: T) {} // expected-error {{classes cannot have non-final generic fuctions in embedded Swift}}
}

func testit3() -> C3<S> {
return C3<S>()
}

51 changes: 51 additions & 0 deletions test/embedded/generic-classes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,52 @@ public func makeInner() -> Outer<Int>.Inner {
return Outer<Int>.Inner()
}

final class List<Element> where Element: ~Copyable {
init(x: Element) where Element: Copyable { }
}

func testList() -> List<Int> {
return List(x: 0)
}

open class OpenClass<Element> where Element: ~Copyable {
public func foo(x: Element) where Element: Copyable { }
}

func testOpenClass() -> OpenClass<Int> {
return OpenClass()
}


class Base<T> {
func foo(_: T) {}
}

class Derived<T>: Base<Array<T>> {}

func testBaseDerived() -> Derived<Int> {
return Derived()
}

class Base2<T> {
func foo(_: T) {}
}

class Derived2<T>: Base2<(T, T)> {}

func testBaseDerived2() -> Derived2<Int> {
return Derived2()
}

class Base3<T> {
func foo(_: T) {}
}
class Derived3<T, U>: Base3<(T, U)> {}

func testBaseDerived3() -> Derived3<Int, Bool> {
return Derived3()
}

@main
struct Main {
static func main() {
Expand All @@ -56,6 +102,11 @@ struct Main {
let x = SubClass2()
x.test()
makeInner().foo()
testList()
testOpenClass()
testBaseDerived()
testBaseDerived2()
testBaseDerived3()
}
}

Expand Down