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 5 // inside struct method supported: 6 // foo; 7 // foo(); 8 // this.foo; 9 // this.foo(); 10 // in static function: 11 // s.foo; 12 // s.foo(); 13 module vox.fe.ast.expr.call; 14 15 import vox.all; 16 17 enum CallExprFlags : ushort 18 { 19 hasNamedArgs = AstFlags.userFlag << 0, 20 } 21 22 @(AstType.expr_call) 23 struct CallExprNode { 24 mixin ExpressionNodeData!(AstType.expr_call); 25 ScopeIndex parentScope; // needed to resolve `this` pointer in member access 26 AstIndex callee; 27 AstNodes args; 28 IrIndex[] argsValues; 29 30 bool hasNamedArgs() { return cast(bool)(flags & CallExprFlags.hasNamedArgs); } 31 } 32 33 void print_call(CallExprNode* node, ref AstPrintState state) 34 { 35 if (node.callee && node.callee.astType(state.context) == AstType.decl_function) 36 { 37 state.print("CALL ", state.context.idString(node.callee.get_node_id(state.context))); 38 } 39 else 40 { 41 state.print("CALL"); 42 print_ast(node.callee, state); 43 } 44 print_ast(node.args, state); 45 } 46 47 void post_clone_call(CallExprNode* node, ref CloneState state) 48 { 49 state.fixScope(node.parentScope); 50 state.fixAstIndex(node.callee); 51 state.fixAstNodes(node.args); 52 } 53 54 void name_register_nested_call(CallExprNode* node, ref NameRegisterState state) { 55 node.state = AstNodeState.name_register_nested; 56 require_name_register(node.callee, state); 57 require_name_register(node.args, state); 58 node.state = AstNodeState.name_register_nested_done; 59 } 60 61 void name_resolve_call(CallExprNode* node, ref NameResolveState state) { 62 node.state = AstNodeState.name_resolve; 63 require_name_resolve(node.callee, state); 64 require_name_resolve(node.args, state); 65 node.state = AstNodeState.name_resolve_done; 66 } 67 68 // Get type from function declaration 69 void type_check_call(ref AstIndex callIndex, CallExprNode* node, ref TypeCheckState state) 70 { 71 CompilationContext* c = state.context; 72 73 node.state = AstNodeState.type_check; 74 scope(exit) node.state = AstNodeState.type_check_done; 75 76 AstNodes templateArgs; 77 AstIndex callee = node.callee.get_effective_node(c); 78 79 start: switch (callee.astType(c)) 80 { 81 // static function call 82 case AstType.decl_function: 83 auto func = callee.get!FunctionDeclNode(c); 84 if (func.isMember) { 85 // rewrite as method[](args) as method[](this, args) 86 // let member_access handle everything else 87 AstIndex thisName = c.appendAst!NameUseExprNode(node.loc, node.parentScope, CommonIds.id_this); 88 require_name_resolve(thisName, c); 89 node.args.putFront(c.arrayArena, thisName); 90 } 91 auto signature = func.signature.get!FunctionSignatureNode(c); 92 return type_check_func_call(node, signature, func.id, state); 93 94 case AstType.decl_struct: 95 require_type_check(callee, state, IsNested.no); 96 return type_check_constructor_call(node, callee.get!StructDeclNode(c), state); 97 98 case AstType.expr_member: 99 MemberExprNode* memberNode = callee.get!MemberExprNode(c); 100 // Method call 101 LookupResult res = lookupMember(callee, memberNode, state); 102 if (res == LookupResult.success) { 103 AstIndex memberIndex = memberNode.member(c); 104 105 if (memberNode.subType == MemberSubType.struct_templ_method) { 106 memberIndex = get_template_instance(memberIndex, node.loc, templateArgs, state); 107 108 if (memberIndex == CommonAstNodes.node_error) { 109 node.type = CommonAstNodes.type_error; 110 return; 111 } 112 } 113 114 auto calleeType = memberIndex.get_type(c); 115 116 if (calleeType.isPointer) 117 { 118 TypeNode* base = calleeType.as_ptr.base.get_type(c); 119 if (base.isFuncSignature) 120 { 121 auto signature = base.as_func_sig; 122 return type_check_func_call(node, signature, memberNode.memberId(c), state); 123 } 124 } 125 126 node.callee = memberIndex; 127 128 auto signature = calleeType.as_func_sig; 129 assert(signature); 130 if (memberNode.member(c).get_node(c).isMember) { 131 lowerThisArgument(signature, memberNode.aggregate, memberNode.loc, c); 132 node.args.putFront(c.arrayArena, memberNode.aggregate); 133 } 134 return type_check_func_call(node, signature, memberNode.memberId(c), state); 135 } 136 137 // UFCS call 138 Identifier calleeName = memberNode.memberId(c); 139 LookupResult ufcsRes = tryUFCSCall(callIndex, memberNode, state); 140 if (ufcsRes == LookupResult.failure) { 141 AstIndex objType = memberNode.aggregate.get_node_type(c); 142 node.type = CommonAstNodes.type_error; 143 c.error(node.loc, "`%s` has no member `%s`", objType.printer(c), c.idString(calleeName)); 144 return; 145 } 146 break; 147 148 case AstType.decl_var, AstType.decl_enum_member: 149 // check if func ptr 150 TypeNode* varType = callee.get_node_type(c).get_type(c); 151 if (varType.isPointer) 152 { 153 TypeNode* base = varType.as_ptr.base.get_type(c); 154 if (base.isFuncSignature) 155 { 156 auto signature = base.as_func_sig; 157 return type_check_func_call(node, signature, callee.get_node_id(c), state); 158 } 159 } 160 if (varType.isAlias) 161 { 162 if (callee.astType(c) == AstType.decl_var) goto default; 163 auto enumMember = callee.get!EnumMemberDecl(c); 164 node.callee = eval_static_expr_alias(enumMember.initializer, c); 165 callee = node.callee; // used in case decl_function 166 goto case AstType.decl_function; 167 } 168 goto default; 169 170 case AstType.expr_index: 171 auto index = callee.get!IndexExprNode(c); 172 AstIndex effective_array = index.array.get_effective_node(c); 173 AstType array_ast_type = effective_array.astType(c); 174 175 require_type_check(index.indices, state); 176 177 if (array_ast_type == AstType.decl_template) 178 { 179 // template instantiation 180 callee = get_template_instance(effective_array, node.loc, index.indices, state); 181 if (callee == CommonAstNodes.node_error) { 182 node.type = CommonAstNodes.type_error; 183 return; 184 } 185 node.callee = callee; 186 187 switch(callee.astType(c)) { 188 case AstType.decl_function: 189 case AstType.decl_struct: 190 goto start; 191 default: 192 c.internal_error(node.loc, "Unexpected template type %s", callee.astType(c)); 193 } 194 } 195 196 if (array_ast_type == AstType.expr_member) 197 { 198 templateArgs = index.indices; 199 callee = effective_array; 200 node.callee = callee; 201 goto case AstType.expr_member; 202 } 203 204 goto case AstType.decl_var; 205 case AstType.decl_template: 206 auto templ = callee.get!TemplateDeclNode(c); 207 208 //writefln("%s %s", templ.isMember, templ.body.get_node(c).isMember); 209 210 if (templ.body.astType(c) != AstType.decl_function) { 211 c.unrecoverable_error(node.loc, "Cannot call template of %s", templ.body.astType(c)); 212 } 213 214 c.assertf(!node.hasNamedArgs, node.loc, "Named arguments with variadics are not implemented"); 215 216 auto templFunc = templ.body.get!FunctionDeclNode(c); 217 auto templSignature = templFunc.signature.get!FunctionSignatureNode(c); 218 219 if (templ.isMember) { 220 // rewrite as method[](args) as method[](this, args) 221 // let member_access handle everything else 222 AstIndex thisName = c.appendAst!NameUseExprNode(node.loc, node.parentScope, CommonIds.id_this); 223 require_name_resolve(thisName, c); 224 node.args.putFront(c.arrayArena, thisName); 225 } 226 227 bool success; 228 AstNodes types = doIfti(node.loc, templ, templSignature, node.args, success, state); 229 if (!success) 230 c.unrecoverable_error(node.loc, "Cannot infer template arguments from runtime arguments"); 231 232 callee = get_template_instance(callee, node.loc, types, state); 233 node.callee = callee; 234 235 if (callee == CommonAstNodes.node_error) { 236 node.type = CommonAstNodes.type_error; 237 return; 238 } 239 240 auto func = callee.get!FunctionDeclNode(c); 241 auto signature = func.signature.get!FunctionSignatureNode(c); 242 return type_check_func_call(node, signature, func.id, state); 243 default: 244 // unknown / unimplemented case 245 node.type = CommonAstNodes.type_error; 246 c.error(node.loc, "Cannot call %s", get_node_kind_name(callee, c)); 247 //c.internal_error(node.loc, 248 // "Only direct function calls are supported right now"); 249 return; 250 } 251 } 252 253 254 // Returns inferred template parameters 255 // args needs to be ref, because type-check needs it to be ref 256 AstNodes doIfti(TokenIndex loc, TemplateDeclNode* templ, FunctionSignatureNode* sig, ref AstNodes rt_args, out bool success, ref TypeCheckState state) 257 { 258 // - run through all provided runtime args 259 // - get type of runtime parameter, if it is template type arg (T or T... here), then 260 // - if it is variadic template parameter T..., this and all subsequent variadic runtime argument types are appended 261 // after non-variadic template parameters, then continue walking non-variadics 262 // - otherwise it is type parameter T 263 // - if no type is given yet, assign runtime arg type 264 // - otherwise find common type between two 265 // - at the end run through all template args, and error if any arg is not inferred. 266 267 // signature has 0 or 1 expanded parameter 268 // template has 0 or 1 variadic parameter 269 270 CompilationContext* c = state.context; 271 272 AstNodes ct_params = templ.parameters; 273 AstNodes rt_params = sig.parameters; 274 auto numRtParams = rt_params.length; 275 auto numCtParams = ct_params.length; 276 auto numRtArgs = rt_args.length; 277 278 //writefln("numRtParams %s, numCtParams %s, numRtArgs %s, sig.hasExpandedParam %s, templ.hasVariadic %s", 279 // numRtParams, numCtParams, numRtArgs, sig.hasExpandedParam, templ.hasVariadic); 280 281 // array of inferred types (TODO: not only types) 282 AstNodes inferredTemplArgs; 283 success = true; 284 if (numCtParams == 0) return inferredTemplArgs; 285 286 HashMap!(Identifier, AstIndex, Identifier.init) paramNames; 287 288 inferredTemplArgs.reserve(c.arrayArena, max(rt_args.length, ct_params.length)); 289 290 foreach(uint i; 0..ct_params.length) 291 { 292 auto ctParam = ct_params[i].get!TemplateParamDeclNode(c); 293 paramNames.put(c.arrayArena, ctParam.id, ct_params[i]); 294 if (ctParam.isVariadic) break; // skip variadic and the rest of params 295 inferredTemplArgs.put(c.arrayArena, AstIndex()); 296 } 297 298 void reportCorrectExpandedParam(TokenIndex loc, Identifier rt_param_id) 299 { 300 if (templ.hasVariadic) { 301 uint variadicIndex = templ.numParamsBeforeVariadic; 302 auto ctParam = ct_params[variadicIndex].get!TemplateParamDeclNode(c); 303 c.error(loc, "Should be `%s... %s`", c.idString(ctParam.id), c.idString(rt_param_id)); 304 } 305 } 306 307 if (templ.hasVariadic) 308 c.assertf(templ.numParamsBeforeVariadic+1 == numCtParams, loc, "TODO: parameters after variadic template parameter"); 309 310 if (sig.hasExpandedParam) 311 { 312 if (!templ.hasVariadic) { 313 uint variadicIndex = sig.numParamsBeforeVariadic; 314 auto param = sig.parameters[variadicIndex].get!VariableDeclNode(c); 315 c.unrecoverable_error(param.loc, "Variadic parameters are not implemented"); 316 } 317 } 318 else 319 { 320 if (numRtParams != numRtArgs) 321 { 322 foreach(AstIndex idx; rt_params) { 323 VariableDeclNode* rt_param = idx.get!VariableDeclNode(c); 324 AstNode* rt_type = rt_param.type.get_node(c); 325 if (rt_type.astType != AstType.expr_name_use) continue; 326 auto typeName = rt_type.as!NameUseExprNode(c); 327 Identifier typeId = typeName.id(c); 328 AstIndex symIndex = paramNames.get(typeId, AstIndex.init); 329 if (!symIndex) continue; 330 auto ctParam = symIndex.get!TemplateParamDeclNode(c); 331 if (ctParam.isVariadic) { 332 reportCorrectExpandedParam(rt_type.loc, rt_param.id); 333 break; 334 } 335 } 336 337 c.unrecoverable_error(loc, 338 "Cannot infer template parameters. Number of runtime arguments (%s) does not match number of function parameters (%s)", 339 numRtArgs, numRtParams); 340 } 341 } 342 343 void processTemplatedArg(AstIndex argTypeIndex, TemplateParamDeclNode* ctParam) 344 { 345 //writefln("ct_arg%s %s <- rt_arg %s", 346 // ctParam.index, c.idString(ctParam.id), 347 // argTypeIndex.printer(c)); 348 349 if (inferredTemplArgs[ctParam.index].isUndefined) 350 { 351 // we found first use of template param. Assign type 352 inferredTemplArgs[ctParam.index] = argTypeIndex; 353 } 354 else if (same_type(inferredTemplArgs[ctParam.index], argTypeIndex, c)) 355 { 356 // ok 357 } 358 else 359 { 360 // calculate common type 361 CommonTypeResult res = calcCommonType(inferredTemplArgs[ctParam.index], argTypeIndex, AstIndex(), AstIndex(), c); 362 if (res.commonType.isErrorType) { 363 c.error(loc, "Cannot infer template parameter %s, from argument types %s and %s", 364 c.idString(ctParam.id), 365 inferredTemplArgs[ctParam.index].printer(c), 366 argTypeIndex.printer(c), 367 ); 368 success = false; 369 } 370 inferredTemplArgs[ctParam.index] = res.commonType; 371 } 372 } 373 374 void processVariadicRtArgs(size_t group1_size) 375 { 376 uint group3_size = cast(uint)(numRtParams - group1_size - 1 - sig.numDefaultArgs); 377 uint rt_group12_size = cast(uint)(numRtArgs - group3_size); 378 uint rt_group2_size = cast(uint)(numRtArgs - group1_size - group3_size); 379 //writefln("groups 1 %s 2 %s 3 %s 4 %s", group1_size, rt_group2_size, group3_size, sig.numDefaultArgs); 380 381 // group 2 382 foreach(size_t i; group1_size..rt_group12_size) 383 { 384 require_type_check(rt_args[i], state); // do not cache args, because require_type_check may modify it 385 AstIndex argTypeIndex = rt_args[i].get_expr_type(c); 386 inferredTemplArgs.put(c.arrayArena, argTypeIndex); 387 } 388 389 // group 3 390 foreach(size_t i; rt_group12_size..numRtArgs) 391 { 392 require_type_check(rt_args[i], state); // do not cache args, because require_type_check may modify it 393 AstIndex argTypeIndex = rt_args[i].get_expr_type(c); 394 uint rtParamIndex = cast(uint)(i - rt_group2_size + 1); // 1 skips variadic param 395 396 AstNode* rtType = rt_params[rtParamIndex].get!VariableDeclNode(c).type.get_node(c); 397 398 if (rtType.astType == AstType.expr_name_use) 399 { 400 auto typeName = rtType.as!NameUseExprNode(c); 401 Identifier typeId = typeName.id(c); 402 AstIndex symIndex = paramNames.get(typeId, AstIndex.init); 403 404 if (symIndex) 405 { 406 // we got template parameter 407 auto ctParam = symIndex.get!TemplateParamDeclNode(c); 408 assert(!ctParam.isVariadic); 409 processTemplatedArg(argTypeIndex, ctParam); 410 } 411 } 412 } 413 } 414 415 // group 1 416 foreach(size_t i, ref AstIndex arg; rt_args) 417 { 418 require_type_check(arg, state); // do not cache arg, because require_type_check may modify it 419 AstIndex argTypeIndex = arg.get_expr_type(c); 420 assert(i < numRtParams); 421 422 VariableDeclNode* rt_param = rt_params[i].get!VariableDeclNode(c); 423 AstNode* rt_type = rt_param.type.get_node(c); 424 425 if (rt_type.astType == AstType.expr_name_use) 426 { 427 auto typeName = rt_type.as!NameUseExprNode(c); 428 Identifier typeId = typeName.id(c); 429 AstIndex symIndex = paramNames.get(typeId, AstIndex.init); 430 if (symIndex) 431 { 432 // we got template parameter 433 auto ctParam = symIndex.get!TemplateParamDeclNode(c); 434 435 if (ctParam.isVariadic) { 436 if (!rt_param.isVariadicParam) { 437 reportCorrectExpandedParam(rt_param.loc, rt_param.id); 438 c.unrecoverable_error(rt_param.loc, "Cannot expand non-variadic template parameter %s", c.idString(typeId)); 439 } 440 // this and the rest of runtime args are going into CT variadic param 441 processVariadicRtArgs(i); 442 break; 443 } 444 445 if (rt_param.isVariadicParam) { 446 reportCorrectExpandedParam(rt_param.loc, rt_param.id); 447 c.unrecoverable_error(rt_param.loc, "Cannot expand non-variadic template parameter %s", c.idString(typeId)); 448 } 449 450 processTemplatedArg(argTypeIndex, ctParam); 451 } 452 else if (rt_param.isVariadicParam) 453 { 454 reportCorrectExpandedParam(rt_param.loc, rt_param.id); 455 c.unrecoverable_error(rt_param.loc, "Cannot expand parameter, type name is not found among template parameters"); 456 } 457 } 458 else if (rt_param.isVariadicParam) 459 { 460 reportCorrectExpandedParam(rt_param.loc, rt_param.id); 461 c.unrecoverable_error(rt_param.loc, "Cannot expand parameter"); 462 } 463 } 464 465 // check that all parameters before variadic were inferred 466 foreach(uint i; 0..templ.numParamsBeforeVariadic) { 467 AstIndex param = inferredTemplArgs[i]; 468 if (param.isDefined) continue; 469 470 auto ctParam = ct_params[i].get!TemplateParamDeclNode(c); 471 c.error(loc, "Cannot infer template parameter %s", c.idString(ctParam.id)); 472 success = false; 473 } 474 475 return inferredTemplArgs; 476 } 477 478 void type_check_func_call(CallExprNode* node, FunctionSignatureNode* signature, Identifier funcId, ref TypeCheckState state) 479 { 480 CompilationContext* c = state.context; 481 482 AstIndex signatureIndex = c.getAstNodeIndex(signature); 483 require_type_check(signatureIndex, state, IsNested.no); 484 node.type = signature.returnType; 485 486 AstNodes params = signature.parameters; 487 auto numParams = params.length; 488 auto numDefaultArgs = signature.numDefaultArgs; 489 c.assertf(numParams >= numDefaultArgs, node.loc, 490 "numParams(%s) < numDefaultArgs(%s)", numParams, numDefaultArgs); 491 auto numRequiredArgs = numParams - numDefaultArgs; 492 auto numArgs = node.args.length; 493 494 if (numArgs < numRequiredArgs) { 495 if (numDefaultArgs == 0) 496 c.error(node.loc, "Too few arguments to `%s`, got %s, expected %s", 497 c.idString(funcId), numArgs, numParams); 498 else 499 c.error(node.loc, "Too few arguments to `%s`, got %s, expected %s-%s", 500 c.idString(funcId), numArgs, numRequiredArgs, numParams); 501 return; 502 } 503 else if (numArgs > numParams) { 504 if (numDefaultArgs == 0) 505 c.error(node.loc, "Too many arguments to `%s`, got %s, expected %s", 506 c.idString(funcId), numArgs, numParams); 507 else 508 c.error(node.loc, "Too many arguments to `%s`, got %s, expected %s-%s", 509 c.idString(funcId), numArgs, numRequiredArgs, numParams); 510 511 return; 512 } 513 514 // We need to allocate for each call, because calls can be nested 515 // We allocate here instead of in IR gen, because eval cannot happen at IR gen, 516 // and we need to call gen_init_value_var for default args, which may need to eval 517 node.argsValues = c.allocateTempArray!IrIndex(numParams + 1); // first argument is callee 518 519 // For named arguments 520 Scope* parameterScope; 521 if (node.hasNamedArgs && numParams > 0) { 522 parameterScope = params[0].get!VariableDeclNode(c).parentScope.get_scope(c); 523 } 524 525 uint parameterIndex = 0; 526 bool skipPositionalArgs = false; 527 528 // check arguments 529 // default arguments do not require checking here 530 foreach (i, ref AstIndex arg; node.args) 531 { 532 require_type_check(arg, state); 533 534 AstNode* argNode = arg.get_node(c); 535 536 if (argNode.astType == AstType.expr_named_argument) 537 { 538 NamedArgumenExprNode* namedArg = argNode.as!NamedArgumenExprNode(c); 539 Identifier argId = namedArg.getId(c); 540 AstIndex paramIndex = parameterScope.symbols.get(argId, AstIndex.init); 541 if (paramIndex.isUndefined) { 542 c.error(namedArg.loc, "Function `%s` has no parameter named `%s`", c.idString(funcId), c.idString(argId)); 543 // we don't know the index of the next parameter, so we cannot tell which parameter is missing 544 skipPositionalArgs = true; 545 continue; 546 } 547 // restore reporting after we found a correct named parameters, since we know indicies after it 548 skipPositionalArgs = false; 549 VariableDeclNode* param = c.getAst!VariableDeclNode(paramIndex); 550 // remember the index for IR generation 551 namedArg.resolve(param.scopeIndex, c); 552 parameterIndex = param.scopeIndex; 553 554 bool success = autoconvTo(namedArg.expr, param.type, c); 555 if (!success) 556 c.error(namedArg.expr.loc(c), 557 "Named argument %s, must have type %s, not %s", c.idString(argId), 558 param.type.printer(c), 559 namedArg.expr.get_expr_type(c).printer(c)); 560 if (node.argsValues[parameterIndex+1] == IrIndex(1, IrValueKind.none)) { 561 c.error(namedArg.loc, "Parameter `%s` provided several times", c.idString(argId)); 562 } 563 node.argsValues[parameterIndex+1] = IrIndex(1, IrValueKind.none); // mark argument as set 564 } 565 else 566 { 567 if (skipPositionalArgs) continue; 568 569 if (parameterIndex >= numParams) { 570 c.error(arg.loc(c), "Trying to provide parameter %s, while `%s` has %s parameters", parameterIndex+1, c.idString(funcId), numParams); 571 ++parameterIndex; 572 continue; 573 } 574 VariableDeclNode* param = c.getAst!VariableDeclNode(params[parameterIndex]); 575 576 bool success = autoconvTo(arg, param.type, c); 577 if (!success) 578 c.error(arg.loc(c), 579 "Argument %s, must have type %s, not %s", parameterIndex+1, 580 param.type.printer(c), 581 arg.get_expr_type(c).printer(c)); 582 if (node.argsValues[parameterIndex+1] == IrIndex(1, IrValueKind.none)) { 583 c.error(argNode.loc, "Parameter `%s` was provided several times", c.idString(param.id)); 584 } 585 node.argsValues[parameterIndex+1] = IrIndex(1, IrValueKind.none); // mark argument as set 586 } 587 ++parameterIndex; 588 } 589 590 foreach(i; 0..numParams) 591 { 592 // eval default argument values 593 VariableDeclNode* param = c.getAst!VariableDeclNode(params[i]); 594 if (node.argsValues[i+1].isDefined) continue; 595 if (param.initializer.isUndefined) { 596 if (param.isAnonymous) 597 c.error(node.loc, "Missing argument for anonymous parameter %s", i+1); 598 else 599 c.error(node.loc, "Missing argument for parameter %s: `%s`", i+1, c.idString(param.id)); 600 continue; 601 } 602 603 AstNode* initializer = param.initializer.get_node(c); 604 if (initializer.astType == AstType.literal_special) { 605 node.argsValues[i+1] = eval_literal_special(cast(SpecialKeyword)initializer.subType, node.loc, node.parentScope, c); 606 } else { 607 node.argsValues[i+1] = param.gen_init_value_var(c); 608 } 609 } 610 } 611 612 void type_check_constructor_call(CallExprNode* node, StructDeclNode* s, ref TypeCheckState state) 613 { 614 CompilationContext* c = state.context; 615 616 IrIndex structType = s.gen_ir_type_struct(c); 617 uint numStructMembers = c.types.get!IrTypeStruct(structType).numMembers; 618 node.argsValues = c.allocateTempArray!IrIndex(numStructMembers); 619 620 if (s.isUnion) { 621 if (node.args.length > 1) 622 c.error(node.loc, "union constructor must have a single argument, not %s", node.args.length); 623 } else if (node.args.length > numStructMembers) { 624 c.error(node.loc, "cannot initialize struct `%s` with %s arguments, it has %s members", 625 c.idString(s.id), node.args.length, numStructMembers); 626 } 627 628 void checkArgument(VariableDeclNode* memberVar, ref AstIndex arg) 629 { 630 AstIndex memberType = memberVar.type; 631 bool success = autoconvTo(arg, memberType, c); 632 if (!success) { 633 c.error(arg.loc(c), 634 "argument for member `%s`, must have type %s, not %s", c.idString(memberVar.id), 635 memberType.printer(c), 636 arg.get_expr_type(c).printer(c)); 637 } 638 } 639 640 uint memberIndex; 641 bool reportedMixed; 642 643 // We expect args to be either all positional or all named 644 if (node.hasNamedArgs) 645 { 646 foreach (i, ref AstIndex arg; node.args) 647 { 648 require_type_check(arg, state); 649 650 AstNode* argNode = arg.get_node(c); 651 652 if (argNode.astType != AstType.expr_named_argument) { 653 if (!reportedMixed) 654 c.error(argNode.loc, "named and positional arguments cannot be mixed in struct constructor"); 655 reportedMixed = true; 656 continue; 657 } 658 659 NamedArgumenExprNode* namedArg = argNode.as!NamedArgumenExprNode(c); 660 Identifier argId = namedArg.getId(c); 661 662 AstIndex memberNodeIndex = s.memberScope.lookup_scope(argId, c); 663 if (memberNodeIndex.isUndefined) { 664 c.error(namedArg.loc, "%s `%s` has no member named `%s`", s.structOrUnionString, c.idString(s.id), c.idString(argId)); 665 continue; 666 } 667 668 if (!isDynamicStructMember(memberNodeIndex, c)) { 669 c.error(namedArg.loc, "cannot initialize %s `%s` of %s `%s`", get_node_kind_name(memberNodeIndex, c), c.idString(argId), s.structOrUnionString, c.idString(s.id)); 670 continue; 671 } 672 673 VariableDeclNode* memberVar = memberNodeIndex.get!VariableDeclNode(c); 674 namedArg.resolve(memberVar.scopeIndex, c); 675 checkArgument(memberVar, namedArg.expr); 676 } 677 } 678 else 679 { 680 foreach(uint i, AstIndex member; StructDynMemberIterator(s, c)) 681 { 682 if (node.args.length == memberIndex) break; 683 684 VariableDeclNode* memberVar = member.get!VariableDeclNode(c); 685 require_type_check(node.args[memberIndex], state); 686 687 checkArgument(memberVar, node.args[memberIndex]); 688 ++memberIndex; 689 } 690 } 691 692 // will iterate the rest of members when positional or all members when named 693 foreach(ref AstIndex member; s.declarations[memberIndex..$]) 694 { 695 if (!isDynamicStructMember(member, c)) continue; 696 VariableDeclNode* memberVar = member.get!VariableDeclNode(c); 697 // init with initializer from struct definition 698 node.argsValues[memberIndex] = memberVar.gen_init_value_var(c); 699 ++memberIndex; 700 } 701 702 node.type = c.getAstNodeIndex(s); 703 } 704 705 ExprValue ir_gen_call(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, CallExprNode* node) 706 { 707 CompilationContext* c = gen.context; 708 709 AstIndex callee = node.callee.get_effective_node(c); 710 711 switch (callee.astType(c)) 712 { 713 case AstType.decl_function: 714 auto func = callee.get!FunctionDeclNode(c); 715 IrIndex irIndex = func.getIrIndex(c); 716 return visitCall(gen, func.signature, irIndex, currentBlock, nextStmt, node); 717 case AstType.decl_struct: 718 return visitConstructor(gen, callee.get!StructDeclNode(c), currentBlock, nextStmt, node); 719 case AstType.decl_enum_member: 720 // TODO: clean up 721 TypeNode* varType = callee.get_node_type(c).get_type(c); 722 if (!varType.isPointer) goto default; 723 TypeNode* base = varType.as_ptr.base.get_type(c); 724 if (!base.isFuncSignature) goto default; 725 IrIndex irIndex = callee.get!EnumMemberDecl(c).gen_init_value_enum_member(c); 726 return visitCall(gen, c.getAstNodeIndex(base), irIndex, currentBlock, nextStmt, node); 727 case AstType.decl_var: 728 VariableDeclNode* var = callee.get!VariableDeclNode(c); 729 TypeNode* varType = var.type.get_type(c); 730 if (!varType.isPointer) goto default; 731 TypeNode* base = varType.as_ptr.base.get_type(c); 732 if (!base.isFuncSignature) goto default; 733 734 IrIndex irIndex = var.irValue.rvalue(gen, node.loc, currentBlock); 735 return visitCall(gen, c.getAstNodeIndex(base), irIndex, currentBlock, nextStmt, node); 736 case AstType.expr_member: 737 // Can probably fold other cases into this one 738 TypeNode* exprType = callee.get_expr_type(c).get_type(c); 739 if (!exprType.isPointer) goto default; 740 TypeNode* base = exprType.as_ptr.base.get_type(c); 741 if (!base.isFuncSignature) goto default; 742 743 IrLabel afterCallee = IrLabel(currentBlock); 744 ExprValue calleeLval = ir_gen_expr(gen, callee, currentBlock, afterCallee); 745 currentBlock = afterCallee.blockIndex; 746 IrIndex calleeRval = calleeLval.rvalue(gen, node.loc, currentBlock); 747 748 return visitCall(gen, c.getAstNodeIndex(base), calleeRval, currentBlock, nextStmt, node); 749 default: 750 c.internal_error(node.loc, "Cannot call %s", callee.get_node_type(c).get_type(c).printer(c)); 751 } 752 } 753 754 ExprValue visitCall(ref IrGenState gen, AstIndex signatureIndex, IrIndex callee, IrIndex currentBlock, ref IrLabel nextStmt, CallExprNode* n) 755 { 756 CompilationContext* c = gen.context; 757 auto signature = signatureIndex.get!FunctionSignatureNode(c); 758 uint numArgs = n.args.length; 759 uint numParams = signature.parameters.length; 760 c.assertf(callee.isDefined, n.loc, "Undefined callee"); 761 c.assertf(numArgs+1 <= IrInstrHeader.MAX_ARGS, n.loc, 762 "Cannot generate a call with %s arguments, max args is %s", 763 numArgs, IrInstrHeader.MAX_ARGS-1); 764 765 n.argsValues[0] = callee; 766 bool alwaysInline; 767 768 if (callee.kind == IrValueKind.func) 769 { 770 // force creation of function type for external functions 771 gen_ir_type(signatureIndex, c); 772 FunctionDeclNode* calleeFunc = c.getFunction(callee); 773 alwaysInline = calleeFunc.isInline; 774 } 775 776 uint parameterIndex = 0; 777 778 foreach (i, AstIndex arg; n.args) 779 { 780 AstNode* argNode = arg.get_node(c); 781 if (argNode.astType == AstType.expr_named_argument) 782 { 783 NamedArgumenExprNode* namedArg = argNode.as!NamedArgumenExprNode(c); 784 arg = namedArg.expr; 785 parameterIndex = namedArg.getParamIndex(c); 786 IrLabel afterArg = IrLabel(currentBlock); 787 ExprValue lval = ir_gen_expr(gen, namedArg.expr, currentBlock, afterArg); 788 currentBlock = afterArg.blockIndex; 789 n.argsValues[parameterIndex+1] = lval.rvalue(gen, n.loc, currentBlock); // account for callee in 0th index 790 } 791 else 792 { 793 IrLabel afterArg = IrLabel(currentBlock); 794 ExprValue lval = ir_gen_expr(gen, arg, currentBlock, afterArg); 795 currentBlock = afterArg.blockIndex; 796 n.argsValues[parameterIndex+1] = lval.rvalue(gen, n.loc, currentBlock); // account for callee in 0th index 797 } 798 debug c.assertf(n.argsValues[parameterIndex+1].isDefined, "Arg %s %s (%s) is undefined", parameterIndex+1, n.astType, c.tokenLoc(n.loc)); 799 ++parameterIndex; 800 } 801 802 // default args are populated in type check 803 804 // TODO: support more than plain func() calls. Such as func_array[42](), (*func_ptr)() etc 805 // need handling of function pointers 806 807 if (signature.returnType.isVoidType(c)) 808 { 809 InstrWithResult res = gen.builder.emitInstr!(IrOpcode.call)(currentBlock, n.argsValues); 810 gen.builder.ir.getInstr(res.instruction).alwaysInline = alwaysInline; 811 c.assertf(!res.result.isDefined, "Call has result"); 812 gen.builder.addJumpToLabel(currentBlock, nextStmt); 813 return ExprValue(); 814 } 815 else if (signature.returnType.isNoreturnType(c)) 816 { 817 InstrWithResult res = gen.builder.emitInstr!(IrOpcode.call)(currentBlock, n.argsValues); 818 gen.builder.addUnreachable(currentBlock); 819 gen.builder.ir.getInstr(res.instruction).alwaysInline = alwaysInline; 820 c.assertf(!res.result.isDefined, "Call has result"); 821 return ExprValue(); 822 } 823 else 824 { 825 IrIndex callResultType = signature.returnType.gen_ir_type(c); 826 827 ExtraInstrArgs extra = { hasResult : true, type : callResultType }; 828 InstrWithResult res = gen.builder.emitInstr!(IrOpcode.call)(currentBlock, extra, n.argsValues); 829 gen.builder.ir.getInstr(res.instruction).alwaysInline = alwaysInline; 830 gen.builder.addJumpToLabel(currentBlock, nextStmt); 831 return ExprValue(res.result); 832 } 833 } 834 835 ExprValue visitConstructor(ref IrGenState gen, StructDeclNode* s, IrIndex currentBlock, ref IrLabel nextStmt, CallExprNode* node) 836 { 837 CompilationContext* c = gen.context; 838 839 uint numArgs = node.args.length; 840 uint numMembers = cast(uint)node.argsValues.length; 841 842 if (numArgs == 0) 843 { 844 return ExprValue(s.gen_init_value_struct(c)); 845 } 846 847 bool allConstants = true; 848 bool allZeroes = true; 849 850 if (node.hasNamedArgs) 851 { 852 foreach (i, ref AstIndex arg; node.args) 853 { 854 NamedArgumenExprNode* namedArg = arg.get!NamedArgumenExprNode(c); 855 856 IrLabel afterArg = IrLabel(currentBlock); 857 ExprValue lval = ir_gen_expr(gen, namedArg.expr, currentBlock, afterArg); 858 currentBlock = afterArg.blockIndex; 859 IrIndex memberValue = lval.rvalue(gen, node.loc, currentBlock); 860 861 if (memberValue.isVirtReg) allConstants = false; 862 if (!memberValue.isConstantZero) allZeroes = false; 863 node.argsValues[namedArg.getParamIndex(c)] = memberValue; 864 } 865 } 866 else 867 { 868 uint memberIndex; 869 foreach(AstIndex member; s.declarations) 870 { 871 if (!isDynamicStructMember(member, c)) continue; 872 if (numArgs == memberIndex) break; // no more positional args provided, others are default inited 873 874 IrLabel afterArg = IrLabel(currentBlock); 875 ExprValue lval = ir_gen_expr(gen, node.args[memberIndex], currentBlock, afterArg); 876 currentBlock = afterArg.blockIndex; 877 IrIndex memberValue = lval.rvalue(gen, node.loc, currentBlock); 878 879 if (memberValue.isVirtReg) allConstants = false; 880 if (!memberValue.isConstantZero) allZeroes = false; 881 node.argsValues[memberIndex] = memberValue; 882 883 ++memberIndex; 884 } 885 } 886 887 // check the rest of args for all zeroes 888 if (allConstants) 889 foreach (uint i; numArgs..numMembers) { 890 if (!node.argsValues[i].isConstantZero) { 891 allZeroes = false; 892 break; 893 } 894 } 895 896 if (node.isLvalue) { 897 c.internal_error(node.loc, "Constructor cannot be an l-value"); 898 } 899 assert(s.irType.isDefined); 900 901 if (allZeroes) 902 { 903 return ExprValue(c.constants.addZeroConstant(s.irType)); 904 } 905 else if (allConstants) 906 { 907 return ExprValue(c.constants.addAggrecateConstant(s.irType, node.argsValues)); 908 } 909 else 910 { 911 ExtraInstrArgs extra = { type : s.irType }; 912 InstrWithResult res = gen.builder.emitInstr!(IrOpcode.create_aggregate)(currentBlock, extra, node.argsValues); 913 return ExprValue(res.result); 914 } 915 }