From e0175cf6e353d86f6f75e4399dc221b05a527a6b Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Tue, 12 May 2026 13:45:08 -0600 Subject: [PATCH 1/2] Don't use student_formula to collect matrix array answer. When collecting a matrix array answer use `student_array` instead of `student_formula` as `student_formula` should always be a formula, and this could fail to convert to a formula if an answer blank is left empty, causing a future `typeMatch` error. Fixes #1406. --- lib/Value/AnswerChecker.pm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/Value/AnswerChecker.pm b/lib/Value/AnswerChecker.pm index 89735f56d..b7ab3c03f 100644 --- a/lib/Value/AnswerChecker.pm +++ b/lib/Value/AnswerChecker.pm @@ -194,9 +194,9 @@ sub cmp_collect { return 1 unless $self->{ans_name}; $ans->{preview_latex_string} = $ans->{preview_text_string} = ""; my $OK = $self->ans_collect($ans); - $ans->{student_ans} = $self->format_matrix($ans->{student_formula}, @{ $self->{format_options} }, tth_delims => 1); + $ans->{student_ans} = $self->format_matrix($ans->{student_array}, @{ $self->{format_options} }, tth_delims => 1); return 0 unless $OK; - my $array = $ans->{student_formula}; + my $array = $ans->{student_array}; if ($self->{ColumnVector}) { my @V = (); @@ -728,8 +728,9 @@ sub ans_collect { } push(@array, [@row]); } - $ans->{student_formula} = [@array]; - $ans->{ans_message} = $ans->{error_message} = ""; + delete $ans->{student_formula}; + $ans->{student_array} = [@array]; + $ans->{ans_message} = $ans->{error_message} = ''; if (scalar(@{$errors})) { $ans->{ans_message} = $ans->{error_message} = '' From b214dab7f2a8b2ee48819d29ff2a44a74ad9431d Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Thu, 14 May 2026 07:12:09 -0600 Subject: [PATCH 2/2] Use Value::isValue instead of ref in typeMatch. When checking if `$other` is an object, check that it is actually a `Value` object instead just that it is a reference in the various `typeMatch` methods. This is done by using `Value::isValue($other)` instead of `ref($other)`. In addition add a test for `Value::isValue($other)` in the `Value::Formula::typeMatch` method to be consistent with the other methods. This was suggested by @dpvc. --- lib/Value/AnswerChecker.pm | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/Value/AnswerChecker.pm b/lib/Value/AnswerChecker.pm index b7ab3c03f..9a620a2f4 100644 --- a/lib/Value/AnswerChecker.pm +++ b/lib/Value/AnswerChecker.pm @@ -295,7 +295,7 @@ sub cmp_list_compare { Value::List::cmp_list_compare(@_) } sub typeMatch { my $self = shift; my $other = shift; - return 1 unless ref($other); + return 1 unless Value::isValue($other); $self->type eq $other->type && !$other->isFormula; } @@ -852,7 +852,7 @@ sub typeMatch { my $self = shift; my $other = shift; my $ans = shift; - return 1 unless ref($other); + return 1 unless Value::isValue($other); return 0 if Value::isFormula($other); return 1 if $other->type eq 'Infinity' && $ans->{ignoreInfinity}; $self->type eq $other->type; @@ -868,7 +868,7 @@ sub typeMatch { my $self = shift; my $other = shift; my $ans = shift; - return 1 unless ref($other); + return 1 unless Value::isValue($other); return 0 if Value::isFormula($other); return 1 if $other->type eq 'Number'; $self->type eq $other->type; @@ -996,7 +996,7 @@ sub typeMatch { my $self = shift; my $other = shift; my $ans = shift; - return ref($other) && $other->type eq 'Point' && !$other->isFormula; + return Value::isValue($other) && $other->type eq 'Point' && !$other->isFormula; } # @@ -1086,7 +1086,7 @@ sub typeMatch { my $self = shift; my $other = shift; my $ans = shift; - return 0 unless ref($other) && !$other->isFormula; + return 0 unless Value::isValue($other) && !$other->isFormula; return $other->type eq 'Vector' || ($ans->{promotePoints} && $other->type eq 'Point'); } @@ -1214,7 +1214,7 @@ sub typeMatch { my $self = shift; my $other = shift; my $ans = shift; - return 0 unless ref($other) && !$other->isFormula; + return 0 unless Value::isValue($other) && !$other->isFormula; return $other->type eq 'Matrix' || ($other->type =~ m/^(Point|List)$/ && $other->{open} . $other->{close} eq $self->{open} . $self->{close}); @@ -1440,7 +1440,7 @@ package Value::Union; sub typeMatch { my $self = shift; my $other = shift; - return 0 unless ref($other) && !$other->isFormula; + return 0 unless Value::isValue($other) && !$other->isFormula; return $other->length == 2 && ($other->{open} eq '(' || $other->{open} eq '[') @@ -1550,7 +1550,7 @@ sub cmp_defaults { # # Match anything but formulas # -sub typeMatch { return !ref($other) || !$other->isFormula } +sub typeMatch { return !Value::isValue($other) || !$other->isFormula } # # Handle removal of outermost parens in correct answer. @@ -1902,7 +1902,7 @@ sub typeMatch { my $self = shift; my $other = shift; my $ans = shift; - return 1 if $self->type eq $other->type; + return 1 if !Value::isValue($other) || $self->type eq $other->type; my $typeMatch = $self->getTypicalValue($self); $other = $self->getTypicalValue($other, 1) if Value::isFormula($other); return 1 unless defined($other); # can't really tell, so don't report type mismatch