patch 8.2.0972: Vim9 script variable declarations need a type

Problem:    Vim9 script variable declarations need a type.
Solution:   Make "let var: type" declare a script-local variable.
diff --git a/src/evalvars.c b/src/evalvars.c
index f2128a6..8a7162c 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -728,8 +728,18 @@
 	else if (expr[0] == '.')
 	    emsg(_("E985: .= is not supported with script version 2"));
 	else if (!ends_excmd2(eap->cmd, arg))
-	    // ":let var1 var2"
-	    arg = list_arg_vars(eap, arg, &first);
+	{
+	    if (current_sctx.sc_version == SCRIPT_VERSION_VIM9)
+	    {
+		// Vim9 declaration ":let var: type"
+		arg = vim9_declare_scriptvar(eap, arg);
+	    }
+	    else
+	    {
+		// ":let var1 var2" - list values
+		arg = list_arg_vars(eap, arg, &first);
+	    }
+	}
 	else if (!eap->skip)
 	{
 	    // ":let"
diff --git a/src/globals.h b/src/globals.h
index e5dcb7b..f0b75e5 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1785,6 +1785,8 @@
 EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before '%s'"));
 
 EXTERN char e_lock_unlock[]	INIT(= N_("E940: Cannot lock or unlock variable %s"));
+EXTERN char e_const_req_value[] INIT(= N_("E1021: const requires a value"));
+EXTERN char e_type_req[]	INIT(= N_("E1022: type or initialization required"));
 #endif
 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
 EXTERN char e_alloc_color[]	INIT(= N_("E254: Cannot allocate color %s"));
diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro
index 1d8575d..45deed6 100644
--- a/src/proto/vim9script.pro
+++ b/src/proto/vim9script.pro
@@ -6,4 +6,5 @@
 void ex_import(exarg_T *eap);
 int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, type_T **type);
 char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx);
+char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
 /* vim: set ft=c : */
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index e9303f1..7674cc0 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -1815,6 +1815,22 @@
   CheckScriptSuccess(lines)
 enddef
 
+def Test_let_declaration()
+  let lines =<< trim END
+    vim9script
+    let var: string
+    g:var_uninit = var
+    var = 'text'
+    g:var_test = var
+  END
+  CheckScriptSuccess(lines)
+  assert_equal('', g:var_uninit)
+  assert_equal('text', g:var_test)
+
+  unlet g:var_uninit
+  unlet g:var_test
+enddef
+
 def Test_forward_declaration()
   let lines =<< trim END
     vim9script
diff --git a/src/version.c b/src/version.c
index ef0e0d1..2996d3b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    972,
+/**/
     971,
 /**/
     970,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 17c16d8..9029a48 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2255,7 +2255,8 @@
 }
 
 /*
- * Find "name" in imported items of the current script/
+ * Find "name" in imported items of the current script or in "cctx" if not
+ * NULL.
  */
     imported_T *
 find_imported(char_u *name, size_t len, cctx_T *cctx)
@@ -5012,12 +5013,12 @@
     }
     else if (cmdidx == CMD_const)
     {
-	emsg(_("E1021: const requires a value"));
+	emsg(_(e_const_req_value));
 	goto theend;
     }
     else if (!has_type || dest == dest_option)
     {
-	emsg(_("E1022: type or initialization required"));
+	emsg(_(e_type_req));
 	goto theend;
     }
     else
diff --git a/src/vim9script.c b/src/vim9script.c
index ca14702..51afa19 100644
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -434,4 +434,59 @@
     return cmd_end;
 }
 
+/*
+ * Declare a script-local variable without init: "let var: type".
+ * "const" is an error since the value is missing.
+ * Returns a pointer to after the type.
+ */
+    char_u *
+vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
+{
+    char_u	    *p;
+    char_u	    *name;
+    scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
+    type_T	    *type;
+    int		    called_emsg_before = called_emsg;
+    typval_T	    init_tv;
+
+    if (eap->cmdidx == CMD_const)
+    {
+	emsg(_(e_const_req_value));
+	return arg + STRLEN(arg);
+    }
+
+    // Check for valid starting character.
+    if (!eval_isnamec1(*arg))
+    {
+	semsg(_(e_invarg2), arg);
+	return arg + STRLEN(arg);
+    }
+
+    for (p = arg + 1; *p != NUL && *p != ':' && eval_isnamec(*p);
+								 MB_PTR_ADV(p))
+	;
+
+    if (*p != ':')
+    {
+	emsg(_(e_type_req));
+	return arg + STRLEN(arg);
+    }
+    name = vim_strnsave(arg, p - arg);
+
+    // parse type
+    p = skipwhite(p + 1);
+    type = parse_type(&p, &si->sn_type_list);
+    if (called_emsg != called_emsg_before)
+	return p;
+
+    // Create the variable with 0/NULL value.
+    CLEAR_FIELD(init_tv);
+    init_tv.v_type = type->tt_type;
+    set_var_const(name, type, &init_tv, FALSE, 0);
+
+    vim_free(name);
+    return p;
+}
+
+
 #endif // FEAT_EVAL