diff --git a/src/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt b/src/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt
index cf657b4fa..4ce19d7ec 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt
@@ -55,20 +55,15 @@ class CallCommand(val ranges: Ranges, val functionCall: Expression) : Command.Si
         return ExecutionResult.Success
       }
 
+      val name = (if (functionCall.scope != null) functionCall.scope.c + ":" else "") + functionCall.functionName
       val funcref = VariableService.getNullableVariableValue(Variable(functionCall.scope, functionCall.functionName), editor, context, parent)
       if (funcref is VimFuncref) {
-        if (funcref.handler is DefinedFunctionHandler && funcref.handler.function.flags.contains(FunctionFlag.DICT) && funcref.handler.function.self == null) {
-          throw ExException(
-            "E725: Calling dict function without Dictionary: " +
-              ((if (functionCall.scope != null) functionCall.scope.c + ":" else "") + functionCall.functionName)
-          )
-        }
         funcref.handler.ranges = ranges
-        funcref.execute(functionCall.arguments, editor, context, parent)
+        funcref.execute(name, functionCall.arguments, editor, context, parent)
         return ExecutionResult.Success
       }
 
-      throw ExException("E117: Unknown function: ${if (functionCall.scope != null) functionCall.scope.c + ":" else ""}${functionCall.functionName}")
+      throw ExException("E117: Unknown function: $name")
     } else if (functionCall is FuncrefCallExpression) {
       functionCall.evaluateWithRange(ranges, editor, context, parent)
       return ExecutionResult.Success
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt b/src/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt
index 1309cee1f..48bc89c0f 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt
@@ -14,6 +14,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
 import com.maddyhome.idea.vim.vimscript.model.Script
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary
+import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimList
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
@@ -28,6 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.SublistExpression
 import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
 import com.maddyhome.idea.vim.vimscript.model.expressions.operators.AssignmentOperator
 import com.maddyhome.idea.vim.vimscript.model.expressions.toVimDataType
+import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
 import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
 import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
 import com.maddyhome.idea.vim.vimscript.services.VariableService
@@ -66,15 +68,19 @@ data class LetCommand(
               if (operator != AssignmentOperator.ASSIGNMENT && !variableValue.dictionary.containsKey(dictKey)) {
                 throw ExException("E716: Key not present in Dictionary: $dictKey")
               }
-              if (variableValue.dictionary.containsKey(dictKey)) {
-                variableValue.dictionary[dictKey] =
-                  operator.getNewValue(
-                    SimpleExpression(variableValue.dictionary[dictKey]!!), expression, editor,
-                    context, this
-                  )
+              var valueToStore = if (variableValue.dictionary.containsKey(dictKey)) {
+                operator.getNewValue(SimpleExpression(variableValue.dictionary[dictKey]!!), expression, editor, context, this)
               } else {
-                variableValue.dictionary[dictKey] = expression.evaluate(editor, context, this)
+                expression.evaluate(editor, context, this)
               }
+              if (valueToStore is VimFuncref && !valueToStore.isSelfFixed &&
+                valueToStore.handler is DefinedFunctionHandler &&
+                (valueToStore.handler as DefinedFunctionHandler).function.flags.contains(FunctionFlag.DICT)
+              ) {
+                valueToStore = valueToStore.copy()
+                valueToStore.dictionary = variableValue
+              }
+              variableValue.dictionary[dictKey] = valueToStore
             }
             is VimList -> {
               // we use Integer.parseInt(........asString()) because in case if index's type is Float, List, Dictionary etc
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimDictionary.kt b/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimDictionary.kt
index 4aee76b4d..f037a6eea 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimDictionary.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimDictionary.kt
@@ -18,14 +18,17 @@ data class VimDictionary(val dictionary: LinkedHashMap<VimString, VimDataType>)
 
   override fun toString(): String {
     val result = StringBuffer("{")
-    result.append(dictionary.map { it.stringOfEntry() }.joinToString(separator = ", "))
+    result.append(dictionary.map { stringOfEntry(it) }.joinToString(separator = ", "))
     result.append("}")
     return result.toString()
   }
 
-  private fun Map.Entry<VimString, VimDataType>.stringOfEntry(): String {
-    val valueString = if (this.value is VimString) "'${this.value}'" else this.value.toString()
-    return "'${this.key}': $valueString"
+  private fun stringOfEntry(entry: Map.Entry<VimString, VimDataType>): String {
+    val valueString = when (entry.value) {
+      is VimString -> "'${entry.value}'"
+      else -> entry.value.toString()
+    }
+    return "'${entry.key}': $valueString"
   }
 
   override fun asBoolean(): Boolean {
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt b/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt
index 90ed71c93..a1285f13f 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt
@@ -23,22 +23,27 @@ import com.intellij.openapi.editor.Editor
 import com.maddyhome.idea.vim.ex.ExException
 import com.maddyhome.idea.vim.vimscript.model.Executable
 import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
+import com.maddyhome.idea.vim.vimscript.model.expressions.Scope
 import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
+import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
 import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
 import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
+import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
 import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
+import com.maddyhome.idea.vim.vimscript.services.VariableService
 
 data class VimFuncref(
   val handler: FunctionHandler,
   val arguments: VimList,
-  val dictionary: VimDictionary,
+  var dictionary: VimDictionary?,
   val type: Type,
-) : VimDataType() {
+) : VimDataType(), Cloneable {
 
   var isSelfFixed = false
 
   companion object {
-    var lambdaCounter = 0
+    var lambdaCounter = 1
+    var anonymousCounter = 1
   }
 
   override fun asDouble(): Double {
@@ -50,14 +55,19 @@ data class VimFuncref(
   }
 
   override fun toString(): String {
-    return if (arguments.values.isEmpty()) {
+    return if (arguments.values.isEmpty() && dictionary == null) {
       when (type) {
         Type.LAMBDA -> "function('${handler.name}')"
         Type.FUNCREF -> "function('${handler.name}')"
         Type.FUNCTION -> handler.name
       }
     } else {
-      "function('${handler.name}', $arguments)"
+      val result = StringBuffer("function('${handler.name}'")
+      if (arguments.values.isNotEmpty()) {
+        result.append(", ").append(arguments.toString())
+      }
+      result.append(")")
+      return result.toString()
     }
   }
 
@@ -65,7 +75,21 @@ data class VimFuncref(
     throw ExException("E703: using Funcref as a Number")
   }
 
-  fun execute(args: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType {
+  fun execute(name: String, args: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType {
+    if (handler is DefinedFunctionHandler && handler.function.flags.contains(FunctionFlag.DICT)) {
+      if (dictionary == null) {
+        throw ExException("E725: Calling dict function without Dictionary: $name")
+      } else {
+        VariableService.storeVariable(
+          Variable(Scope.LOCAL_VARIABLE, "self"),
+          dictionary!!,
+          editor,
+          context,
+          handler.function
+        )
+      }
+    }
+
     val allArguments = listOf(this.arguments.values.map { SimpleExpression(it) }, args).flatten()
       if (handler is DefinedFunctionHandler && handler.function.isDeleted) {
         throw ExException("E933: Function was deleted: ${handler.name}")
@@ -80,6 +104,10 @@ data class VimFuncref(
       return handler.executeFunction(allArguments, editor, context, parent)
     }
 
+    override fun clone(): Any {
+      return VimFuncref(handler, arguments, dictionary, type)
+    }
+
     enum class Type {
       LAMBDA,
       FUNCREF,
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt b/src/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt
index c2417d2fc..41db174c6 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt
@@ -23,15 +23,23 @@ import com.intellij.openapi.editor.Editor
 import com.maddyhome.idea.vim.vimscript.model.Executable
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary
+import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
 import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
+import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
 
 data class DictionaryExpression(val dictionary: LinkedHashMap<Expression, Expression>) : Expression() {
 
   override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
-    val dict: LinkedHashMap<VimString, VimDataType> = linkedMapOf()
+    val dict = VimDictionary(linkedMapOf())
     for ((key, value) in dictionary) {
-      dict[VimString(key.evaluate(editor, context, parent).asString())] = value.evaluate(editor, context, parent)
+      val evaluatedVal = value.evaluate(editor, context, parent)
+      var newFuncref = evaluatedVal
+      if (evaluatedVal is VimFuncref && evaluatedVal.handler is DefinedFunctionHandler && !evaluatedVal.isSelfFixed) {
+        newFuncref = evaluatedVal.copy()
+        newFuncref.dictionary = dict
+      }
+      dict.dictionary[VimString(key.evaluate(editor, context, parent).asString())] = newFuncref
     }
-    return VimDictionary(dict)
+    return dict
   }
 }
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt b/src/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt
index 01c4680c0..a17ac6769 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt
@@ -32,7 +32,7 @@ data class FuncrefCallExpression(val expression: Expression, val args: List<Expr
     val value = expression.evaluate(editor, context, parent)
     if (value is VimFuncref) {
       value.handler.ranges = ranges
-      return value.execute(args, editor, context, parent)
+      return value.execute(value.handler.name, args, editor, context, parent)
     } else {
       // todo more exceptions
       throw ExException("E15: Invalid expression")
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/expressions/FunctionCallExpression.kt b/src/com/maddyhome/idea/vim/vimscript/model/expressions/FunctionCallExpression.kt
index a9b457f45..7ab3e0393 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/expressions/FunctionCallExpression.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/expressions/FunctionCallExpression.kt
@@ -25,10 +25,8 @@ data class FunctionCallExpression(val scope: Scope?, val functionName: String, v
 
     val funcref = VariableService.getNullableVariableValue(Variable(scope, functionName), editor, context, parent)
     if (funcref is VimFuncref) {
-      if (funcref.handler is DefinedFunctionHandler && funcref.handler.function.flags.contains(FunctionFlag.DICT) && funcref.handler.function.self == null) {
-        throw ExException("E725: Calling dict function without Dictionary: ${(if (scope != null) scope.c + ":" else "") + functionName}")
-      }
-      return funcref.execute(arguments, editor, context, parent)
+      val name = (if (scope != null) scope.c + ":" else "") + functionName
+      return funcref.execute(name, arguments, editor, context, parent)
     }
     throw ExException("E117: Unknown function: ${if (scope != null) scope.c + ":" else ""}$functionName")
   }
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt b/src/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt
index 2e145117d..5b5be8e72 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt
@@ -27,6 +27,6 @@ class LambdaFunctionCallExpression(val lambda: LambdaExpression, val arguments:
 
   override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
     val funcref = lambda.evaluate(editor, context, parent)
-    return funcref.execute(arguments, editor, context, parent)
+    return funcref.execute("", arguments, editor, context, parent)
   }
 }
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt b/src/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt
index a0ff9456b..a7bee0ab8 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt
@@ -71,7 +71,11 @@ object FunctionFunctionHandler : FunctionHandler() {
     if (arg3 != null && arg3 !is VimDictionary) {
       throw ExException("E922: expected a dict")
     }
-    return VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCTION)
+    val funcref = VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary, VimFuncref.Type.FUNCTION)
+    if (dictionary != null) {
+      funcref.isSelfFixed = true
+    }
+    return funcref
   }
 }
 
@@ -115,7 +119,7 @@ object FuncrefFunctionHandler : FunctionHandler() {
     if (arg3 != null && arg3 !is VimDictionary) {
       throw ExException("E922: expected a dict")
     }
-    return VimFuncref(handler, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCREF)
+    return VimFuncref(handler, arglist ?: VimList(mutableListOf()), dictionary, VimFuncref.Type.FUNCREF)
   }
 }
 
diff --git a/src/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt b/src/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt
index 0d42a3fa2..898538c76 100644
--- a/src/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt
+++ b/src/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt
@@ -20,7 +20,6 @@ data class FunctionDeclaration(
 ) : Executable {
   override lateinit var parent: Executable
   var isDeleted = false
-  var self: VimDataType? = null
 
   /**
    * we store the "a:" and "l:" scope variables here
diff --git a/test/org/jetbrains/plugins/ideavim/ex/implementation/functions/DictionaryFunctionTest.kt b/test/org/jetbrains/plugins/ideavim/ex/implementation/functions/DictionaryFunctionTest.kt
new file mode 100644
index 000000000..7cd4f9adf
--- /dev/null
+++ b/test/org/jetbrains/plugins/ideavim/ex/implementation/functions/DictionaryFunctionTest.kt
@@ -0,0 +1,222 @@
+/*
+ * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
+ * Copyright (C) 2003-2021 The IdeaVim authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.jetbrains.plugins.ideavim.ex.implementation.functions
+
+import org.jetbrains.plugins.ideavim.SkipNeovimReason
+import org.jetbrains.plugins.ideavim.TestWithoutNeovim
+import org.jetbrains.plugins.ideavim.VimTestCase
+
+class DictionaryFunctionTest : VimTestCase() {
+
+  fun `test self in dictionary function with assignment via function function`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self.data |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'data': [], 'print': function('Print')}"))
+    typeText(commandToKeys("call dict.print()"))
+    assertExOutput("[]\n")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  fun `test self in dictionary function with assignment via let command`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self.name |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'name': 'dict_name'}"))
+    typeText(commandToKeys("let PrintFr = function('Print')"))
+    typeText(commandToKeys("let dict.print = PrintFr"))
+    typeText(commandToKeys("call dict.print()"))
+    assertExOutput("dict_name\n")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  @TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
+  fun `test dictionary function without dict`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("call Print()"))
+    assertPluginError(true)
+    assertPluginErrorMessageContains("E725: Calling dict function without Dictionary: Print")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  // todo big brain logic
+//  fun `test assigned dictionary function to another dictionary`() {
+//    configureByText("\n")
+//    typeText(
+//      commandToKeys(
+//        """
+//           function Print() dict |
+//             echo self.name |
+//           endfunction
+//        """.trimIndent()
+//      )
+//    )
+//    typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
+//    typeText(commandToKeys("echo dict.print"))
+//    assertExOutput("function('Print', {'name': 'dict', 'print': function('Print')}")
+//    typeText(commandToKeys("echo dict"))
+//    assertExOutput("{'name': 'dict', 'print': function('Print')}")
+//    typeText(commandToKeys("call dict.print()"))
+//    assertExOutput("dict\n")
+//
+//    typeText(commandToKeys("let dict2 = {'name': 'dict2', 'print': dict.print}"))
+//    typeText(commandToKeys("echo dict2.print"))
+//    assertExOutput("function('Print', {'name': 'dict2', 'print': function('Print', {name: 'dict', 'print': function('Print')})}")
+//    typeText(commandToKeys("echo dict2"))
+//    assertExOutput("{'name': 'dict2', 'print': function('Print', {name: 'dict', 'print': function('Print')})}")
+//    typeText(commandToKeys("call dict2.print()"))
+//    assertExOutput("dict2\n")
+//
+//    typeText(commandToKeys("delfunction! Print"))
+//  }
+
+  fun `test self is not changed after let assignment`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self.name |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
+    typeText(commandToKeys("let dict2 = {'name': 'dict2'}"))
+    typeText(commandToKeys("let dict2.print = dict.print"))
+
+    typeText(commandToKeys("call dict2.print()"))
+    assertExOutput("dict2\n")
+
+    typeText(commandToKeys("call dict.print()"))
+    assertExOutput("dict\n")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  fun `test self is not changed after in-dictionary assignment`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self.name |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
+    typeText(commandToKeys("let dict2 = {'name': 'dict2', 'print': dict.print}"))
+
+    typeText(commandToKeys("call dict2.print()"))
+    assertExOutput("dict2\n")
+
+    typeText(commandToKeys("call dict.print()"))
+    assertExOutput("dict\n")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  fun `test assigned partial to another dictionary`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self.name |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'name': 'dict'}"))
+    typeText(commandToKeys("let dict.print = function('Print', dict)"))
+    typeText(commandToKeys("call dict.print()"))
+    assertExOutput("dict\n")
+
+    typeText(commandToKeys("let dict2 = {'name': 'dict2', 'print': dict.print}"))
+    typeText(commandToKeys("call dict2.print()"))
+    assertExOutput("dict\n")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  @TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
+  fun `test self is read-only`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             let self = [] |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
+    typeText(commandToKeys("call dict.print()"))
+    assertPluginError(true)
+    assertPluginErrorMessageContains("E46: Cannot change read-only variable \"self\"")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+
+  fun `test self in inner dictionary`() {
+    configureByText("\n")
+    typeText(
+      commandToKeys(
+        """
+           function Print() dict |
+             echo self.name |
+           endfunction
+        """.trimIndent()
+      )
+    )
+    typeText(commandToKeys("let dict = {'name': 'dict', 'innerDict': {'name': 'innerDict', 'print': function('Print')}}"))
+    typeText(commandToKeys("call dict.innerDict.print()"))
+    assertExOutput("innerDict\n")
+
+    typeText(commandToKeys("delfunction! Print"))
+  }
+}
diff --git a/vimscript-info/VIMSCRIPT_ROADMAP.md b/vimscript-info/VIMSCRIPT_ROADMAP.md
index 24a91d3b1..5a5c0c0b6 100644
--- a/vimscript-info/VIMSCRIPT_ROADMAP.md
+++ b/vimscript-info/VIMSCRIPT_ROADMAP.md
@@ -27,9 +27,8 @@
 - [x] function as method
 - [x] `function` function
 - [x] `funcref` function
-- [ ] dictionary functions  
+- [x] `dict` function flag
 - [ ] anonymous functions  
-- [ ] `dict` function flag
 - [ ] default value in functions e.g. `function F1(a, b = 10)`
 - [ ] delayed parsing of if/for/while etc.
 - [ ] `has("ide")` or "ide" option