2024-02-26 21:58:02 +00:00
|
|
|
# Copyright 2024 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.
|
2024-04-05 08:47:05 +00:00
|
|
|
"""Helper functions for working with args."""
|
|
|
|
|
|
|
|
load(":variables.bzl", "get_type")
|
|
|
|
|
|
|
|
visibility([
|
|
|
|
"//cc/toolchains",
|
|
|
|
"//tests/rule_based_toolchain/...",
|
|
|
|
])
|
2024-02-26 21:58:02 +00:00
|
|
|
|
|
|
|
def get_action_type(args_list, action_type):
|
|
|
|
"""Returns the corresponding entry in ArgsListInfo.by_action.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
args_list: (ArgsListInfo) The args list to look through
|
|
|
|
action_type: (ActionTypeInfo) The action type to look up.
|
|
|
|
Returns:
|
|
|
|
The information corresponding to this action type.
|
|
|
|
|
|
|
|
"""
|
|
|
|
for args in args_list.by_action:
|
|
|
|
if args.action == action_type:
|
|
|
|
return args
|
|
|
|
|
|
|
|
return struct(action = action_type, args = tuple(), files = depset([]))
|
2024-04-05 08:47:05 +00:00
|
|
|
|
|
|
|
def validate_nested_args(*, nested_args, variables, actions, label, fail = fail):
|
|
|
|
"""Validates the typing for an nested_args invocation.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
nested_args: (NestedArgsInfo) The nested_args to validate
|
|
|
|
variables: (Dict[str, VariableInfo]) A mapping from variable name to
|
|
|
|
the metadata (variable type and valid actions).
|
|
|
|
actions: (List[ActionTypeInfo]) The actions we require these variables
|
|
|
|
to be valid for.
|
|
|
|
label: (Label) The label of the rule we're currently validating.
|
|
|
|
Used for error messages.
|
|
|
|
fail: The fail function. Use for testing only.
|
|
|
|
"""
|
|
|
|
stack = [(nested_args, {})]
|
|
|
|
|
|
|
|
for _ in range(9999999):
|
|
|
|
if not stack:
|
|
|
|
break
|
|
|
|
nested_args, overrides = stack.pop()
|
|
|
|
if nested_args.iterate_over != None or nested_args.unwrap_options:
|
|
|
|
# Make sure we don't keep using the same object.
|
|
|
|
overrides = dict(**overrides)
|
|
|
|
|
|
|
|
if nested_args.iterate_over != None:
|
|
|
|
type = get_type(
|
|
|
|
name = nested_args.iterate_over,
|
|
|
|
variables = variables,
|
|
|
|
overrides = overrides,
|
|
|
|
actions = actions,
|
|
|
|
args_label = label,
|
|
|
|
nested_label = nested_args.label,
|
|
|
|
fail = fail,
|
|
|
|
)
|
|
|
|
if type["name"] == "list":
|
|
|
|
# Rewrite the type of the thing we iterate over from a List[T]
|
|
|
|
# to a T.
|
|
|
|
overrides[nested_args.iterate_over] = type["elements"]
|
|
|
|
elif type["name"] == "option" and type["elements"]["name"] == "list":
|
|
|
|
# Rewrite Option[List[T]] to T.
|
|
|
|
overrides[nested_args.iterate_over] = type["elements"]["elements"]
|
|
|
|
else:
|
|
|
|
fail("Attempting to iterate over %s, but it was not a list - it was a %s" % (nested_args.iterate_over, type["repr"]))
|
|
|
|
|
|
|
|
# 1) Validate variables marked with after_option_unwrap = False.
|
|
|
|
# 2) Unwrap Option[T] to T as required.
|
|
|
|
# 3) Validate variables marked with after_option_unwrap = True.
|
|
|
|
for after_option_unwrap in [False, True]:
|
|
|
|
for var_name, requirements in nested_args.requires_types.items():
|
|
|
|
for requirement in requirements:
|
|
|
|
if requirement.after_option_unwrap == after_option_unwrap:
|
|
|
|
type = get_type(
|
|
|
|
name = var_name,
|
|
|
|
variables = variables,
|
|
|
|
overrides = overrides,
|
|
|
|
actions = actions,
|
|
|
|
args_label = label,
|
|
|
|
nested_label = nested_args.label,
|
|
|
|
fail = fail,
|
|
|
|
)
|
|
|
|
if type["name"] not in requirement.valid_types:
|
|
|
|
fail("{msg}, but {var_name} has type {type}".format(
|
|
|
|
var_name = var_name,
|
|
|
|
msg = requirement.msg,
|
|
|
|
type = type["repr"],
|
|
|
|
))
|
|
|
|
|
|
|
|
# Only unwrap the options after the first iteration of this loop.
|
|
|
|
if not after_option_unwrap:
|
|
|
|
for var in nested_args.unwrap_options:
|
|
|
|
type = get_type(
|
|
|
|
name = var,
|
|
|
|
variables = variables,
|
|
|
|
overrides = overrides,
|
|
|
|
actions = actions,
|
|
|
|
args_label = label,
|
|
|
|
nested_label = nested_args.label,
|
|
|
|
fail = fail,
|
|
|
|
)
|
|
|
|
if type["name"] == "option":
|
|
|
|
overrides[var] = type["elements"]
|
|
|
|
|
|
|
|
for child in nested_args.nested:
|
|
|
|
stack.append((child, overrides))
|