Нет. Результат $hash{nonexistent} это undef а не def даже в показанном вами примере. Тут работу делает функция push.
Это lvalue context. Ничего общего с autovivification который указывал вадим здесь нет. Последний работает в rvalue context.
В общих чертах: элементы массивов и хешей в lvalue контексте автосоздаются со значением undef. А затем естессно присвается чтото в них.
Пример с push более сложен чем кажется многим.
Во первых push на самом деле принимает arrayref, это лишь синтаксическая видимость что там просто array. Когда вы передаете туда @$arr, Никакого разыменования arrayref там нет, иначе бы сразу отьехали с эксепшеном когда там undef.
Push если ему передали lvalue undef апгрейдит его до arrayref. Если rvalue undef то вылетит.
А так как push провоцирует lvalue context, то элемент хеша автосоздается со значением undef, и этот lvalue undef уходит в пуш и апгрейдится.
Примеры
push @{undef()}, 1;
Вылет, изменение rvalue undef запрещено.
my $a = undef;
push @$a, 1;
Все ок, апгрейд lvalue undef до arrayref
my %h;
say $h{key1};
Rvalue context, элемент не создается.
$h{key1}++;
Lvalue context, элемент создается при поиске как undef, затем выполняется операция.
say $h{h}{key};
Оба поиска в rvalue context. Первый уровень создается механизмом autovivification.
$h{h}{key}++;
Первый поиск rvalue и создает autovivification, второй поиск lvalue, и создает undef через hash lvalue fetch
say @{$h{arr}};
Вылет. Разыменование всегда отьезжает на undefe
push @{$h{arr}}, 1;
Ок, lvalue context, результат lvalue undef, и далее в пуше он апгрейдится.
Да. Я поспешил скпазать о том, что хешевый элемент от ундеф есть деф. Пардон.