From 02974fd3a272dacb9b99103012dc08040b6e191a Mon Sep 17 00:00:00 2001 From: Christopher Paciorek Date: Sun, 17 Dec 2023 15:21:11 -0800 Subject: [PATCH] fix issue 1344 (not 1144) with a check in keyword processing (#1370) * fix issue 1144 with a check in keyword processing * add testing for new getParam check --- .../R/nimbleFunction_keywordProcessing.R | 8 ++++ .../nimble/tests/testthat/test-getParam.R | 46 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/packages/nimble/R/nimbleFunction_keywordProcessing.R b/packages/nimble/R/nimbleFunction_keywordProcessing.R index ea91919db..ead9c1822 100644 --- a/packages/nimble/R/nimbleFunction_keywordProcessing.R +++ b/packages/nimble/R/nimbleFunction_keywordProcessing.R @@ -168,7 +168,15 @@ getParam_keywordInfo <- keywordInfoClass( if(isCodeArgBlank(code, 'param')) stop("'param' argument missing from 'getParam', with no accessor argument supplied") + + ## Avoid situations where user has syntax from run code in `param` or of getting anything from global env (issue 1344). + paramVars <- all.vars(code$param) + wh <- which(!paramVars %in% nfProc$setupSymTab$getSymbolNames()) + if(length(wh)) + stop("`param` argument in `getParam` contains variables not found in setup code: ", paste(paramVars[wh], collapse = ", "), ".") + paramInfo_ArgList <- list(model = code$model, node = nodeFunVec_ArgList$nodes, param = code$param, hasIndex = useNodeFunctionVectorByIndex) ## use nodeFunVec_ArgList$nodes instead of code$node because nodeFunVec_ArgList$nodes may have been updated if code$nodes has a run-time index. In that case the paramID will be vector + paramInfoName <- paramInfo_SetupTemplate$makeName(paramInfo_ArgList) paramIDname <- paramInfo_SetupTemplate$makeOtherNames(paramInfoName, paramInfo_ArgList) diff --git a/packages/nimble/tests/testthat/test-getParam.R b/packages/nimble/tests/testthat/test-getParam.R index 35a1340cb..934148939 100644 --- a/packages/nimble/tests/testthat/test-getParam.R +++ b/packages/nimble/tests/testthat/test-getParam.R @@ -300,5 +300,51 @@ test_that("getParam works in various multi-instance combinations", { expect_identical(gsp5_2$run(), cgsp5$gsp5_2$run()) }) +test_that("error trap indexing in param argument of getParam", { + + nf <- nimbleFunction( + setup = function(model) { + i <- 2 + params <- c('mean','sd') + }, + run = function() { + returnType(double(0)) + tmp <- model$getParam('y', params[i]) + return(tmp) + }) + + code <- nimbleCode({ + y ~ dnorm(0, 1) + }) + m <- nimbleModel(code) + rnf <- nf(m) + cm <- compileNimble(m) + ## Should succeed as `i` in setup. + cnf <- compileNimble(rnf, project = m) + + # or i in global; or i in run + nf <- nimbleFunction( + setup = function(model) { + params <- c('mean','sd') + }, + run = function() { + i <- 2 + returnType(double(0)) + tmp <- model$getParam('y', params[i]) + return(tmp) + }) + + code <- nimbleCode({ + y ~ dnorm(0, 1) + }) + m <- nimbleModel(code) + rnf <- nf(m) + cm <- compileNimble(m) + expect_error(cnf <- compileNimble(rnf, project = m), + "contains variables not found in setup") + +}) + + options(warn = RwarnLevel) nimbleOptions(verbose = nimbleVerboseSetting)