Skip to content

Calling "super" from a class multiple layers of inheritance deep causes infinite recursion #353

@thatcosmonaut

Description

@thatcosmonaut

my_class.ts

export class MyClass {
    do_thing() {
        let x = 1 + 2
    }
}

sub_my_class.ts

import { MyClass } from "./my_class";

export class SubMyClass extends MyClass {
    do_thing() {
        super.do_thing()
    }
}

sub_sub_my_class.ts

import { SubMyClass } from "./sub_my_class";

export class SubSubMyClass extends SubMyClass {
    do_thing() {
        super.do_thing()
    }
}

main.ts

import { SubSubMyClass } from "./sub_sub_my_class";

const my_class = new SubSubMyClass();

my_class.do_thing();

This transpiles to:
my_class.lua

local exports = exports or {}
local MyClass = MyClass or {}
MyClass.__index = MyClass
function MyClass.new(construct, ...)
    local self = setmetatable({}, MyClass)
    if construct and MyClass.constructor then MyClass.constructor(self, ...) end
    return self
end
function MyClass.constructor(self)
end
function MyClass.do_thing(self)
    local x = 1+2;
end
exports.MyClass = MyClass
return exports

sub_my_class.lua

local exports = exports or {}
local my_class0 = require("src.my_class")
local MyClass = my_class0.MyClass
local SubMyClass = SubMyClass or MyClass.new()
SubMyClass.__index = SubMyClass
SubMyClass.__base = MyClass
function SubMyClass.new(construct, ...)
    local self = setmetatable({}, SubMyClass)
    if construct and SubMyClass.constructor then SubMyClass.constructor(self, ...) end
    return self
end
function SubMyClass.do_thing(self)
    self.__base.do_thing(self);
end
exports.SubMyClass = SubMyClass
return exports

sub_sub_my_class.lua

local exports = exports or {}
local sub_my_class0 = require("src.sub_my_class")
local SubMyClass = sub_my_class0.SubMyClass
local SubSubMyClass = SubSubMyClass or SubMyClass.new()
SubSubMyClass.__index = SubSubMyClass
SubSubMyClass.__base = SubMyClass
function SubSubMyClass.new(construct, ...)
    local self = setmetatable({}, SubSubMyClass)
    if construct and SubSubMyClass.constructor then SubSubMyClass.constructor(self, ...) end
    return self
end
function SubSubMyClass.do_thing(self)
    self.__base.do_thing(self);
end
exports.SubSubMyClass = SubSubMyClass
return exports

main.lua

local sub_sub_my_class0 = require("src.sub_sub_my_class")
local SubSubMyClass = sub_sub_my_class0.SubSubMyClass
local my_class = SubSubMyClass.new(true);
my_class:do_thing();

lua build/main.lua throws the following:

lua: ./src/sub_my_class.lua:13: stack overflow
stack traceback:
        ./src/sub_my_class.lua:13: in field 'do_thing'
        ./src/sub_my_class.lua:13: in field 'do_thing'
        ./src/sub_my_class.lua:13: in field 'do_thing'
        ./src/sub_my_class.lua:13: in field 'do_thing'
        ./src/sub_my_class.lua:13: in field 'do_thing'
        ./src/sub_my_class.lua:13: in field 'do_thing'

What we actually want is for the transpilation to produce:
sub_my_class.lua

function SubMyClass.do_thing(self)
    MyClass.do_thing(self);
end

because self.__base when called from the child refers to the child's base, which is the current class, which causes infinite recursion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions