patch 8.2.3442: Vim9: || and && are not handled at compile time

Problem:    Vim9: || and && are not handled at compile time when possible.
Solution:   When using constants generate fewer instructions.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 4807e3a..0d64f01 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2847,7 +2847,7 @@
 }
 
 /*
- * Check that the last item of "ppconst" is a bool.
+ * Check that the last item of "ppconst" is a bool, if there is an item.
  */
     static int
 check_ppconst_bool(ppconst_T *ppconst)
@@ -4845,7 +4845,8 @@
 	}
 	else
 	{
-	    if (generate_ppconst(cctx, ppconst) == FAIL)
+	    if (cctx->ctx_skip != SKIP_YES
+				    && generate_ppconst(cctx, ppconst) == FAIL)
 		return FAIL;
 	    r = compile_load(arg, p, cctx, TRUE, TRUE);
 	}
@@ -5240,6 +5241,7 @@
     {
 	garray_T	*instr = &cctx->ctx_instr;
 	garray_T	end_ga;
+	int		save_skip = cctx->ctx_skip;
 
 	/*
 	 * Repeat until there is no following "||" or "&&"
@@ -5251,7 +5253,10 @@
 	    long	save_sourcing_lnum;
 	    int		start_ctx_lnum = cctx->ctx_lnum;
 	    int		save_lnum;
+	    int		const_used;
 	    int		status;
+	    jumpwhen_T	jump_when = opchar == '|'
+				      ? JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE;
 
 	    if (next != NULL)
 	    {
@@ -5274,14 +5279,38 @@
 	    status = check_ppconst_bool(ppconst);
 	    if (status != FAIL)
 	    {
-		// TODO: use ppconst if the value is a constant
-		generate_ppconst(cctx, ppconst);
+		// Use the last ppconst if possible.
+		if (ppconst->pp_used > 0)
+		{
+		    typval_T	*tv = &ppconst->pp_tv[ppconst->pp_used - 1];
+		    int		is_true = tv2bool(tv);
 
-		// Every part must evaluate to a bool.
-		status = bool_on_stack(cctx);
-		if (status != FAIL)
-		    status = ga_grow(&end_ga, 1);
+		    if ((is_true && opchar == '|')
+						|| (!is_true && opchar == '&'))
+		    {
+			// For "false && expr" and "true || expr" the "expr"
+			// does not need to be evaluated.
+			cctx->ctx_skip = SKIP_YES;
+			clear_tv(tv);
+			tv->v_type = VAR_BOOL;
+			tv->vval.v_number = is_true ? VVAL_TRUE : VVAL_FALSE;
+		    }
+		    else
+		    {
+			// For "true && expr" and "false || expr" only "expr"
+			// needs to be evaluated.
+			--ppconst->pp_used;
+			jump_when = JUMP_NEVER;
+		    }
+		}
+		else
+		{
+		    // Every part must evaluate to a bool.
+		    status = bool_on_stack(cctx);
+		}
 	    }
+	    if (status != FAIL)
+		status = ga_grow(&end_ga, 1);
 	    cctx->ctx_lnum = save_lnum;
 	    if (status == FAIL)
 	    {
@@ -5289,10 +5318,15 @@
 		return FAIL;
 	    }
 
-	    *(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
-	    ++end_ga.ga_len;
-	    generate_JUMP(cctx, opchar == '|'
-				 ?  JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0);
+	    if (jump_when != JUMP_NEVER)
+	    {
+		if (cctx->ctx_skip != SKIP_YES)
+		{
+		    *(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
+		    ++end_ga.ga_len;
+		}
+		generate_JUMP(cctx, jump_when, 0);
+	    }
 
 	    // eval the next expression
 	    SOURCING_LNUM = save_sourcing_lnum;
@@ -5302,6 +5336,7 @@
 		return FAIL;
 	    }
 
+	    const_used = ppconst->pp_used;
 	    if ((opchar == '|' ? compile_expr3(arg, cctx, ppconst)
 				  : compile_expr4(arg, cctx, ppconst)) == FAIL)
 	    {
@@ -5309,6 +5344,20 @@
 		return FAIL;
 	    }
 
+	    // "0 || 1" results in true, "1 && 0" results in false.
+	    if (ppconst->pp_used == const_used + 1)
+	    {
+		typval_T	*tv = &ppconst->pp_tv[ppconst->pp_used - 1];
+
+		if (tv->v_type == VAR_NUMBER
+			 && (tv->vval.v_number == 1 || tv->vval.v_number == 0))
+		{
+		    tv->vval.v_number = tv->vval.v_number == 1
+						      ? VVAL_TRUE : VVAL_FALSE;
+		    tv->v_type = VAR_BOOL;
+		}
+	    }
+
 	    p = may_peek_next_line(cctx, *arg, &next);
 	}
 
@@ -5317,26 +5366,32 @@
 	    ga_clear(&end_ga);
 	    return FAIL;
 	}
-	generate_ppconst(cctx, ppconst);
 
-	// Every part must evaluate to a bool.
-	if (bool_on_stack(cctx) == FAIL)
+	if (cctx->ctx_skip != SKIP_YES && ppconst->pp_used == 0)
+	    // Every part must evaluate to a bool.
+	    if (bool_on_stack(cctx) == FAIL)
+	    {
+		ga_clear(&end_ga);
+		return FAIL;
+	    }
+
+	if (end_ga.ga_len > 0)
 	{
-	    ga_clear(&end_ga);
-	    return FAIL;
-	}
+	    // Fill in the end label in all jumps.
+	    generate_ppconst(cctx, ppconst);
+	    while (end_ga.ga_len > 0)
+	    {
+		isn_T	*isn;
 
-	// Fill in the end label in all jumps.
-	while (end_ga.ga_len > 0)
-	{
-	    isn_T	*isn;
-
-	    --end_ga.ga_len;
-	    isn = ((isn_T *)instr->ga_data)
+		--end_ga.ga_len;
+		isn = ((isn_T *)instr->ga_data)
 				  + *(((int *)end_ga.ga_data) + end_ga.ga_len);
-	    isn->isn_arg.jump.jump_where = instr->ga_len;
+		isn->isn_arg.jump.jump_where = instr->ga_len;
+	    }
+	    ga_clear(&end_ga);
 	}
-	ga_clear(&end_ga);
+
+	cctx->ctx_skip = save_skip;
     }
 
     return OK;