diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 38 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 91 |
3 files changed, 78 insertions, 52 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 2b7f8f2fc..e06578c86 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2820,18 +2820,38 @@ namespace Slang // Nothing to do } - void visitParamDecl(ParamDecl* para) + void visitParamDecl(ParamDecl* paramDecl) { - // TODO: This needs to bottleneck through the common variable checks + // TODO: This logic should be shared with the other cases of + // variable declarations. The main reason I am not doing it + // yet is that we use a `ParamDecl` with a null type as a + // special case in attribute declarations, and that could + // trip up the ordinary variable checks. - if(para->type.exp) + auto typeExpr = paramDecl->type; + if(typeExpr.exp) { - para->type = CheckUsableType(para->type); - - if (para->type.Equals(getSession()->getVoidType())) - { - getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid); - } + typeExpr = CheckUsableType(typeExpr); + paramDecl->type = typeExpr; + } + + // The "initializer" expression for a parameter represents + // a default argument value to use if an explicit one is + // not supplied. + if(auto initExpr = paramDecl->initExpr) + { + // We must check the expression and coerce it to the + // actual type of the parameter. + // + initExpr = CheckExpr(initExpr); + initExpr = Coerce(typeExpr.type, initExpr); + paramDecl->initExpr = initExpr; + + // TODO: a default argument expression needs to + // conform to other constraints to be valid. + // For example, it should not be allowed to refer + // to other parameters of the same function (or maybe + // only the parameters to its left...). } } diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index e74126f1b..f1aee496c 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -176,7 +176,6 @@ DIAGNOSTIC(30013, Error, subscriptNonArray, "no subscript operation found for t DIAGNOSTIC(30014, Error, subscriptIndexNonInteger, "index expression must evaluate to int.") DIAGNOSTIC(30015, Error, undefinedIdentifier, "'$0': undefined identifier.") DIAGNOSTIC(30015, Error, undefinedIdentifier2, "undefined identifier '$0'.") -DIAGNOSTIC(30016, Error, parameterCannotBeVoid, "'void' can not be parameter type.") DIAGNOSTIC(30017, Error, componentNotAccessibleFromShader, "component '$0' is not accessible from shader '$1'.") DIAGNOSTIC(30019, Error, typeMismatch, "expected an expression of type '$0', got '$1'") DIAGNOSTIC(30020, Error, importOperatorReturnTypeMismatch, "import operator should return '$1', but the expression has type '$0''. do you forget 'project'?") diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 24181c75a..57fa55741 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1417,21 +1417,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> SLANG_UNIMPLEMENTED_X("codegen for aggregate type constructor expression"); } - // Add arguments that appeared directly in an argument list - // to the list of argument values for a call. - void addDirectCallArgs( - InvokeExpr* expr, - List<IRInst*>* ioArgs) - { - for( auto arg : expr->Arguments ) - { - // TODO: Need to handle case of l-value arguments, - // when they are matched to `out` or `in out` parameters. - auto loweredArg = lowerRValueExpr(context, arg); - addArgs(context, ioArgs, loweredArg); - } - } - // After a call to a function with `out` or `in out` // parameters, we may need to copy data back into // the l-value locations used for output arguments. @@ -1452,18 +1437,44 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> List<OutArgumentFixup>* ioFixups) { UInt argCount = expr->Arguments.Count(); - UInt argIndex = 0; + UInt argCounter = 0; for (auto paramDeclRef : getMembersOfType<ParamDecl>(funcDeclRef)) { - if (argIndex >= argCount) - { - // The remaining parameters must be defaulted... - break; - } - auto paramDecl = paramDeclRef.getDecl(); RefPtr<Type> paramType = lowerSimpleType(context, GetType(paramDeclRef)); - auto argExpr = expr->Arguments[argIndex++]; + + UInt argIndex = argCounter++; + RefPtr<Expr> argExpr; + if(argIndex < argCount) + { + argExpr = expr->Arguments[argIndex]; + } + else + { + // We have run out of arguments supplied at the call site, + // but there are still parameters remaining. This must mean + // that these parameters have default argument expressions + // associated with them. + argExpr = getInitExpr(paramDeclRef); + + // Assert that such an expression must have been present. + SLANG_ASSERT(argExpr); + + // TODO: The approach we are taking here to default arguments + // is simplistic, and has consequences for the front-end as + // well as binary serializatiojn of modules. + // + // We could consider some more refined approaches where, e.g., + // functions with default arguments generate multiple IR-level + // functions, that compute and provide the default values. + // + // Alternatively, each parameter with defaults could be generated + // into its own callable function that provides the default value, + // so that calling modules can call into a pre-generated function. + // + // Each of these options involves trade-offs, and we need to + // make a conscious decision at some point. + } if (paramDecl->HasModifier<OutModifier>() || paramDecl->HasModifier<InOutModifier>()) @@ -1543,8 +1554,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } else { - SLANG_UNEXPECTED("shouldn't relaly happen"); - UNREACHABLE(addDirectCallArgs(expr, ioArgs)); + SLANG_UNEXPECTED("callee was not a callable decl"); } } @@ -1696,24 +1706,21 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> return result; } - // The default case is to assume that we just have - // an ordinary expression, and can lower it as such. - LoweredValInfo funcVal = lowerRValueExpr(context, expr->FunctionExpr); - - // Now we add any direct arguments from the call expression itself. - addDirectCallArgs(expr, &irArgs); - - // Delegate to the logic for invoking a value. - auto result = emitCallToVal(context, type, funcVal, irArgs.Count(), irArgs.Buffer()); - - // TODO: because of the nature of how the `emitCallToVal` case works - // right now, we don't have information on in/out parameters, and - // so we can't collect info to apply fixups. + // TODO: In this case we should be emitting code for the callee as + // an ordinary expression, then emitting the arguments according + // to the type information on the callee (e.g., which paameters + // are `out` or `inout`, and then finally emitting the `call` + // instruciton. // - // Once we have a better representation for function types, though, - // this should be fixable. - - return result; + // We don't currently have the case of emitting arguments according + // to function type info (instead of declaration info), and really + // this case can't occur unless we start adding first-class functions + // to the source language. + // + // For now we just bail out with an error. + // + SLANG_UNEXPECTED("could not resolve target declaration for call"); + UNREACHABLE_RETURN(LoweredValInfo()); } LoweredValInfo subscriptValue( |
