I'm thinking of making a value class that has some guard on how it can be instantiated. For the sake of example, say I want a non-negative integer:
class NonNegInt private (val value: Int) extends AnyVal
object NonNegInt {
  def apply(value: Int): Try[NonNegInt] = Try {
    if (value >= 0) new NonNegInt(value) else throw new IllegalArgumentException("non-negative integers only!")
  }
}
My only worry is that the private constructor may make it impossible for the scala compiler to treat the NonNegInt as a primitive int. Is this true?
                        
If "treat as a primitive" here means "avoid allocation", then this indeed will not work, but not because of a private constructor.
As mentioned in Value Classes Guide
Another instance of this rule is when a value class is used as a type argument. For example, the actual Meter instance must be created for even a call to identity.
Basically, because identity[T] is parametrized, invoking it on a value type requires an allocation of an instance. Try[T] is the same situation:
Try { ... }"block" is an invocation of a parametrized functionTry.apply[T]with T beingNonNegInt. This call will require an allocation ofNonNegIntinstance.