1 /// Copyright: Copyright (c) 2017-2019 Andrey Penechko. 2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 3 /// Authors: Andrey Penechko. 4 module vox.fe.ast.type.func_sig; 5 6 import vox.all; 7 8 enum FuncSignatureFlags : ushort 9 { 10 // Set if at least one of return or parameter types is meta type 11 isCtfeOnly = AstFlags.userFlag << 0, 12 // Function has parameter with expanded type 13 hasExpandedParam = AstFlags.userFlag << 1, 14 attachedToFunctionWithBody = AstFlags.userFlag << 2, 15 } 16 17 @(AstType.type_func_sig) 18 struct FunctionSignatureNode { 19 mixin AstNodeData!(AstType.type_func_sig, AstFlags.isType, AstNodeState.name_register_self_done); 20 AstIndex returnType; 21 // parameters are owned by the function declaration or 22 // if it is part of function type literal then there is no owner 23 AstNodes parameters; // array of var declarations 24 CallConvention callConvention; // Is set in the parser 25 ubyte numDefaultArgs; 26 /// Number of parameters before variadic parameter 27 /// Is equal to parameters.length when no variadic is present 28 ushort numParamsBeforeVariadic; 29 30 private IrIndex irType; /// Index of function type 31 TypeNode* typeNode() return { return cast(TypeNode*)&this; } 32 33 IrIndex getIrType(CompilationContext* c) { 34 gen_ir_type_func_sig(&this, c); // calculate if needed 35 return irType; 36 } 37 38 bool isCtfeOnly() { return cast(bool)(flags & FuncSignatureFlags.isCtfeOnly); } 39 bool hasExpandedParam() { return cast(bool)(flags & FuncSignatureFlags.hasExpandedParam); } 40 bool attachedToFunctionWithBody() { return cast(bool)(flags & FuncSignatureFlags.attachedToFunctionWithBody); } 41 bool isExternal() { return hasAttributes && attributeInfo.isExternal; } 42 } 43 44 void print_func_sig(FunctionSignatureNode* node, ref AstPrintState state) 45 { 46 state.print("TYPE ", node.typeNode.printer(state.context), node.isCtfeOnly ? " #ctfe" : null); 47 } 48 49 void post_clone_func_sig(FunctionSignatureNode* node, ref CloneState state) 50 { 51 state.fixAstIndex(node.returnType); 52 state.fixAstNodes(node.parameters); 53 } 54 55 // only occurs when signature is a part of function declaration 56 void name_register_nested_func_sig(FunctionSignatureNode* node, ref NameRegisterState state) { 57 node.state = AstNodeState.name_register_nested; 58 require_name_register(node.parameters, state); 59 node.state = AstNodeState.name_register_nested_done; 60 if (node.hasExpandedParam) expandVariadicParam(node, state.context); 61 } 62 63 void name_resolve_func_sig(FunctionSignatureNode* node, ref NameResolveState state) 64 { 65 node.state = AstNodeState.name_resolve; 66 require_name_resolve(node.returnType, state); 67 require_name_resolve(node.parameters, state); 68 node.state = AstNodeState.name_resolve_done; 69 } 70 71 // This happend when we are name resolving function signature inside template instance, 72 // so we already have final values for variadic template argument 73 void expandVariadicParam(FunctionSignatureNode* node, CompilationContext* c) 74 { 75 uint variadicIndex = node.numParamsBeforeVariadic; 76 auto param = node.parameters[variadicIndex].get!VariableDeclNode(c); 77 // we are still in name register pass, but we need to get to the alias array 78 require_name_resolve(param.type, c); 79 80 AstNode* typeArray = param.type.get_effective_node(c).get_node(c); 81 if (typeArray.astType != AstType.decl_alias_array) 82 { 83 if (typeArray.isError) return; 84 if (typeArray.astType == AstType.type_slice) { 85 c.unrecoverable_error(param.loc, 86 "Variadic arrays are not yet implemented", 87 typeArray.astType); 88 } 89 c.unrecoverable_error(param.loc, 90 "Expand operator must be applied to variadic template argument, not %s", 91 typeArray.astType); 92 } 93 94 auto types = typeArray.as!AliasArrayDeclNode(c); 95 96 uint numVariadicParams = types.items.length; 97 node.parameters.replaceAt(c.arrayArena, variadicIndex, 1, types.items[]); 98 99 AstNodes vars; 100 vars.reserve(c.arrayArena, numVariadicParams); 101 102 foreach(size_t i, AstIndex type; types.items) 103 { 104 string originalId = c.idString(param.id); 105 Identifier paramId = c.idMap.getOrRegFormatted(c, "__%s_%s", originalId, i); 106 AstIndex newParamIndex = c.appendAst!VariableDeclNode(param.loc, ScopeIndex.init, type, AstIndex.init, paramId, cast(ushort)(param.scopeIndex + i)); 107 auto newParam = newParamIndex.get!VariableDeclNode(c); 108 newParam.flags |= VariableFlags.isParameter | VariableFlags.isAnonymous; 109 newParam.state = AstNodeState.name_resolve_done; 110 node.parameters[variadicIndex + i] = newParamIndex; 111 vars.put(c.arrayArena, newParamIndex); 112 } 113 114 // update indices of other params 115 foreach(size_t i; variadicIndex + numVariadicParams..node.parameters.length) 116 { 117 auto rtParam = node.parameters[i].get!VariableDeclNode(c); 118 rtParam.scopeIndex = cast(ushort)(rtParam.scopeIndex + numVariadicParams - 1); 119 } 120 121 // rewrite variadic parameter as array literal in-place 122 static assert(VariableDeclNode.sizeof >= AliasArrayDeclNode.sizeof, 123 "VariableDeclNode.sizeof < AliasArrayDeclNode.sizeof"); 124 auto arrayNode = cast(AliasArrayDeclNode*)param; 125 *arrayNode = AliasArrayDeclNode(param.loc, vars); 126 } 127 128 // Parameters consist of 4 groups: 129 // 1) 0+, non-variadic, non-default 130 // 2) 0+, variadic 131 // 3) 0+, non-variadic, non-default 132 // 4) 0+, non-variadic, default 133 void type_check_func_sig(FunctionSignatureNode* node, ref TypeCheckState state) 134 { 135 CompilationContext* c = state.context; 136 137 node.state = AstNodeState.type_check; 138 139 // ir_header 140 gen_ir_header_func_sig(node, c); 141 142 // Process @extern attribute 143 process_externs(node, c); 144 145 require_type_check(node.returnType, state); 146 check_is_type(node.returnType, c); 147 148 TypeNode* returnType = node.returnType.get_type(c); 149 if (returnType.isOpaqueStruct(c)) { 150 c.error(node.loc, 151 "function cannot return opaque type `%s`", 152 returnType.printer(c)); 153 } 154 155 require_type_check(node.parameters, state); 156 157 if (caclIsCtfeOnly(node, c)) node.flags |= FuncSignatureFlags.isCtfeOnly; 158 159 node.state = AstNodeState.type_check_done; 160 } 161 162 // Validate @extern attributes, bind externals and update calling conventions 163 // depends on ir_header 164 void process_externs(FunctionSignatureNode* node, CompilationContext* c) 165 { 166 // Check that function `isExternal` matches `isExternal` of signature 167 if (!node.attachedToFunctionWithBody && !node.isExternal) { 168 // allow until @extern(module) is implemented 169 // TODO: we don't know atm if we are attached to function without body or it is free function type 170 } 171 172 if (!node.isExternal) return; // skip if no extern properties are bound to this node 173 174 AstIndex lastExternAttrib; 175 176 foreach(AstIndex attrib; node.attributeInfo.attributes) 177 { 178 auto attribNode = attrib.get_node(c); 179 180 if (attribNode.astType != AstType.decl_builtin_attribute) continue; 181 182 void onExternAttrib() { 183 // check for duplicates 184 if (lastExternAttrib.isDefined) { 185 // check if previous @extern attribute is broadcasted 186 // NOTE: all broadcasted attributes are located before direct attributes 187 // so we can detect multiple directly applied @extern attributes by detecting 2 consecutive @extern attributes 188 if (!attribNode.as!BuiltinAttribNode(c).isBroadcasted) 189 { 190 if (lastExternAttrib.get!BuiltinAttribNode(c).isBroadcasted) { 191 // allow duplicates in cases when only one @extern attribute is directly applied 192 // and others are broadcast applied (like `@extern(...):` and `@extern(...){...}`) 193 } else { 194 c.error(attribNode.loc, "Duplicate @extern attribute"); 195 } 196 } 197 } 198 lastExternAttrib = attrib; // save last @extern attribute 199 } 200 201 final switch(cast(BuiltinAttribSubType)attribNode.subType) { 202 case BuiltinAttribSubType.extern_syscall: 203 onExternAttrib(); 204 uint syscall_number = attribNode.as!BuiltinAttribNode(c).data; 205 206 if (syscall_number > ushort.max) { 207 c.error(attribNode.loc, "Max supported syscall number is 64k, got %s", syscall_number); 208 return; 209 } 210 211 if (c.targetOs != TargetOs.linux) { 212 c.error(attribNode.loc, "@extern(syscall) attribute is only implemented on linux"); 213 return; 214 } 215 break; 216 217 case BuiltinAttribSubType.extern_module: 218 onExternAttrib(); 219 break; 220 } 221 } 222 223 // Apply the last @extern attribute 224 auto attribNode = lastExternAttrib.get_node(c); 225 final switch(cast(BuiltinAttribSubType)attribNode.subType) { 226 case BuiltinAttribSubType.extern_syscall: 227 uint syscall_number = attribNode.as!BuiltinAttribNode(c).data; 228 auto funcType = &c.types.get!IrTypeFunction(node.irType); 229 funcType.callConv = CallConvention.sysv64_syscall; 230 funcType.syscallNumber = cast(ushort)syscall_number; 231 break; 232 233 case BuiltinAttribSubType.extern_module: 234 // TODO: lookup by the name in external host module, or create import entry for dll symbols 235 break; 236 } 237 238 if (node.attachedToFunctionWithBody) { 239 if (attribNode.as!BuiltinAttribNode(c).isBroadcasted) { 240 // allow broadcasted @extern attribute on function with body 241 } else { 242 c.error(node.loc, "External function cannot have a body"); 243 } 244 } 245 } 246 247 private bool caclIsCtfeOnly(FunctionSignatureNode* node, CompilationContext* c) { 248 if (node.returnType.get_node_type(c).isMetaType(c)) return true; 249 foreach (AstIndex param; node.parameters) { 250 if (param.get_node_type(c).isMetaType(c)) return true; 251 } 252 return false; 253 } 254 255 bool same_type_func_sig(FunctionSignatureNode* t1, FunctionSignatureNode* t2, CompilationContext* c) 256 { 257 if (!same_type(t1.returnType, t2.returnType, c)) return false; 258 if (t1.parameters.length != t2.parameters.length) return false; 259 foreach (i, AstIndex paramA; t1.parameters) 260 { 261 AstIndex paramB = t2.parameters[i]; 262 if (!same_type(paramA.get_node_type(c), paramB.get_node_type(c), c)) return false; 263 } 264 return true; 265 } 266 267 TypeConvResKind type_conv_func_sig(FunctionSignatureNode* node, AstIndex typeBIndex, ref AstIndex expr, CompilationContext* c) 268 { 269 if (typeBIndex.get_type(c).isAlias) return TypeConvResKind.ii_i; 270 return TypeConvResKind.fail; 271 } 272 273 void gen_ir_header_func_sig(FunctionSignatureNode* node, CompilationContext* c) 274 { 275 final switch(node.getPropertyState(NodeProperty.ir_header)) { 276 case PropertyState.not_calculated: break; 277 case PropertyState.calculating: c.circular_dependency; 278 case PropertyState.calculated: return; 279 } 280 281 c.begin_node_property_calculation(node, NodeProperty.ir_header); 282 scope(exit) c.end_node_property_calculation(node, NodeProperty.ir_header); 283 284 uint numResults = node.returnType.isTypeVoid ? 0 : 1; 285 node.irType = c.types.appendFuncSignature(numResults, node.parameters.length, node.callConvention); 286 } 287 288 // depends on ir_header 289 IrIndex gen_ir_type_func_sig(FunctionSignatureNode* node, CompilationContext* c) 290 out(res; res.isTypeFunction, "Not a function type") 291 { 292 final switch(node.getPropertyState(NodeProperty.ir_body)) { 293 case PropertyState.not_calculated: break; 294 case PropertyState.calculating: c.circular_dependency; 295 case PropertyState.calculated: return node.irType; 296 } 297 298 // dependencies 299 gen_ir_header_func_sig(node, c); 300 301 c.begin_node_property_calculation(node, NodeProperty.ir_body); 302 scope(exit) c.end_node_property_calculation(node, NodeProperty.ir_body); 303 304 305 auto funcType = &c.types.get!IrTypeFunction(node.irType); 306 307 if (funcType.numResults == 1) { 308 IrIndex returnType = node.returnType.gen_ir_type(c); 309 funcType.resultTypes[0] = returnType; 310 } 311 312 IrIndex[] parameterTypes = funcType.parameterTypes; 313 foreach(i, AstIndex parameter; node.parameters) { 314 parameterTypes[i] = parameter.get_node_type(c).gen_ir_type(c); 315 } 316 317 return node.irType; 318 }