patch 9.0.1031: Vim9 class is not implemented yet

Problem:    Vim9 class is not implemented yet.
Solution:   Add very basic class support.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 17066b0..ab9e965 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -43,6 +43,20 @@
     if (len == 0)
 	return FAIL;
 
+    if (len == 4 && STRNCMP(name, "this", 4) == 0
+	    && cctx->ctx_ufunc != NULL
+	    && (cctx->ctx_ufunc->uf_flags & FC_OBJECT))
+    {
+	if (lvar != NULL)
+	{
+	    CLEAR_POINTER(lvar);
+	    lvar->lv_name = (char_u *)"this";
+	    if (cctx->ctx_ufunc->uf_class != NULL)
+		lvar->lv_type = &cctx->ctx_ufunc->uf_class->class_type;
+	}
+	return OK;
+    }
+
     // Find local in current function scope.
     for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
     {
@@ -296,7 +310,11 @@
 {
     return (cctx != NULL
 		&& (lookup_local(name, len, NULL, cctx) == OK
-		    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
+		    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK
+		    || (len == 4
+			&& cctx->ctx_ufunc != NULL
+			&& (cctx->ctx_ufunc->uf_flags & FC_OBJECT)
+			&& STRNCMP(name, "this", 4) == 0)))
 	    || script_var_exists(name, len, cctx, NULL) == OK
 	    || find_imported(name, len, FALSE) != NULL;
 }
@@ -957,7 +975,7 @@
 	goto theend;
     }
 
-    ufunc = define_function(eap, lambda_name, lines_to_free);
+    ufunc = define_function(eap, lambda_name, lines_to_free, NULL);
     if (ufunc == NULL)
     {
 	r = eap->skip ? OK : FAIL;
@@ -1450,6 +1468,7 @@
     lhs->lhs_dest = dest_local;
     lhs->lhs_vimvaridx = -1;
     lhs->lhs_scriptvar_idx = -1;
+    lhs->lhs_member_idx = -1;
 
     // "dest_end" is the end of the destination, including "[expr]" or
     // ".name".
@@ -1509,7 +1528,7 @@
 	else
 	{
 	    // No specific kind of variable recognized, just a name.
-	    if (check_reserved_name(lhs->lhs_name) == FAIL)
+	    if (check_reserved_name(lhs->lhs_name, cctx) == FAIL)
 		return FAIL;
 
 	    if (lookup_local(var_start, lhs->lhs_varlen,
@@ -1757,8 +1776,16 @@
 	    lhs->lhs_type = &t_any;
 	}
 
-	if (lhs->lhs_type->tt_member == NULL)
+	if (lhs->lhs_type == NULL || lhs->lhs_type->tt_member == NULL)
 	    lhs->lhs_member_type = &t_any;
+	else if (lhs->lhs_type->tt_type == VAR_CLASS
+		|| lhs->lhs_type->tt_type == VAR_OBJECT)
+	{
+	    // for an object or class member get the type of the member
+	    class_T *cl = (class_T *)lhs->lhs_type->tt_member;
+	    lhs->lhs_member_type = class_member_type(cl, after + 1,
+					   lhs->lhs_end, &lhs->lhs_member_idx);
+	}
 	else
 	    lhs->lhs_member_type = lhs->lhs_type->tt_member;
     }
@@ -1880,6 +1907,11 @@
 	    r = FAIL;
 	}
     }
+    else if (lhs->lhs_member_idx >= 0)
+    {
+	// object member index
+	r = generate_PUSHNR(cctx, lhs->lhs_member_idx);
+    }
     else // if (*p == '.')
     {
 	char_u *key_end = to_name_end(p + 1, TRUE);
@@ -1996,7 +2028,7 @@
 	return FAIL;
     }
 
-    if (lhs->lhs_type == &t_any)
+    if (lhs->lhs_type == NULL || lhs->lhs_type == &t_any)
     {
 	// Index on variable of unknown type: check at runtime.
 	dest_type = VAR_ANY;
@@ -2042,8 +2074,12 @@
     if (compile_load_lhs(lhs, var_start, rhs_type, cctx) == FAIL)
 	return FAIL;
 
-    if (dest_type == VAR_LIST || dest_type == VAR_DICT
-			      || dest_type == VAR_BLOB || dest_type == VAR_ANY)
+    if (dest_type == VAR_LIST
+	    || dest_type == VAR_DICT
+	    || dest_type == VAR_BLOB
+	    || dest_type == VAR_CLASS
+	    || dest_type == VAR_OBJECT
+	    || dest_type == VAR_ANY)
     {
 	if (is_assign)
 	{
@@ -2466,6 +2502,8 @@
 		    case VAR_PARTIAL:
 		    case VAR_VOID:
 		    case VAR_INSTR:
+		    case VAR_CLASS:
+		    case VAR_OBJECT:
 		    case VAR_SPECIAL:  // cannot happen
 			// This is skipped for local variables, they are always
 			// initialized to zero.  But in a "for" or "while" loop
@@ -2897,6 +2935,22 @@
     if (check_args_shadowing(ufunc, &cctx) == FAIL)
 	goto erret;
 
+    // For an object method and constructor "this" is the first local variable.
+    if (ufunc->uf_flags & FC_OBJECT)
+    {
+	dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+							 + ufunc->uf_dfunc_idx;
+	if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
+	    goto erret;
+	((char_u **)dfunc->df_var_names.ga_data)[0] =
+						 vim_strsave((char_u *)"this");
+	++dfunc->df_var_names.ga_len;
+
+	// In the constructor allocate memory for the object.
+	if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
+	    generate_CONSTRUCT(&cctx, ufunc->uf_class);
+    }
+
     if (ufunc->uf_def_args.ga_len > 0)
     {
 	int	count = ufunc->uf_def_args.ga_len;
@@ -3500,14 +3554,19 @@
     {
 	if (ufunc->uf_ret_type->tt_type == VAR_UNKNOWN)
 	    ufunc->uf_ret_type = &t_void;
-	else if (ufunc->uf_ret_type->tt_type != VAR_VOID)
+	else if (ufunc->uf_ret_type->tt_type != VAR_VOID
+		&& (ufunc->uf_flags & FC_NEW) != FC_NEW)
 	{
 	    emsg(_(e_missing_return_statement));
 	    goto erret;
 	}
 
 	// Return void if there is no return at the end.
-	generate_instr(&cctx, ISN_RETURN_VOID);
+	// For a constructor return the object.
+	if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
+	    generate_instr(&cctx, ISN_RETURN_OBJECT);
+	else
+	    generate_instr(&cctx, ISN_RETURN_VOID);
     }
 
     // When compiled with ":silent!" and there was an error don't consider the