src/Extension/ProductVariationsExtension.php
public function onAfterDelete()
    {
        $remove = false;
        // if a record is staged or live, leave it's variations alone.
        if (!property_exists($this, 'owner')) {
            $remove = true;
        } else {
            $staged = Versioned::get_by_stage($this->owner->ClassName, 'Stage')
                ->byID($this->owner->ID);
            $live = Versioned::get_by_stage($this->owner->ClassName, 'Live')
                ->byID($this->owner->ID);
            if (!$staged && !$live) {
                $remove = true;
            }
        }
        if ($remove) {
            foreach ($this->owner->Variations() as $variation) {
                $variation->delete();
                $variation->destroy();
            }
        }
    }
public function onAfterDelete()
    {
        $remove = false;
        // if a record is staged or live, leave it's variations alone.
        if (!property_exists($this, 'owner')) {
            $remove = true;
        } else {
            $staged = Versioned::get_by_stage($this->owner->ClassName, 'Stage')
                ->byID($this->owner->ID);
            $live = Versioned::get_by_stage($this->owner->ClassName, 'Live')
                ->byID($this->owner->ID);
            if (!$staged && !$live) {
                $remove = true;
            }
        }
        if ($remove) {
            foreach ($this->owner->Variations() as $variation) {
                $variation->delete();
                $variation->destroy();
            }
        }
    }
Make sure variations are deleted with product.