patch 9.0.1054: object member can't get type from initializer

Problem:    Object member can't get type from initializer.
Solution:   If there is no type specified try to use the type of the
            initializer.  Check for a valid type.
diff --git a/src/errors.h b/src/errors.h
index 9c8d593..2cf29cc 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3374,4 +3374,8 @@
 	INIT(= N_("E1327: Object required, found %s"));
 EXTERN char e_constructor_default_value_must_be_vnone_str[]
 	INIT(= N_("E1328: Constructor default value must be v:none: %s"));
+EXTERN char e_cannot_get_object_member_type_from_initializer_str[]
+	INIT(= N_("E1329: Cannot get object member type from initializer: %s"));
+EXTERN char e_invalid_type_for_object_member_str[]
+	INIT(= N_("E1330: Invalid type for object member: %s"));
 #endif
diff --git a/src/proto/vim9type.pro b/src/proto/vim9type.pro
index 98c6091..d5e4d48 100644
--- a/src/proto/vim9type.pro
+++ b/src/proto/vim9type.pro
@@ -13,6 +13,7 @@
 int type_any_or_unknown(type_T *type);
 int need_convert_to_bool(type_T *type, typval_T *tv);
 type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags);
+int valid_declaration_type(type_T *type);
 type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
 int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
 int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 3f66f3f..7eecdda 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -231,7 +231,58 @@
       assert_equal("none", chris.education)
   END
   v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      class Person
+        this.name: string
+        this.age: number = 42
+        this.education: string = "unknown"
+
+        def new(this.name, this.age = v:none, this.education = v:none)
+        enddef
+      endclass
+
+      var missing = Person.new()
+  END
+  v9.CheckScriptFailure(lines, 'E119:')
 enddef
 
+def Test_class_object_member_inits()
+  var lines =<< trim END
+      vim9script
+      class TextPosition
+        this.lnum: number
+        this.col = 1
+        this.addcol: number = 2
+      endclass
+
+      var pos = TextPosition.new()
+      assert_equal(0, pos.lnum)
+      assert_equal(1, pos.col)
+      assert_equal(2, pos.addcol)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      class TextPosition
+        this.lnum
+        this.col = 1
+      endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1022:')
+
+  lines =<< trim END
+      vim9script
+      class TextPosition
+        this.lnum = v:none
+        this.col = 1
+      endclass
+  END
+  v9.CheckScriptFailure(lines, 'E1330:')
+enddef
+
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/version.c b/src/version.c
index fbc5956..6ab6ddc 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1054,
+/**/
     1053,
 /**/
     1052,
diff --git a/src/vim9class.c b/src/vim9class.c
index 74a9bf3..1713496 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -125,43 +125,74 @@
 	    char_u *varname_end = to_name_end(varname, FALSE);
 
 	    char_u *colon = skipwhite(varname_end);
-	    // TODO: accept initialization and figure out type from it
-	    if (*colon != ':')
+	    char_u *type_arg = colon;
+	    type_T *type = NULL;
+	    if (*colon == ':')
+	    {
+		if (VIM_ISWHITE(*varname_end))
+		{
+		    semsg(_(e_no_white_space_allowed_before_colon_str),
+								      varname);
+		    break;
+		}
+		if (!VIM_ISWHITE(colon[1]))
+		{
+		    semsg(_(e_white_space_required_after_str_str), ":",
+								      varname);
+		    break;
+		}
+		type_arg = skipwhite(colon + 1);
+		type = parse_type(&type_arg, &type_list, TRUE);
+		if (type == NULL)
+		    break;
+	    }
+
+	    char_u *expr_start = skipwhite(type_arg);
+	    char_u *expr_end = expr_start;
+	    if (type == NULL && *expr_start != '=')
 	    {
 		emsg(_(e_type_or_initialization_required));
 		break;
 	    }
