1# Copyright 2024 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Helper functions for working with args.""" 15 16load(":variables.bzl", "get_type") 17 18visibility([ 19 "//cc/toolchains", 20 "//tests/rule_based_toolchain/...", 21]) 22 23def get_action_type(args_list, action_type): 24 """Returns the corresponding entry in ArgsListInfo.by_action. 25 26 Args: 27 args_list: (ArgsListInfo) The args list to look through 28 action_type: (ActionTypeInfo) The action type to look up. 29 Returns: 30 The information corresponding to this action type. 31 32 """ 33 for args in args_list.by_action: 34 if args.action == action_type: 35 return args 36 37 return struct(action = action_type, args = tuple(), files = depset([])) 38 39def validate_nested_args(*, nested_args, variables, actions, label, fail = fail): 40 """Validates the typing for an nested_args invocation. 41 42 Args: 43 nested_args: (NestedArgsInfo) The nested_args to validate 44 variables: (Dict[str, VariableInfo]) A mapping from variable name to 45 the metadata (variable type and valid actions). 46 actions: (List[ActionTypeInfo]) The actions we require these variables 47 to be valid for. 48 label: (Label) The label of the rule we're currently validating. 49 Used for error messages. 50 fail: The fail function. Use for testing only. 51 """ 52 stack = [(nested_args, {})] 53 54 for _ in range(9999999): 55 if not stack: 56 break 57 nested_args, overrides = stack.pop() 58 if nested_args.iterate_over != None or nested_args.unwrap_options: 59 # Make sure we don't keep using the same object. 60 overrides = dict(**overrides) 61 62 if nested_args.iterate_over != None: 63 type = get_type( 64 name = nested_args.iterate_over, 65 variables = variables, 66 overrides = overrides, 67 actions = actions, 68 args_label = label, 69 nested_label = nested_args.label, 70 fail = fail, 71 ) 72 if type["name"] == "list": 73 # Rewrite the type of the thing we iterate over from a List[T] 74 # to a T. 75 overrides[nested_args.iterate_over] = type["elements"] 76 elif type["name"] == "option" and type["elements"]["name"] == "list": 77 # Rewrite Option[List[T]] to T. 78 overrides[nested_args.iterate_over] = type["elements"]["elements"] 79 else: 80 fail("Attempting to iterate over %s, but it was not a list - it was a %s" % (nested_args.iterate_over, type["repr"])) 81 82 # 1) Validate variables marked with after_option_unwrap = False. 83 # 2) Unwrap Option[T] to T as required. 84 # 3) Validate variables marked with after_option_unwrap = True. 85 for after_option_unwrap in [False, True]: 86 for var_name, requirements in nested_args.requires_types.items(): 87 for requirement in requirements: 88 if requirement.after_option_unwrap == after_option_unwrap: 89 type = get_type( 90 name = var_name, 91 variables = variables, 92 overrides = overrides, 93 actions = actions, 94 args_label = label, 95 nested_label = nested_args.label, 96 fail = fail, 97 ) 98 if type["name"] not in requirement.valid_types: 99 fail("{msg}, but {var_name} has type {type}".format( 100 var_name = var_name, 101 msg = requirement.msg, 102 type = type["repr"], 103 )) 104 105 # Only unwrap the options after the first iteration of this loop. 106 if not after_option_unwrap: 107 for var in nested_args.unwrap_options: 108 type = get_type( 109 name = var, 110 variables = variables, 111 overrides = overrides, 112 actions = actions, 113 args_label = label, 114 nested_label = nested_args.label, 115 fail = fail, 116 ) 117 if type["name"] == "option": 118 overrides[var] = type["elements"] 119 120 for child in nested_args.nested: 121 stack.append((child, overrides)) 122