Skip to content
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

Unexpected ClassCastException upon atom field access when intersection types and warnings are combined #12180

Open
radeusgd opened this issue Jan 29, 2025 · 2 comments
Assignees
Labels

Comments

@radeusgd
Copy link
Member

I was hitting an unexpected ClassCastException when running Table tests during development of my #12165 PR.

I was able to distill the issue into a small repro:

from Standard.Base import all

type My_Atom
    Value my_field

type My_Refinement
    Value x

My_Refinement.from (that : My_Atom) -> My_Refinement =
    My_Refinement.Value that

prepare_atom =
    x = Warning.attach "warn" <|
        My_Atom.Value 42
    x : My_Atom & My_Refinement

main =
    x = prepare_atom
    IO.println x.my_field

Expected behaviour

The code should just print:

42

Actual behaviour

The interpreter crashes with ClassCastException:

Execution finished with an error: java.lang.ClassCastException: class org.enso.interpreter.runtime.warning.WithWarnings cannot be cast to class org.enso.interpreter.runtime.data.atom.Atom (org.enso.interpreter.runtime.warning.WithWarnings and org.enso.interpreter.runtime.data.atom.Atom are in module org.enso.runtime of loader 'app')
        at <java> org.enso.runtime/org.enso.interpreter.runtime.data.atom.GetFieldNode.execute(GetFieldNode.java:38)
        at <enso> my_field(Internal)
        at <enso> err.main<arg-1>(err.enso:19:16-25)
        at <enso> err.main(err.enso:19:5-25)
@radeusgd
Copy link
Member Author

Context that I had to find when trying to figure out a repro smaller than running the whole Table_Tests suite with my changes.

public Object execute(VirtualFrame frame) {
// this is safe, as only Atoms will ever get here through method dispatch.
Atom atom = (Atom) Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0];
return structs.getField(atom, index);
}

The (Atom) cast in GetFieldNode assumes that the thing it got is an Atom but in this case it is a WithWarnings instance.

The assumption seems to be broken because InvokeMethodNode::doMultiValue delegates to InvokeFunctionNode, extracting the first value from the multi value, but it does not extract warnings. If this was not a multi value, the doWarning specialization would have removed the warnings. Perhaps we need doMultiValue to somehow delegate to doWarning?

@JaroslavTulach JaroslavTulach self-assigned this Jan 29, 2025
radeusgd added a commit that referenced this issue Jan 29, 2025
radeusgd added a commit that referenced this issue Jan 29, 2025
@JaroslavTulach
Copy link
Member

both EnsoMultiValue and WithWarnings are a kind of 'enhance a value' wrapper and while a single wrapper like this is ok having two starts to show possibly unexpected interactions between them

  • Yes. That's exactly our problem.
  • I was thinking just of defining order among the values.
  • Just another assert at

assert !Stream.of(values).anyMatch(v -> v instanceof EnsoMultiValue)

  • to prevent WithWarnings to be wrapped by EnsoMultiValue
  • remove warnings from the values and keep the warnings only for the whole multivalue
  • one has to make sure warnings are reattached when any of the multi values is "extracted from it"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: New
Development

No branches or pull requests

2 participants