diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java index 4cd81e7eeed0ec..48b10d462a5f4f 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java @@ -620,7 +620,7 @@ public RunModuleExtensionResult run( // Instiantiate the repos one by one. for (InnateExtensionRepo repo : repos) { Object exported = repo.loadedBzl().getModule().getGlobal(repo.ruleName()); - if (!(exported instanceof RepositoryRuleFunction)) { + if (exported == null) { ImmutableSet exportedRepoRules = repo.loadedBzl().getModule().getGlobals().entrySet().stream() .filter(e -> e.getValue() instanceof RepositoryRuleFunction) @@ -636,6 +636,17 @@ public RunModuleExtensionResult run( repo.tag().getLocation(), SpellChecker.didYouMean(repo.ruleName(), exportedRepoRules)), Transience.PERSISTENT); + } else if (!(exported instanceof RepositoryRuleFunction)) { + throw new SingleExtensionEvalFunctionException( + ExternalDepsException.withMessage( + Code.BAD_MODULE, + "%s exports a value called %s of type %s, yet a repository_rule is requested" + + " at %s", + repo.bzlLabel(), + repo.ruleName(), + Starlark.type(exported), + repo.tag().getLocation()), + Transience.PERSISTENT); } RepositoryRuleFunction repoRule = (RepositoryRuleFunction) exported; Dict kwargs = repo.tag().getAttributeValues().attributes(); diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java index 5ae281f5a522ae..b36b5614ff4663 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java @@ -2448,7 +2448,35 @@ public void innate_noSuchRepoRule() throws Exception { "load('@data//:data.bzl', self_data='data')", "data=self_data"); scratch.file( - workspaceRoot.getRelative("repo.bzl").getPathString(), "data_repo = 3 # not a repo rule"); + workspaceRoot.getRelative("repo.bzl").getPathString(), + "# not a repo rule", + "def data_repo(name):", + " pass"); + + SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl")); + reporter.removeHandler(failFastHandler); + EvaluationResult result = + evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext); + assertThat(result.hasError()).isTrue(); + assertThat(result.getError().getException()) + .hasMessageThat() + .contains( + "//:repo.bzl exports a value called data_repo of type function, yet a repository_rule" + + " is requested at /ws/MODULE.bazel"); + } + + @Test + public void innate_noSuchValue() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "data_repo = use_repo_rule('//:repo.bzl', 'data_repo')", + "data_repo(name='data', data='get up at 6am.')"); + scratch.file(workspaceRoot.getRelative("BUILD").getPathString()); + scratch.file( + workspaceRoot.getRelative("data.bzl").getPathString(), + "load('@data//:data.bzl', self_data='data')", + "data=self_data"); + scratch.file(workspaceRoot.getRelative("repo.bzl").getPathString(), ""); SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl")); reporter.removeHandler(failFastHandler);