genquery should fail when querying nonexistent targets, but if the target is the scope it doesn't
Description of the bug:
the existence of a target in the scope of a genquery seems to create the target as a source file. I expect that genquery will not create targets other than itself.
What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.
genquery(
name = "query_nonexistent_target_deps",
scope = ["//:nonexistent_target"],
expression = "deps(//:nonexistent_target)",
)
building this query will succeed, with empty output. Running the same query with the CLI (bazel query "deps(//:nonexistent_target)" will error IF this genquery is not in the BUILD file, but also succeeds with empty output if this genquery is in the BUILD file.
another interesting data point: bzl query --output=label_kind //:nonexistent_target returns source file //:nonexistent_target if this genquery is defined, but errors otherwise.
Which operating system are you running Bazel on?
Ubuntu 20.04
What is the output of bazel info release?
release 6.1.0-0b9dc52a311198b1cde5c2df9403bb5e9529057f
If bazel info release returns development version or (@non-git), tell us how you built Bazel.
No response
What's the output of git remote get-url origin; git rev-parse master; git rev-parse HEAD ?
No response
Have you found anything relevant by searching the web?
I don't see anything relevant
Any other information, logs, or outputs that you want to share?
No response
Interestingly this bug seems to only happen if the nonexistent target in question is in the same package as the genquery. E.g.
genquery(
name = "test_query",
expression = "deps(//anotherpackage:doesntexist)",
scope = ["//anotherpackage:doesntexist"],
)
will fail to build.
btw I probably should've clarified the impact - this affects a macro we have which uses a genquery to assert there's no dependencies between two different targets. as such the macro implementation involves setting the "from" targets as the scope, and often folks will want to use this macro in the same package as the "from" targets. So that's particularly prone to running into this problem. The impact is that when this issue occurs, the test passes, despite no longer testing anything useful.
Valid request. Thanks for detailing, @dgoldstein0 .
@anakanemison (who recently refactored genquery), @meisterT (team owner of query) - any quick impressions on why this happens? I know we have code that assumes targets are source files if not otherwise clear. I can't remember when that kicks in.
bump on this - it's been almost a year. has there been any investigation?
It would not surprise me if we have broken tests in our codebase as a result of this bug - discovering one was exactly what led me to this. We have a macro that asserts there is no dependency between two lists of targets, and under the hood uses genquery for this, with scope of the first list of targets. so when those targets stop existing, the test stops being meaningful and should fail, but due to this bug, the test keeps passing and just becomes meaningless.
... and to add to that, I got motivated to go add some workarounds. Main discoveries about this bug:
- the bug seems exclusive to same-package nonexistent labels. Try to query a label in another package that doesn't exist and you'll get an error
- the same package labels that get magicked into existence this way have kind='source file'
Based on that latter fact I was able to query for output=label_kind and look for the 'source file' kind as a way to detect the target didn't actually exist (as some of our use cases, 'source file' wasn't a reasonable input). Found 7 buggy usages of a macro in our codebase with this, one which was an unfixable genquery using a ... wildcard (which got copied into scope, hence counted as a 'source file' instead of a broken query) but most of which were just targets that had been deleted or renamed.
FWI I'm still reading. I can check for the questions I asked above but I'm not sure when.
Isn't this the usual, non-genquery-specific behavior that Bazel assumes targets not otherwise defined in a BUILD file are source files?
maybe? I'm not familiar with that behavior, but it seems very weird to me that the scope of a genquery can make bazel assume a target or file exists, that clearly doesn't.