Break dependency on vfs from the interface of syntax and cmdline.

These libs are exposed externally, implying that the vfs is also exposed externally.

We break out PathFragment from vfs to still use this in their interface. This class is a much smaller dependency than the entire vfs.

PiperOrigin-RevId: 174729373
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 4810d3b..f75cf26 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -273,7 +273,6 @@
         "skylarkinterface/*.java",
     ]),
     deps = [
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//third_party:jsr305",
     ],
 )
@@ -291,7 +290,7 @@
         "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
         "//src/main/java/com/google/devtools/build/lib/profiler",
-        "//src/main/java/com/google/devtools/build/lib/vfs",
+        "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//third_party:asm",
         "//third_party:asm-commons",
         "//third_party:asm-util",
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/BUILD b/src/main/java/com/google/devtools/build/lib/cmdline/BUILD
index 0273178..306eba1 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/BUILD
@@ -21,7 +21,7 @@
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
-        "//src/main/java/com/google/devtools/build/lib/vfs",
+        "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
         "//third_party:guava",
         "//third_party:jsr305",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
index 976b56d..0520c02 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
@@ -21,6 +21,7 @@
 import com.google.devtools.build.lib.syntax.Mutability;
 import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkSemantics;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.vfs.RootedPath;
@@ -125,7 +126,10 @@
                     /*importMap=*/ null)
                 .setupDynamic(Runtime.PKG_NAME, Runtime.NONE)
                 .setupDynamic(Runtime.REPOSITORY_NAME, Runtime.NONE);
