-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Unsound compilation of local classes in conjunction with exceptions #22051
Comments
What's EString and EInt? |
They're just local names for the constructor of the exception type that's defined inside def boundary[T](body: (T => RuntimeException) => T): T =
case class Break(value: T) extends RuntimeException
try body(Break.apply)
catch case Break(t) => t
@main def main =
boundary[Int]: foo =>
val v: String = boundary[String]: bar =>
throw foo(3)
v.length |
We can manually create a tag for each def boundary[T](body: (T => RuntimeException) => T): T =
val tag: AnyRef = new Object
case class Break(value: T, tag: AnyRef) extends RuntimeException
try body(Break.apply(_, tag))
catch case Break(t, _: tag.type) => t
def test() =
boundary[Int]: EInt =>
val v: String = boundary[String]: EString =>
throw EInt(3)
v.length
test() |
@noti0na1's solution is correct. The problem is erasure and how classes are handled. So I am not sure whether there is anything to fix here. |
Well, I believe Java has the same behaviour, so I'm not sure whether we should "fix" this or not? import java.util.function.Function;
public class BoundaryExample {
public static <T> T boundary(Function<Function<T, RuntimeException>, T> body) {
class Break extends RuntimeException {
final T value;
Break(T value) {
this.value = value;
}
}
try {
return body.apply(value -> new Break(value));
} catch (Break e) {
return e.value;
}
}
public static void main(String[] args) {
Integer result = boundary(EInt -> {
String v = boundary(EString -> {
throw EInt.apply(3);
});
return v.length();
});
System.out.println(result);
}
}
|
Gosh, if Java has the same issue, you might be able to get a paper out of it. 😯 That said in Scala we should try to emit a warning on the extractor, the same way we do for path-dependent classes for which we cannot statically enforce the right prefix. |
Some interesting find:
|
Compiler version
Scala CLI version: 1.5.4
Scala version (default): 3.5.2
Minimized code
Output
Expectation
The program should either be rejected at compilation, or not crash. The problem seems to be that there's only one
Break
class at runtime, but the typechecker thinks thatBreak
must contain aT
.The text was updated successfully, but these errors were encountered: