merged branch with upstream changes to master
diff --git a/BUILD b/BUILD
index ad98f37..6630132 100644
--- a/BUILD
+++ b/BUILD
@@ -15,6 +15,7 @@
     srcs = [
         "BUILD",
         "//lib:test_deps",
+        "//rules:test_deps",
         "//toolchains/unittest:test_deps",
     ] + glob(["*.bzl"]),
 )
diff --git a/lib/types.bzl b/lib/types.bzl
index 37c32bc..7824893 100644
--- a/lib/types.bzl
+++ b/lib/types.bzl
@@ -20,6 +20,7 @@
 _a_string_type = type("")
 _a_tuple_type = type(())
 _an_int_type = type(1)
+_a_depset_type = type(depset())
 
 def _a_function():
     pass
@@ -114,6 +115,17 @@
     """
     return type(v) == _a_function_type
 
+def _is_depset(v):
+    """Returns True if v is an instance of a `depset`.
+
+    Args:
+      v: The value whose type should be checked.
+
+    Returns:
+      True if v is an instance of a `depset`, False otherwise.
+    """
+    return type(v) == _a_depset_type
+
 types = struct(
     is_list = _is_list,
     is_string = _is_string,
@@ -123,4 +135,5 @@
     is_tuple = _is_tuple,
     is_dict = _is_dict,
     is_function = _is_function,
+    is_depset = _is_depset,
 )
diff --git a/rules/BUILD b/rules/BUILD
index 4f98c5d..e161093 100644
--- a/rules/BUILD
+++ b/rules/BUILD
@@ -2,10 +2,16 @@
 
 licenses(["notice"])
 
+package(default_visibility = ["//visibility:public"])
+
+bzl_library(
+    name = "build_test",
+    srcs = ["build_test.bzl"],
+)
+
 bzl_library(
     name = "maprule",
     srcs = ["maprule.bzl"],
-    visibility = ["//visibility:public"],
     deps = [":maprule_private"],
 )
 
@@ -18,3 +24,16 @@
         "//lib:paths",
     ],
 )
+
+# Exported for build_test.bzl to make sure of, it is an implementation detail
+# of the rule and should not be directly used by anything else.
+exports_files(["empty_test.sh"])
+
+filegroup(
+    name = "test_deps",
+    testonly = True,
+    srcs = [
+        "BUILD",
+        "empty_test.sh",
+    ] + glob(["*.bzl"]),
+)
diff --git a/rules/build_test.bzl b/rules/build_test.bzl
new file mode 100644
index 0000000..34c8657
--- /dev/null
+++ b/rules/build_test.bzl
@@ -0,0 +1,88 @@
+# Copyright 2019 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.
+
+"""A test verifying other targets build as part of a `bazel test`"""
+
+load("//lib:new_sets.bzl", "sets")
+
+def build_test(name, targets, **kwargs):
+    """Test rule checking that other targets build.
+
+    This works not by an instance of this test failing, but instead by
+    the targets it depends on failing to build, and hence failing
+    the attempt to run this test.
+
+    NOTE: At the moment, this won't work on Windows; but someone adding
+    support would be welcomed.
+
+    Typical usage:
+
+      load("@bazel_skylib//rules:build_test.bzl", "build_test")
+      build_test(
+          name = "my_build_test",
+          targets = [
+              "//some/package:rule",
+          ],
+      )
+
+    Args:
+      name: The name of the test rule.
+      targets: A list of targets to ensure build.
+      **kwargs: The <a href="https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes-tests">common attributes for tests</a>.
+    """
+    if len(targets) == 0:
+        fail("targets must be non-empty", "targets")
+    if kwargs.get("data", None):
+        fail("data is not supported on a build_test()", "data")
+
+    # Remove any duplicate test targets.
+    targets = sets.to_list(sets.make(targets))
+
+    # Use a genrule to ensure the targets are built (works because it forces
+    # the outputs of the other rules on as data for the genrule)
+
+    # Split into batches to hopefully avoid things becoming so large they are
+    # too much for a remote execution set up.
+    batch_size = max(1, len(targets) // 100)
+
+    # Pull a few args over from the test to the genrule.
+    args_to_reuse = ["compatible_with", "restricted_to", "tags"]
+    genrule_args = {k: kwargs.get(k) for k in args_to_reuse if k in kwargs}
+
+    # Pass an output from the genrules as data to a shell test to bundle
+    # it all up in a test.
+    test_data = []
+
+    for idx, batch in enumerate([targets[i:i + batch_size] for i in range(0, len(targets), batch_size)]):
+        full_name = "{name}_{idx}__deps".format(name = name, idx = idx)
+        test_data.append(full_name)
+        native.genrule(
+            name = full_name,
+            srcs = batch,
+            outs = [full_name + ".out"],
+            testonly = 1,
+            visibility = ["//visibility:private"],
+            # TODO: Does this need something else for Windows?
+            cmd = "touch $@",
+            **genrule_args
+        )
+
+    native.sh_test(
+        name = name,
+        # TODO: Does this need something else for Windows?
+        srcs = ["@bazel_skylib//rules:empty_test.sh"],
+        data = test_data,
+        size = kwargs.pop("size", "small"),  # Default to small for test size
+        **kwargs
+    )
diff --git a/rules/empty_test.sh b/rules/empty_test.sh
new file mode 100755
index 0000000..fde58b3
--- /dev/null
+++ b/rules/empty_test.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+# This is a support file for build_test.bzl, it shouldn't be used by anything else.
+exit 0
diff --git a/rules/maprule_private.bzl b/rules/maprule_private.bzl
index 007bfa5..ae44cf9 100644
--- a/rules/maprule_private.bzl
+++ b/rules/maprule_private.bzl
@@ -44,7 +44,7 @@
 _cmd_maprule_example = """
     # This file is //projects/game:BUILD
 
-    load("//tools/build_rules:maprule.bzl", "cmd_maprule")
+    load("@bazel_skylib//rules:maprule.bzl", "cmd_maprule")
 
     cmd_maprule(
         name = "process_assets",
@@ -77,7 +77,7 @@
 _bash_maprule_example = """
     # This file is //projects/game:BUILD
 
-    load("//tools/build_rules:maprule.bzl", "bash_maprule")
+    load("@bazel_skylib//rules:maprule.bzl", "bash_maprule")
 
     bash_maprule(
         name = "process_assets",
diff --git a/tests/BUILD b/tests/BUILD
index bad49b0..5bd929d 100644
--- a/tests/BUILD
+++ b/tests/BUILD
@@ -1,4 +1,5 @@
 load("//:bzl_library.bzl", "bzl_library")
+load(":build_test_tests.bzl", "build_test_test_suite")
 load(":collections_tests.bzl", "collections_test_suite")
 load(":dicts_tests.bzl", "dicts_test_suite")
 load(":maprule_tests.bzl", "maprule_test_suite")
@@ -14,6 +15,8 @@
 
 licenses(["notice"])
 
+build_test_test_suite()
+
 collections_test_suite()
 
 dicts_test_suite()
diff --git a/tests/build_test_tests.bzl b/tests/build_test_tests.bzl
new file mode 100644
index 0000000..d4f6c88
--- /dev/null
+++ b/tests/build_test_tests.bzl
@@ -0,0 +1,41 @@
+# Copyright 2019 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.
+
+"""Unit tests for build_test.bzl."""
+
+load("//rules:build_test.bzl", "build_test")
+
+def build_test_test_suite():
+    # Since the rules doesn't do anything really, it just makes some targets
+    # to get Bazel to build other targets via a `bazel test`, just make some
+    # targets to exercise the rule.
+
+    # Make a source file
+    native.genrule(
+        name = "build_test__make_src",
+        outs = ["build_test__src.cc"],
+        cmd = "echo 'int dummy() { return 0; }' > $@",
+    )
+
+    # Use it in a non-test target
+    native.cc_library(
+        name = "build_test__build_target",
+        srcs = [":build_test__make_src"],
+    )
+
+    # Wrap a build test around the target.
+    build_test(
+        name = "build_test__test",
+        targets = [":build_test__build_target"],
+    )
diff --git a/tests/types_tests.bzl b/tests/types_tests.bzl
index 55cc64e..6681d1c 100644
--- a/tests/types_tests.bzl
+++ b/tests/types_tests.bzl
@@ -35,6 +35,7 @@
     asserts.false(env, types.is_string(True))
     asserts.false(env, types.is_string(None))
     asserts.false(env, types.is_string(_a_function))
+    asserts.false(env, types.is_string(depset()))
 
     return unittest.end(env)
 
@@ -55,6 +56,7 @@
     asserts.false(env, types.is_bool(""))
     asserts.false(env, types.is_bool(None))
     asserts.false(env, types.is_bool(_a_function))
+    asserts.false(env, types.is_bool(depset()))
 
     return unittest.end(env)
 
@@ -75,6 +77,7 @@
     asserts.false(env, types.is_list(True))
     asserts.false(env, types.is_list(None))
     asserts.false(env, types.is_list(_a_function))
+    asserts.false(env, types.is_list(depset()))
 
     return unittest.end(env)
 
@@ -95,6 +98,7 @@
     asserts.false(env, types.is_none([]))
     asserts.false(env, types.is_none([1]))
     asserts.false(env, types.is_none(_a_function))
+    asserts.false(env, types.is_none(depset()))
 
     return unittest.end(env)
 
@@ -116,6 +120,7 @@
     asserts.false(env, types.is_int([1]))
     asserts.false(env, types.is_int(None))
     asserts.false(env, types.is_int(_a_function))
+    asserts.false(env, types.is_int(depset()))
 
     return unittest.end(env)
 
@@ -137,6 +142,7 @@
     asserts.false(env, types.is_tuple([1]))
     asserts.false(env, types.is_tuple(None))
     asserts.false(env, types.is_tuple(_a_function))
+    asserts.false(env, types.is_tuple(depset()))
 
     return unittest.end(env)
 
@@ -158,13 +164,14 @@
     asserts.false(env, types.is_dict([1]))
     asserts.false(env, types.is_dict(None))
     asserts.false(env, types.is_dict(_a_function))
+    asserts.false(env, types.is_dict(depset()))
 
     return unittest.end(env)
 
 is_dict_test = unittest.make(_is_dict_test)
 
 def _is_function_test(ctx):
-    """Unit tests for types.is_dict."""
+    """Unit tests for types.is_function."""
 
     env = unittest.begin(ctx)
 
@@ -178,11 +185,36 @@
     asserts.false(env, types.is_function([]))
     asserts.false(env, types.is_function([1]))
     asserts.false(env, types.is_function(None))
+    asserts.false(env, types.is_function(depset()))
 
     return unittest.end(env)
 
 is_function_test = unittest.make(_is_function_test)
 
+def _is_depset_test(ctx):
+    """Unit tests for types.is_depset."""
+
+    env = unittest.begin(ctx)
+
+    asserts.true(env, types.is_depset(depset()))
+    asserts.true(env, types.is_depset(depset(["foo"])))
+    asserts.true(env, types.is_depset(
+        depset(["foo"], transitive = [depset(["bar", "baz"])]),
+    ))
+
+    asserts.false(env, types.is_depset({}))
+    asserts.false(env, types.is_depset(1))
+    asserts.false(env, types.is_depset("s"))
+    asserts.false(env, types.is_depset(()))
+    asserts.false(env, types.is_depset(True))
+    asserts.false(env, types.is_depset([]))
+    asserts.false(env, types.is_depset([1]))
+    asserts.false(env, types.is_depset(None))
+
+    return unittest.end(env)
+
+is_depset_test = unittest.make(_is_depset_test)
+
 def types_test_suite():
     """Creates the test targets and test suite for types.bzl tests."""
     unittest.suite(
@@ -195,4 +227,5 @@
         is_tuple_test,
         is_dict_test,
         is_function_test,
+        is_depset_test,
     )