-	    if (VIM_ISWHITE(*varname_end))
-	    {
-		semsg(_(e_no_white_space_allowed_before_colon_str), varname);
-		break;
-	    }
-	    if (!VIM_ISWHITE(colon[1]))
-	    {
-		semsg(_(e_white_space_required_after_str_str), ":", varname);
-		break;
-	    }
 
-	    char_u *type_arg = skipwhite(colon + 1);
-	    type_T *type = parse_type(&type_arg, &type_list, TRUE);
-	    if (type == NULL)
-		break;
-
-	    char_u *expr_start = skipwhite(type_arg);
-	    if (*expr_start == '=' && (!VIM_ISWHITE(expr_start[-1])
-					       || !VIM_ISWHITE(expr_start[1])))
+	    if (*expr_start == '=')
 	    {
-		semsg(_(e_white_space_required_before_and_after_str_at_str),
+		if (!VIM_ISWHITE(expr_start[-1]) || !VIM_ISWHITE(expr_start[1]))
+		{
+		    semsg(_(e_white_space_required_before_and_after_str_at_str),
 								"=", type_arg);
-		break;
-	    }
-	    expr_start = skipwhite(expr_start + 1);
+		    break;
+		}
+		expr_start = skipwhite(expr_start + 1);
 
-	    char_u *expr_end = expr_start;
-	    evalarg_T	evalarg;
-	    init_evalarg(&evalarg);
-	    skip_expr(&expr_end, &evalarg);
-	    clear_evalarg(&evalarg, NULL);
+		expr_end = expr_start;
+		evalarg_T evalarg;
+		fill_evalarg_from_eap(&evalarg, eap, FALSE);
+		skip_expr(&expr_end, &evalarg);
+
+		if (type == NULL)
+		{
+		    // No type specified, use the type of the initializer.
+		    typval_T tv;
+		    tv.v_type = VAR_UNKNOWN;
+		    char_u *expr = expr_start;
+		    int res = eval0(expr, &tv, eap, &evalarg);
+
+		    if (res == OK)
+			type = typval2type(&tv, get_copyID(), &type_list,
+							       TVTT_DO_MEMBER);
+		    if (type == NULL)
+		    {
+			semsg(_(e_cannot_get_object_member_type_from_initializer_str),
+				expr_start);
+			clear_evalarg(&evalarg, NULL);
+			break;
+		    }
+		}
+		clear_evalarg(&evalarg, NULL);
+	    }
+	    if (!valid_declaration_type(type))
+		break;
 
 	    if (ga_grow(&objmembers, 1) == FAIL)
 		break;
diff --git a/src/vim9type.c b/src/vim9type.c
index 2d55cf2..0709ce0 100644
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -425,6 +425,17 @@
 	return &t_number;
     if (tv->v_type == VAR_BOOL)
 	return &t_bool;
+    if (tv->v_type == VAR_SPECIAL)
+    {
+	if (tv->vval.v_number == VVAL_NULL)
+	    return &t_null;
+	if (tv->vval.v_number == VVAL_NONE)
+	    return &t_none;
+	if (tv->vval.v_number == VVAL_TRUE
+		|| tv->vval.v_number == VVAL_TRUE)
+	    return &t_bool;
+	return &t_unknown;
+    }
     if (tv->v_type == VAR_STRING)
 	return &t_string;
     if (tv->v_type == VAR_BLOB)
@@ -620,6 +631,25 @@
 }
 
 /*
+ * Return TRUE if "type" can be used for a variable declaration.
+ * Give an error and return FALSE if not.
+ */
+    int
+valid_declaration_type(type_T *type)
+{
+    if (type->tt_type == VAR_SPECIAL  // null, none
+	    || type->tt_type == VAR_VOID)
+    {
+	char *tofree = NULL;
+	char *name = type_name(type, &tofree);
+	semsg(_(e_invalid_type_for_object_member_str), name);
+	vim_free(tofree);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+/*
  * Get a type_T for a typval_T, used for v: variables.
  * "type_list" is used to temporarily create types in.
  */