-          ast = BuildFileAST.parseSkylarkFile(path, astFileSize, env.getListener());
+        byte[] bytes = FileSystemUtils.readWithKnownFileSize(path, astFileSize);
+        ast =
+            BuildFileAST.parseSkylarkFile(
+                bytes, path.getDigest(), path.asFragment(), env.getListener());
           ast = ast.validate(validationEnv, env.getListener());
         }
     } catch (IOException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java
index 4160214..4c56ade 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceASTFunction.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.syntax.LoadStatement;
 import com.google.devtools.build.lib.syntax.ParserInputSource;
 import com.google.devtools.build.lib.syntax.Statement;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.vfs.RootedPath;
@@ -65,8 +66,13 @@
             Transience.PERSISTENT);
       }
       if (workspaceFileValue.exists()) {
-        ast = BuildFileAST.parseBuildFile(
-            ParserInputSource.create(repoWorkspace), ast.getStatements(), env.getListener());
+        byte[] bytes =
+            FileSystemUtils.readWithKnownFileSize(repoWorkspace, repoWorkspace.getFileSize());
+        ast =
+            BuildFileAST.parseBuildFile(
+                ParserInputSource.create(bytes, repoWorkspace.asFragment()),
+                ast.getStatements(),
+                env.getListener());
         if (ast.containsErrors()) {
           throw new WorkspaceASTFunctionException(
               new BuildFileContainsErrorsException(
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java
index bee73ef..e3751a8 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java
@@ -14,7 +14,6 @@
 
 package com.google.devtools.build.lib.skylarkinterface;
 
-import com.google.devtools.build.lib.util.Pair;
 import java.lang.reflect.Method;
 import javax.annotation.Nullable;
 
@@ -23,21 +22,30 @@
  */
 public class SkylarkInterfaceUtils {
 
+  private static final class ClassAndSkylarkModule {
+    final Class<?> klass;
+    final SkylarkModule skylarkModule;
+
+    ClassAndSkylarkModule(Class<?> klass, SkylarkModule skylarkModule) {
+      this.klass = klass;
+      this.skylarkModule = skylarkModule;
+    }
+  }
+
   @Nullable
-  private static Pair<Class<?>, SkylarkModule> searchForSkylarkModule(Class<?> classObj) {
+  private static ClassAndSkylarkModule searchForSkylarkModule(Class<?> classObj) {
     if (classObj.isAnnotationPresent(SkylarkModule.class)) {
-      return new Pair<Class<?>, SkylarkModule>(
-          classObj, classObj.getAnnotation(SkylarkModule.class));
+      return new ClassAndSkylarkModule(classObj, classObj.getAnnotation(SkylarkModule.class));
     }
     Class<?> superclass = classObj.getSuperclass();
     if (superclass != null) {
-      Pair<Class<?>, SkylarkModule> result = searchForSkylarkModule(superclass);
+      ClassAndSkylarkModule result = searchForSkylarkModule(superclass);
       if (result != null) {
         return result;
       }
     }
     for (Class<?> interfaceObj : classObj.getInterfaces()) {
-      Pair<Class<?>, SkylarkModule> result = searchForSkylarkModule(interfaceObj);
+      ClassAndSkylarkModule result = searchForSkylarkModule(interfaceObj);
       if (result != null) {
         return result;
       }
@@ -52,8 +60,8 @@
    */
   @Nullable
   public static SkylarkModule getSkylarkModule(Class<?> classObj) {
-    Pair<Class<?>, SkylarkModule> result = searchForSkylarkModule(classObj);
-    return result == null ? null : result.second;
+    ClassAndSkylarkModule result = searchForSkylarkModule(classObj);
+    return result == null ? null : result.skylarkModule;
   }
 
   /**
@@ -63,8 +71,8 @@
    */
   @Nullable
   public static Class<?> getParentWithSkylarkModule(Class<?> classObj) {
-    Pair<Class<?>, SkylarkModule> result = searchForSkylarkModule(classObj);
-    return result == null ? null : result.first;
+    ClassAndSkylarkModule result = searchForSkylarkModule(classObj);
+    return result == null ? null : result.klass;
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintable.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintable.java
new file mode 100644
index 0000000..39760c4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkPrintable.java
@@ -0,0 +1,42 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkinterface;
+
+/**
+ * Interface for types that aren't {@link SkylarkValue}s, but that we still want to support printing
+ * of.
+ */
+public interface SkylarkPrintable {
+
+  /**
+   * Print an official representation of object x.
+   *
+   * <p>For regular data structures, the value should be parsable back into an equal data structure.
+   *
+   * @param printer a printer to be used for formatting nested values.
+   */
+  void repr(SkylarkPrinter printer);
+
+  /**
+   * Print an informal, human-readable representation of the value.
+   *
+   * <p>By default dispatches to the {@code repr} method.
+   *
+   * @param printer a printer to be used for formatting nested values.
+   */
+  default void str(SkylarkPrinter printer) {
+    repr(printer);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java
index 6d430ff..b61da9b 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkValue.java
@@ -19,7 +19,7 @@
  *
  * <p>This is used for extending the Skylark interpreter with domain-specific values.
  */
-public interface SkylarkValue {
+public interface SkylarkValue extends SkylarkPrintable {
 
   /**
    * Returns if the value is immutable and thus suitable for being used as a dictionary key.
@@ -30,24 +30,4 @@
   default boolean isImmutable() {
       return false;
   }
-
-  /**
-   * Print an official representation of object x.
-   *
-   * <p>For regular data structures, the value should be parsable back into an equal data structure.
-   *
-   * @param printer a printer to be used for formatting nested values.
-   */
-  void repr(SkylarkPrinter printer);
-
-  /**
-   * Print an informal, human-readable representation of the value.
-   *
-   * <p>By default dispatches to the {@code repr} method.
-   *
-   * @param printer a printer to be used for formatting nested values.
-   */
-  default void str(SkylarkPrinter printer) {
-    repr(printer);
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java b/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java
index fcd3da0..439e4c5 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java
@@ -23,7 +23,6 @@
 import com.google.devtools.build.lib.syntax.Parser.ParseResult;
 import com.google.devtools.build.lib.syntax.SkylarkImports.SkylarkImportSyntaxException;
 import com.google.devtools.build.lib.util.Pair;
-import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
 import java.util.List;
@@ -278,24 +277,14 @@
         .validateBuildFile(eventHandler);
   }
 
-  /**
-   * Parse the specified Skylark file, returning its AST. All errors during scanning or parsing will
-   * be reported to the reporter.
-   *
-   * @throws IOException if the file cannot not be read.
-   */
-  public static BuildFileAST parseSkylarkFile(Path file, EventHandler eventHandler)
+  public static BuildFileAST parseSkylarkFile(
+      byte[] bytes, byte[] digest, PathFragment path, EventHandler eventHandler)
       throws IOException {
-    return parseSkylarkFile(file, file.getFileSize(), eventHandler);
-  }
-
-  public static BuildFileAST parseSkylarkFile(Path file, long fileSize, EventHandler eventHandler)
-      throws IOException {
-    ParserInputSource input = ParserInputSource.create(file, fileSize);
+    ParserInputSource input = ParserInputSource.create(bytes, path);
     Parser.ParseResult result = Parser.parseFile(input, eventHandler);
     return create(
         ImmutableList.of(), result,
-        HashCode.fromBytes(file.getDigest()).toString(), eventHandler);
+        HashCode.fromBytes(digest).toString(), eventHandler);
   }
 
   public static BuildFileAST parseSkylarkFile(ParserInputSource input, EventHandler eventHandler) {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ParserInputSource.java b/src/main/java/com/google/devtools/build/lib/syntax/ParserInputSource.java
index 5f2ce3f..05663e2 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/ParserInputSource.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/ParserInputSource.java
@@ -13,10 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.syntax;
 
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
-
 import java.io.IOException;
 
 /**
@@ -38,20 +35,9 @@
    */
   public abstract PathFragment getPath();
 
-  /**
-   * Create an input source instance by (eagerly) reading from the file at
-   * path. The file is assumed to be ISO-8859-1 encoded and smaller than
-   * 2 Gigs - these assumptions are reasonable for BUILD files, which is
-   * all we care about here.
-   */
-  public static ParserInputSource create(Path path) throws IOException {
-    return create(path, path.getFileSize());
-  }
-
-  public static ParserInputSource create(Path path, long fileSize) throws IOException {
-    byte[] bytes = FileSystemUtils.readWithKnownFileSize(path, fileSize);
-    char[] content = FileSystemUtils.convertFromLatin1(bytes);
-    return create(content, path.asFragment());
+  public static ParserInputSource create(byte[] bytes, PathFragment path) throws IOException {
+    char[] content = convertFromLatin1(bytes);
+    return create(content, path);
   }
 
   /**
@@ -82,4 +68,12 @@
       }
     };
   }
+
+  private static char[] convertFromLatin1(byte[] content) {
+    char[] latin1 = new char[content.length];
+    for (int i = 0; i < latin1.length; i++) { // yeah, latin1 is this easy! :-)
+      latin1[i] = (char) (0xff & content[i]);
+    }
+    return latin1;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
index fe4191f..69b16fe 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Printer.java
@@ -16,11 +16,10 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrintable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
-import com.google.devtools.build.lib.vfs.Path;
-import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Formattable;
@@ -316,8 +315,8 @@
         // values such as Locations or ASTs.
         this.append("null");
 
-      } else if (o instanceof SkylarkValue) {
-        ((SkylarkValue) o).repr(this);
+      } else if (o instanceof SkylarkPrintable) {
+        ((SkylarkPrintable) o).repr(this);
 
       } else if (o instanceof String) {
         writeString((String) o);
@@ -344,13 +343,6 @@
         this.repr(entry.getKey());
         this.append(": ");
         this.repr(entry.getValue());
-
-      } else if (o instanceof PathFragment) {
-        this.append(((PathFragment) o).getPathString());
-
-      } else if (o instanceof Path) {
-        append(o.toString());
-
       } else if (o instanceof Class<?>) {
         this.append(EvalUtils.getDataTypeNameFromClass((Class<?>) o));
 
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/BUILD b/src/main/java/com/google/devtools/build/lib/vfs/BUILD
index 37bb571..1e6c5a9 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/vfs/BUILD
@@ -6,17 +6,45 @@
     visibility = ["//src/main/java/com/google/devtools/build/lib:__pkg__"],
 )
 
-# Virtual file system; do not use externally!
+PATH_FRAGMENT_SOURCES = [
+    "Canonicalizer.java",
+    "PathFragment.java",
+    "PathFragmentSerializationProxy.java",
+    "UnixPathFragment.java",
+    "WindowsPathFragment.java",
+]
+
 java_library(
-    name = "vfs",
-    srcs = glob([
-        "*.java",
-    ]),
-    visibility = ["//visibility:public"],
+    name = "pathfragment",
+    srcs = PATH_FRAGMENT_SOURCES,
     deps = [
         "//src/main/java/com/google/devtools/build/lib:base-util",
         "//src/main/java/com/google/devtools/build/lib:os_util",
         "//src/main/java/com/google/devtools/build/lib:preconditions",
+        "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+        "//src/main/java/com/google/devtools/build/lib/concurrent",
+        "//third_party:guava",
+    ],
+)
+
+# Virtual file system; do not use externally!
+java_library(
+    name = "vfs",
+    srcs = glob(
+        [
+            "*.java",
+        ],
+        exclude = PATH_FRAGMENT_SOURCES,
+    ),
+    visibility = ["//visibility:public"],
+    exports = [
+        ":pathfragment",
+    ],
+    deps = [
+        ":pathfragment",
+        "//src/main/java/com/google/devtools/build/lib:base-util",
+        "//src/main/java/com/google/devtools/build/lib:preconditions",
+        "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib/clock",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
         "//src/main/java/com/google/devtools/build/lib/profiler",
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Path.java b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
index 52b8af3..ab5ad5c 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/Path.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/Path.java
@@ -15,6 +15,8 @@
 
 import com.google.common.base.Predicate;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrintable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.StringCanonicalizer;
 import com.google.devtools.build.lib.vfs.FileSystem.HashFunction;
@@ -37,21 +39,20 @@
 import java.util.Objects;
 
 /**
- * <p>Instances of this class represent pathnames, forming a tree
- * structure to implement sharing of common prefixes (parent directory names).
- * A node in these trees is something like foo, bar, .., ., or /. If the
- * instance is not a root path, it will have a parent path. A path can also
- * have children, which are indexed by name in a map.
+ * Instances of this class represent pathnames, forming a tree structure to implement sharing of
+ * common prefixes (parent directory names). A node in these trees is something like foo, bar, ..,
+ * ., or /. If the instance is not a root path, it will have a parent path. A path can also have
+ * children, which are indexed by name in a map.
  *
- * <p>There is some limited support for Windows-style paths. Most importantly, drive identifiers
- * in front of a path (c:/abc) are supported. However, Windows-style backslash separators
+ * <p>There is some limited support for Windows-style paths. Most importantly, drive identifiers in
+ * front of a path (c:/abc) are supported. However, Windows-style backslash separators
  * (C:\\foo\\bar) and drive-relative paths ("C:foo") are explicitly not supported, same with
  * advanced features like \\\\network\\paths and \\\\?\\unc\\paths.
  *
  * <p>{@link FileSystem} implementations maintain pointers into this graph.
  */
 @ThreadSafe
-public class Path implements Comparable<Path>, Serializable {
+public class Path implements Comparable<Path>, Serializable, SkylarkPrintable {
 
   /** Filesystem-specific factory for {@link Path} objects. */
   public static interface PathFactory {
@@ -427,6 +428,11 @@
     return builder.toString();
   }
 
+  @Override
+  public void repr(SkylarkPrinter printer) {
+    printer.append(getPathString());
+  }
+
   /**
    * Returns the path as a string.
    */
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java b/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
index c47a5f7..a6d6b2b 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
@@ -20,6 +20,8 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrintable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.StringCanonicalizer;
@@ -45,7 +47,8 @@
  */
 @Immutable
 @ThreadSafe
-public abstract class PathFragment implements Comparable<PathFragment>, Serializable {
+public abstract class PathFragment
+    implements Comparable<PathFragment>, Serializable, SkylarkPrintable {
   private static final Helper HELPER =
       OS.getCurrent() == OS.WINDOWS ? WindowsPathFragment.HELPER : UnixPathFragment.HELPER;
 
@@ -451,18 +454,17 @@
   }
 
   /**
-   * Returns the path formed by appending the single non-special segment
-   * "baseName" to this path.
+   * Returns the path formed by appending the single non-special segment "baseName" to this path.
    *
-   * <p>You should almost always use {@link #getRelative} instead, which has
-   * the same performance characteristics if the given name is a valid base
-   * name, and which also works for '.', '..', and strings containing '/'.
+   * <p>You should almost always use {@link #getRelative} instead, which has the same performance
+   * characteristics if the given name is a valid base name, and which also works for '.', '..', and
+   * strings containing '/'.
    *
-   * @throws IllegalArgumentException if {@code baseName} is not a valid base
-   *     name according to {@link FileSystemUtils#checkBaseName}
+   * @throws IllegalArgumentException if {@code baseName} is not a valid base name according to
+   *     {@link #checkBaseName}
    */
   public PathFragment getChild(String baseName) {
-    FileSystemUtils.checkBaseName(baseName);
+    checkBaseName(baseName);
     baseName = StringCanonicalizer.intern(baseName);
     String[] newSegments = Arrays.copyOf(segments, segments.length + 1);
     newSegments[newSegments.length - 1] = baseName;
@@ -734,4 +736,21 @@
   public String toString() {
     return getPathString();
   }
+
+  @Override
+  public void repr(SkylarkPrinter printer) {
+    printer.append(getPathString());
+  }
+
+  private static void checkBaseName(String baseName) {
+    if (baseName.length() == 0) {
+      throw new IllegalArgumentException("Child must not be empty string ('')");
+    }
+    if (baseName.equals(".") || baseName.equals("..")) {
+      throw new IllegalArgumentException("baseName must not be '" + baseName + "'");
+    }
+    if (baseName.indexOf('/') != -1) {
+      throw new IllegalArgumentException("baseName must not contain a slash: '" + baseName + "'");
+    }
+  }
 }