diff options
Diffstat (limited to 'source/slang/check.cpp')
| -rw-r--r-- | source/slang/check.cpp | 122 |
1 files changed, 95 insertions, 27 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 82936b65d..10714ca3a 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2134,39 +2134,74 @@ namespace Slang void CheckVarDeclCommon(RefPtr<VarDeclBase> varDecl) { - if (function || checkingPhase == CheckingPhase::Header) + // A variable that didn't have an explicit type written must + // have its type inferred from the initial-value expresison. + // + if(!varDecl->type.exp) { - TypeExp typeExp = CheckUsableType(varDecl->type); - varDecl->type = typeExp; - if (varDecl->type.Equals(getSession()->getVoidType())) + // In this case we need to perform all checking of the + // variable (including semantic checking of the initial-value + // expression) during the first phase of checking. + + auto initExpr = varDecl->initExpr; + if(!initExpr) { - getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid); + getSink()->diagnose(varDecl, Diagnostics::varWithoutTypeMustHaveInitializer); + varDecl->type.type = getSession()->getErrorType(); } - } + else + { + initExpr = CheckExpr(initExpr); - if (checkingPhase == CheckingPhase::Body) + // TODO: We might need some additional steps here to ensure + // that the type of the expression is one we are okay with + // inferring. E.g., if we ever decide that integer and floating-point + // literals have a distinct type from the standard int/float types, + // then we would need to "decay" a literal to an explicit type here. + + varDecl->initExpr = initExpr; + varDecl->type.type = initExpr->type; + } + + varDecl->SetCheckState(DeclCheckState::Checked); + } + else { - if (auto initExpr = varDecl->initExpr) + if (function || checkingPhase == CheckingPhase::Header) { - initExpr = CheckTerm(initExpr); - initExpr = Coerce(varDecl->type.Ptr(), initExpr); - varDecl->initExpr = initExpr; + TypeExp typeExp = CheckUsableType(varDecl->type); + varDecl->type = typeExp; + if (varDecl->type.Equals(getSession()->getVoidType())) + { + getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid); + } + } - // If this is an array variable, then we first want to give - // it a chance to infer an array size from its initializer - // - // TODO(tfoley): May need to extend this to handle the - // multi-dimensional case... - // - maybeInferArraySizeForVariable(varDecl); - // - // Next we want to make sure that the declared (or inferred) - // size for the array meets whatever language-specific - // constraints we want to enforce (e.g., disallow empty - // arrays in specific cases) - // - validateArraySizeForVariable(varDecl); + if (checkingPhase == CheckingPhase::Body) + { + if (auto initExpr = varDecl->initExpr) + { + initExpr = CheckTerm(initExpr); + initExpr = Coerce(varDecl->type.Ptr(), initExpr); + varDecl->initExpr = initExpr; + + // If this is an array variable, then we first want to give + // it a chance to infer an array size from its initializer + // + // TODO(tfoley): May need to extend this to handle the + // multi-dimensional case... + // + maybeInferArraySizeForVariable(varDecl); + // + // Next we want to make sure that the declared (or inferred) + // size for the array meets whatever language-specific + // constraints we want to enforce (e.g., disallow empty + // arrays in specific cases) + // + validateArraySizeForVariable(varDecl); + } } + } varDecl->SetCheckState(getCheckedState()); } @@ -4289,8 +4324,19 @@ namespace Slang functionNode->SetCheckState(DeclCheckState::CheckingHeader); auto oldFunc = this->function; this->function = functionNode; - auto returnType = CheckProperType(functionNode->ReturnType); - functionNode->ReturnType = returnType; + + auto resultType = functionNode->ReturnType; + if(resultType.exp) + { + resultType = CheckProperType(functionNode->ReturnType); + } + else + { + resultType = TypeExp(getSession()->getVoidType()); + } + functionNode->ReturnType = resultType; + + HashSet<Name*> paraNames; for (auto & para : functionNode->GetParameters()) { @@ -9535,6 +9581,28 @@ namespace Slang if(isGlobalShaderParameter(varDeclRef.getDecl())) isLValue = false; + // Variables declared with `let` are always immutable. + if(varDeclRef.As<LetDecl>()) + isLValue = false; + + // Generic value parameters are always immutable + if(varDeclRef.As<GenericValueParamDecl>()) + isLValue = false; + + // Function parameters declared in the "modern" style + // are immutable unless they have an `out` or `inout` modifier. + if( varDeclRef.As<ModernParamDecl>() ) + { + // Note: the `inout` modifier AST class inherits from + // the class for the `out` modifier so that we can + // make simple checks like this. + // + if( !varDeclRef.getDecl()->HasModifier<OutModifier>() ) + { + isLValue = false; + } + } + qualType.IsLeftValue = isLValue; return qualType; } |
