From 04208ca07dffaa10c8dd882ed592ccdd7188958d Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 27 Jun 2024 11:04:23 +0200 Subject: [PATCH] getPublicTruffleFile may yield an exception --- .../interpreter/runtime/data/EnsoFile.java | 33 +++++++++++++++---- .../runtime/error/DataflowError.java | 3 +- test/Base_Tests/src/System/File_Spec.enso | 9 +++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoFile.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoFile.java index 5d2de7614117..ca0c05cd85c7 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoFile.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoFile.java @@ -42,6 +42,7 @@ import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode; import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers; import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode; +import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @@ -451,7 +452,12 @@ private static FileSystemException replaceCreateDirectoriesNoSuchFileException( return noSuchFileException; } - var parent = fromString(EnsoContext.get(null), path).truffleFile.getParent(); + var parent = + switch (fromString(EnsoContext.get(null), path)) { + case EnsoFile f -> f.truffleFile.getParent(); + case null -> null; + default -> null; + }; // Unknown parent, so the heuristic cannot be applied - return the original. if (parent == null) { return noSuchFileException; @@ -486,7 +492,12 @@ private static FileSystemException replaceCreateDirectoriesGenericException( // On Linux, when creating a directory tree `foo/my-file.txt/a/b/c`, the operation fails with // `FileSystemException` with the full path (`foo/my-file.txt/a/b/c`). So we need to traverse // this path to find the actually problematic part. - var file = fromString(EnsoContext.get(null), path).truffleFile; + var file = + switch (fromString(EnsoContext.get(null), path)) { + case EnsoFile f -> f.truffleFile; + case null -> null; + default -> null; + }; // We try to find the first file that exists on the path. while (file != null && !file.exists()) { file = file.getParent(); @@ -630,9 +641,19 @@ public boolean startsWith(EnsoFile parent) { autoRegister = false) @Builtin.Specialize @TruffleBoundary - public static EnsoFile fromString(EnsoContext context, String path) { - TruffleFile file = context.getPublicTruffleFile(path); - return new EnsoFile(file); + public static EnsoObject fromString(EnsoContext context, String path) + throws IllegalArgumentException { + try { + TruffleFile file = context.getPublicTruffleFile(path); + return new EnsoFile(file); + } catch (IllegalArgumentException | UnsupportedOperationException ex) { + var err = + context + .getBuiltins() + .error() + .makeUnsupportedArgumentsError(new Object[] {Text.create(path)}, ex.getMessage()); + return DataflowError.withoutTrace(err, null); + } } @Builtin.Method( @@ -652,7 +673,7 @@ public static EnsoFile currentDirectory(EnsoContext context) { autoRegister = false) @Builtin.Specialize @TruffleBoundary - public static EnsoFile userHome(EnsoContext context) { + public static EnsoObject userHome(EnsoContext context) { return fromString(context, System.getProperty("user.home")); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/DataflowError.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/DataflowError.java index e3c8de84e9b7..179106849647 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/DataflowError.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/DataflowError.java @@ -12,6 +12,7 @@ import com.oracle.truffle.api.nodes.Node; import java.util.Objects; import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @@ -24,7 +25,7 @@ */ @ExportLibrary(InteropLibrary.class) @ExportLibrary(TypesLibrary.class) -public final class DataflowError extends AbstractTruffleException { +public final class DataflowError extends AbstractTruffleException implements EnsoObject { /** Signals (local) values that haven't yet been initialized */ public static final DataflowError UNINITIALIZED = new DataflowError(null, (Node) null); diff --git a/test/Base_Tests/src/System/File_Spec.enso b/test/Base_Tests/src/System/File_Spec.enso index d14eb3031730..a240a5955290 100644 --- a/test/Base_Tests/src/System/File_Spec.enso +++ b/test/Base_Tests/src/System/File_Spec.enso @@ -1,6 +1,7 @@ from Standard.Base import all import Standard.Base.Errors.Common.Forbidden_Operation import Standard.Base.Errors.Common.Dry_Run_Operation +import Standard.Base.Errors.Common.Unsupported_Argument_Types import Standard.Base.Errors.Encoding_Error.Encoding_Error import Standard.Base.Errors.File_Error.File_Error import Standard.Base.Errors.Illegal_Argument.Illegal_Argument @@ -31,6 +32,10 @@ add_specs suite_builder = windows_file = enso_project.data / "windows.txt" non_existent_file = File.new "does_not_exist.txt" + only_on_windows = case Platform.os of + Platform.OS.Windows -> Nothing + _ -> "This test runs only on Windows." + suite_builder.group "File Operations" group_builder-> group_builder.specify "should get name of the root" <| root = File.new "/" @@ -41,6 +46,10 @@ add_specs suite_builder = path = sample_file.path File.new path + group_builder.specify "invalid character in path on Windows" pending=only_on_windows <| + err = File.new "C:\dev:a" + err . should_fail_with Unsupported_Argument_Types + group_builder.specify "should have `new` be a no-op on a file" <| file = File.new sample_file file . should_equal sample_file