Skip to content

Commit 1ca1198

Browse files
committed
Fix bugs in method invocation logic for static method calls, and in static field lookup logic.
1 parent d4d4bf1 commit 1ca1198

File tree

4 files changed

+31
-37
lines changed

4 files changed

+31
-37
lines changed

src/compiler/__tests__/tests/methodOverriding.test.ts

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,6 @@ const testCases: testCase[] = [
4949
`,
5050
expectedLines: ['Child display']
5151
},
52-
{
53-
comment: 'Method overriding with return type covariance',
54-
program: `
55-
class Parent {
56-
public Number getValue() {
57-
return 10;
58-
}
59-
}
60-
class Child extends Parent {
61-
public Integer getValue() {
62-
return 20;
63-
}
64-
}
65-
public class Main {
66-
public static void main(String[] args) {
67-
Parent ref = new Child();
68-
System.out.println(ref.getValue()); // 20
69-
}
70-
}
71-
`,
72-
expectedLines: ['20']
73-
},
7452
{
7553
comment: 'Overriding with multiple levels of inheritance',
7654
program: `
@@ -141,7 +119,7 @@ const testCases: testCase[] = [
141119
}
142120
}
143121
class Child extends Parent {
144-
// public void show() {} // Uncommenting should cause compilation error
122+
public void show() {} // Uncommenting should cause compilation error
145123
}
146124
public class Main {
147125
public static void main(String[] args) {
@@ -177,12 +155,14 @@ const testCases: testCase[] = [
177155
}
178156
public class Main {
179157
public static void main(String[] args) {
180-
A ref = new D();
181-
ref.test(); // D test
158+
A ref1 = new D();
159+
B ref2 = new C();
160+
ref1.test(); // D test
161+
ref2.test(); // C test
182162
}
183163
}
184164
`,
185-
expectedLines: ['D test']
165+
expectedLines: ['D test', 'C test']
186166
},
187167
{
188168
comment: 'Overriding private methods (should not override, treated as new method)',

src/compiler/code-generator.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ const codeGenerators: { [type: string]: (node: Node, cg: CodeGenerator) => Compi
793793

794794
// --- Handle super. calls ---
795795
if (n.identifier.startsWith('super.')) {
796-
candidateMethods = cg.symbolTable.queryMethod(n.identifier.slice(6)).pop() as MethodInfos
796+
candidateMethods = cg.symbolTable.queryMethod(n.identifier.slice(6)) as MethodInfos
797797
candidateMethods.filter(method =>
798798
method.className == cg.symbolTable.queryClass(cg.currentClass).parentClassName)
799799
cg.code.push(OPCODE.ALOAD, 0);
@@ -802,9 +802,18 @@ const codeGenerators: { [type: string]: (node: Node, cg: CodeGenerator) => Compi
802802
else if (n.identifier.includes('.')) {
803803
const lastDot = n.identifier.lastIndexOf('.');
804804
const receiverStr = n.identifier.slice(0, lastDot);
805-
const recvRes = compile({ kind: 'ExpressionName', name: receiverStr }, cg);
806-
maxStack = Math.max(maxStack, recvRes.stackSize);
807-
candidateMethods = cg.symbolTable.queryMethod(n.identifier).pop() as MethodInfos
805+
806+
if (receiverStr === 'this') {
807+
candidateMethods = cg.symbolTable.queryMethod(n.identifier.slice(5)) as MethodInfos
808+
console.debug(candidateMethods)
809+
candidateMethods.filter(method =>
810+
method.className == cg.currentClass)
811+
cg.code.push(OPCODE.ALOAD, 0);
812+
} else {
813+
const recvRes = compile({ kind: 'ExpressionName', name: receiverStr }, cg);
814+
maxStack = Math.max(maxStack, recvRes.stackSize);
815+
candidateMethods = cg.symbolTable.queryMethod(n.identifier).pop() as MethodInfos
816+
}
808817
}
809818
// --- Handle unqualified calls ---
810819
else {
@@ -1210,7 +1219,12 @@ const codeGenerators: { [type: string]: (node: Node, cg: CodeGenerator) => Compi
12101219
}
12111220
}
12121221

1213-
const info = cg.symbolTable.queryVariable(name)
1222+
let info: VariableInfo | SymbolInfo[]
1223+
try {
1224+
info = cg.symbolTable.queryVariable(name)
1225+
} catch (e) {
1226+
return { stackSize: 1, resultType: 'Ljava/lang/Class;' };
1227+
}
12141228
if (Array.isArray(info)) {
12151229
const fieldInfos = info
12161230
for (let i = 0; i < fieldInfos.length; i++) {
@@ -1223,7 +1237,7 @@ const codeGenerators: { [type: string]: (node: Node, cg: CodeGenerator) => Compi
12231237
}
12241238
const fieldInfo = fieldInfos[i] as FieldInfo
12251239
const field = cg.constantPoolManager.indexFieldrefInfo(
1226-
fieldInfo.typeName,
1240+
fieldInfo.parentClassName,
12271241
fieldInfo.name,
12281242
fieldInfo.typeDescriptor
12291243
)

src/compiler/compiler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export class Compiler {
173173
this.symbolTable.insertFieldInfo({
174174
name: v.variableDeclaratorId,
175175
accessFlags: accessFlags,
176-
parentClassName: this.parentClassName,
176+
parentClassName: this.className,
177177
typeName: fullType,
178178
typeDescriptor: typeDescriptor
179179
})

src/compiler/symbol-table.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export class SymbolTable {
231231
insertVariableInfo(info: VariableInfo) {
232232
const key = generateSymbol(info.name, SymbolType.VARIABLE)
233233

234-
for (let i = this.curIdx; i > this.curClassIdx; i--) {
234+
for (let i = this.curIdx; i >= this.curClassIdx; i--) {
235235
if (this.tables[i].has(key)) {
236236
throw new SymbolRedeclarationError(info.name)
237237
}
@@ -312,7 +312,7 @@ export class SymbolTable {
312312
tokens.forEach((token, i) => {
313313
if (i === 0) {
314314
const key1 = generateSymbol(token, SymbolType.VARIABLE)
315-
for (let i = this.curIdx; i > this.curClassIdx; i--) {
315+
for (let i = this.curIdx; i >= this.curClassIdx; i--) {
316316
if (this.tables[i].has(key1)) {
317317
const node = this.tables[i].get(key1)!
318318
token = (node.info as VariableInfo).typeName
@@ -359,7 +359,7 @@ export class SymbolTable {
359359
}
360360

361361
const key1 = generateSymbol(name, SymbolType.VARIABLE)
362-
for (let i = this.curIdx; i > this.curClassIdx; i--) {
362+
for (let i = this.curIdx; i >= this.curClassIdx; i--) {
363363
if (this.tables[i].has(key1)) {
364364
throw new InvalidMethodCallError(name)
365365
}
@@ -391,7 +391,7 @@ export class SymbolTable {
391391
const key1 = generateSymbol(name, SymbolType.VARIABLE)
392392
const key2 = generateSymbol(name, SymbolType.FIELD)
393393

394-
for (let i = this.curIdx; i > this.curClassIdx; i--) {
394+
for (let i = this.curIdx; i >= this.curClassIdx; i--) {
395395
const table = this.tables[i]
396396
if (table.has(key1)) {
397397
return (table.get(key1) as SymbolNode).info as VariableInfo

0 commit comments

Comments
 (0)