Skip to content

Commit

Permalink
fix: Treat local type merging failure as a reported error rather than…
Browse files Browse the repository at this point in the history
… throwing an IllegalStateException
  • Loading branch information
Col-E committed Jun 25, 2024
1 parent 86eb0aa commit 424530b
Showing 1 changed file with 28 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import me.darknet.assembler.compile.analysis.AnalysisException;
import me.darknet.assembler.compile.analysis.AnalysisResults;
import me.darknet.assembler.compile.analysis.Local;
import me.darknet.assembler.compile.analysis.ValueMergeException;
import me.darknet.assembler.compile.analysis.frame.Frame;
import me.darknet.assembler.compile.analysis.jvm.AnalysisSimulation;
import me.darknet.assembler.compile.analysis.jvm.JvmAnalysisEngine;
Expand Down Expand Up @@ -423,12 +424,15 @@ public void visitEnd() {
// Populate variables
// - Our variables are not scoped, so we can merge by name.
// - Known 'null' locals can merge with duplicate locals which may have type info associated with them
Map<String, Local> localsMap = new HashMap<>();
int paramOffset = parameters.size();
Map<String, Local> localsMap = analysisEngine.frames().values().stream()
.flatMap(Frame::locals)
.map(l -> (Local) l) // Required to make the stream type-safe
.filter(local -> local.index() >= paramOffset)
.collect(Collectors.toMap(Local::name, Function.identity(), (a, b) -> {
analysisEngine.frames().forEach((index, frame) -> {
for (Local local : frame.locals().toList()) {
// Skip parameters
if (local.index() < paramOffset)
continue;

localsMap.merge(local.name(), local, (a, b) -> {
ClassType at = a.type(); // These may be 'null' for known 'null' values
ClassType bt = b.type();

Expand All @@ -450,8 +454,23 @@ public void visitEnd() {
return a.adaptType(Types.OBJECT);

// Merge locals by type
return a.adaptType(common(at, bt));
}));
try {
return a.adaptType(common(at, bt));
} catch (ValueMergeException e) {
// If the values could not be merged, report where the failure originated from.
CodeElement element = code.elements().get(index);
ASTInstruction ast = analysisEngine.getCodeToAstMap().get(element);
if (ast != null) {
errorCollector.addError(e.getMessage(), ast.location());
return a.adaptType(Types.OBJECT);
} else {
throw new IllegalStateException();
}
}
});
}
});

localsMap.forEach((name, local) -> {
int index = local.index();
ClassType type = local.safeType();
Expand All @@ -473,7 +492,7 @@ private void add(Instruction instruction) {
codeBuilderList.addInstruction(instruction);
}

private @NotNull ClassType common(@NotNull ClassType a, @NotNull ClassType b) {
private @NotNull ClassType common(@NotNull ClassType a, @NotNull ClassType b) throws ValueMergeException {
if (a instanceof ObjectType ao && b instanceof ObjectType bo) {
if (ao instanceof ArrayType aa) {
if (bo instanceof ArrayType ba) {
Expand All @@ -496,6 +515,6 @@ private void add(Instruction instruction) {
} else if (a instanceof PrimitiveType ap && b instanceof PrimitiveType bp) {
return ap.widen(bp);
}
throw new IllegalStateException("Cannot find common type between " + a.descriptor() + " and " + b.descriptor());
throw new ValueMergeException("Cannot find common type between " + a.descriptor() + " and " + b.descriptor());
}
}

0 comments on commit 424530b

Please sign in to comment.