sub _inline_set_value {
my $self = shift;
- my ($instance, $value, $tc, $coercion, $tc_obj, $for_constructor) = @_;
+ my ($instance, $value, $tc, $coercion, $message, $for_constructor) = @_;
my $old = '@old';
my $copy = '$val';
$tc ||= '$type_constraint';
$coercion ||= '$type_coercion';
- $tc_obj ||= '$type_constraint_obj';
+ $message ||= '$type_message';
my @code;
if ($self->_writer_value_needs_copy) {
push @code, $self->_inline_check_required
unless $for_constructor;
- push @code, $self->_inline_tc_code($value, $tc, $coercion, $tc_obj);
+ push @code, $self->_inline_tc_code($value, $tc, $coercion, $message);
# constructors do triggers all at once at the end
push @code, $self->_inline_get_old_value_for_trigger($instance, $old)
sub _inline_tc_code {
my $self = shift;
- my ($value, $tc, $coercion, $tc_obj, $is_lazy) = @_;
+ my ($value, $tc, $coercion, $message, $is_lazy) = @_;
return (
$self->_inline_check_coercion(
$value, $tc, $coercion, $is_lazy,
),
$self->_inline_check_constraint(
- $value, $tc, $tc_obj, $is_lazy,
+ $value, $tc, $message, $is_lazy,
),
);
}
sub _inline_check_constraint {
my $self = shift;
- my ($value, $tc, $tc_obj) = @_;
+ my ($value, $tc, $message) = @_;
return unless $self->has_type_constraint;
$self->_inline_throw_error(
'"Attribute (' . $attr_name . ') does not pass the type '
. 'constraint because: " . '
- . $tc_obj . '->get_message(' . $value . ')',
+ . 'do { local $_ = ' . $value . '; '
+ . $message . '->(' . $value . ')'
+ . '}',
'data => ' . $value
) . ';',
'}',
$self->_inline_throw_error(
'"Attribute (' . $attr_name . ') does not pass the type '
. 'constraint because: " . '
- . $tc_obj . '->get_message(' . $value . ')',
+ . 'do { local $_ = ' . $value . '; '
+ . $message . '->(' . $value . ')'
+ . '}',
'data => ' . $value
) . ';',
'}',
sub _inline_get_value {
my $self = shift;
- my ($instance, $tc, $coercion, $tc_obj) = @_;
+ my ($instance, $tc, $coercion, $message) = @_;
my $slot_access = $self->_inline_instance_get($instance);
$tc ||= '$type_constraint';
$coercion ||= '$type_coercion';
- $tc_obj ||= '$type_constraint_obj';
+ $message ||= '$type_message';
return (
- $self->_inline_check_lazy($instance, $tc, $coercion, $tc_obj),
+ $self->_inline_check_lazy($instance, $tc, $coercion, $message),
$self->_inline_return_auto_deref($slot_access),
);
}
sub _inline_check_lazy {
my $self = shift;
- my ($instance, $tc, $coercion, $tc_obj) = @_;
+ my ($instance, $tc, $coercion, $message) = @_;
return unless $self->is_lazy;
return (
'if (!' . $slot_exists . ') {',
- $self->_inline_init_from_default($instance, '$default', $tc, $coercion, $tc_obj, 'lazy'),
+ $self->_inline_init_from_default($instance, '$default', $tc, $coercion, $message, 'lazy'),
'}',
);
}
sub _inline_init_from_default {
my $self = shift;
- my ($instance, $default, $tc, $coercion, $tc_obj, $for_lazy) = @_;
+ my ($instance, $default, $tc, $coercion, $message, $for_lazy) = @_;
if (!($self->has_default || $self->has_builder)) {
$self->throw_error(
# appropriate for checking the result of a default
$self->has_type_constraint
? ($self->_inline_check_coercion($default, $tc, $coercion, $for_lazy),
- $self->_inline_check_constraint($default, $tc, $tc_obj, $for_lazy))
+ $self->_inline_check_constraint($default, $tc, $message, $for_lazy))
: (),
$self->_inline_init_slot($instance, $default),
);
'$params->{\'' . $attr->init_arg . '\'}',
'$type_constraint_bodies[' . $idx . ']',
'$type_coercions[' . $idx . ']',
- '$type_constraints[' . $idx . ']',
+ '$type_constraint_messages[' . $idx . ']',
'for constructor',
);
'$default',
'$type_constraint_bodies[' . $idx . ']',
'$type_coercions[' . $idx . ']',
- '$type_constraints[' . $idx . ']',
+ '$type_constraint_messages[' . $idx . ']',
'for constructor',
),
);
if ($attr->has_type_constraint) {
my $tc_obj = $attr->type_constraint;
- # is this going to be an issue? it's currently only used for the tc
- # message. is there a way to inline that too?
- $env->{'$type_constraint_obj'} = \$tc_obj;
-
$env->{'$type_constraint'} = \(
$tc_obj->_compiled_type_constraint
) unless $tc_obj->can_be_inlined;
+ # these two could probably get inlined versions too
$env->{'$type_coercion'} = \(
$tc_obj->coercion->_compiled_type_coercion
) if $tc_obj->has_coercion;
+ $env->{'$type_message'} = \(
+ $tc_obj->has_message ? $tc_obj->message : $tc_obj->_default_message
+ );
$env = { %$env, %{ $tc_obj->inline_environment } };
}
'sub {',
'my ' . $inv . ' = shift;',
$self->_inline_curried_arguments,
- $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_constraint_obj'),
+ $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'),
# get
'if (@_ == 1) {',
$self->_inline_check_var_is_valid_index('$_[0]'),
sub _inline_tc_code {
my $self = shift;
- my ($value, $tc, $coercion, $tc_obj, $is_lazy) = @_;
+ my ($value, $tc, $coercion, $message, $is_lazy) = @_;
return unless $self->_constraint_must_be_checked;
else {
return (
$self->_inline_check_coercion($value, $tc, $coercion, $is_lazy),
- $self->_inline_check_constraint($value, $tc, $tc_obj, $is_lazy),
+ $self->_inline_check_constraint($value, $tc, $message, $is_lazy),
);
}
}
'sub {',
'my ' . $inv . ' = shift;',
$self->_inline_curried_arguments,
- $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_constraint_obj'),
+ $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'),
# get
'if (@_ == 1) {',
$self->_inline_check_var_is_valid_key('$_[0]'),
$self->_inline_check_argument_count,
$self->_inline_process_arguments($inv, $slot_access),
$self->_inline_check_arguments,
- $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_constraint_obj'),
+ $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'),
$self->_inline_return_value($slot_access),
);
}
$self->_inline_check_argument_count,
$self->_inline_process_arguments($inv, $slot_access),
$self->_inline_check_arguments('for writer'),
- $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_constraint_obj'),
+ $self->_inline_check_lazy($inv, '$type_constraint', '$type_coercion', '$type_message'),
);
if ($self->_return_value($slot_access)) {
push @code, (
$self->_inline_coerce_new_values,
$self->_inline_copy_native_value(\$potential),
- $self->_inline_tc_code($potential, '$type_constraint', '$type_coercion', '$type_constraint_obj'),
+ $self->_inline_tc_code($potential, '$type_constraint', '$type_coercion', '$type_message'),
$self->_inline_get_old_value_for_trigger($inv, $old),
$self->_inline_capture_return_value($slot_access),
$self->_inline_set_new_value($inv, $potential, $slot_access),
around _inline_tc_code => sub {
my $orig = shift;
my $self = shift;
- my ($value, $tc, $coercion, $tc_obj, $for_lazy) = @_;
+ my ($value, $tc, $coercion, $message, $for_lazy) = @_;
return unless $for_lazy || $self->_constraint_must_be_checked;
around _inline_check_constraint => sub {
my $orig = shift;
my $self = shift;
- my ($value, $tc, $tc_obj, $for_lazy) = @_;
+ my ($value, $tc, $message, $for_lazy) = @_;
return unless $for_lazy || $self->_constraint_must_be_checked;
: undef
} @type_constraints;
+ my @type_constraint_messages = map {
+ defined $_
+ ? ($_->has_message ? $_->message : $_->_default_message)
+ : undef
+ } @type_constraints;
+
return {
((any { defined && $_->has_initializer } @$attrs)
? ('$attrs' => \$attrs)
: ()),
'$defaults' => \$defaults,
'$triggers' => \$triggers,
- '@type_constraints' => \@type_constraints,
'@type_coercions' => \@type_coercions,
'@type_constraint_bodies' => \@type_constraint_bodies,
+ '@type_constraint_messages' => \@type_constraint_messages,
( map { defined($_) ? %{ $_->inline_environment } : () }
@type_constraints ),
# pretty sure this is only going to be closed over if you use a custom