I donβt have an answer to this, but this is definitely not an `of course`

.

If you just simplify the function to e.g.

```
@inline calcM(x) = x^2
```

then compiler decides to evaluate it during compile time:

```
julia> @code_warntype MyType{3}()
Variables
#self#::Type{MyType{3, M} where M}
M::Int64
Body::MyType{3, 9}
1 β Core.NewvarNode(:(M))
β %2 = ($(Expr(:static_parameter, 1)) β₯ 0)::Core.Const(true)
β %2
βββ goto #3
2 β Core.Const(:(Base.AssertionError("N β₯ 0")))
βββ Core.Const(:(Base.throw(%5)))
3 β (M = Main.calcM($(Expr(:static_parameter, 1))))
β %8 = Core.apply_type(Main.MyType, $(Expr(:static_parameter, 1)), M::Core.Const(9))::Core.Const(MyType{3, 9})
β %9 = (%8)()::Core.Const(MyType{3, 9}())
βββ return %9
```

Along those lines: You can nudge the compiler to make your example type stable by adding an additional type check.

```
julia> function MyType{N}() where N
@assert N β₯ 0
T = typeof(N)
M = calcM(N)::T
MyType{N,M}()
end
julia> @code_warntype MyType{3}()
Variables
#self#::Type{MyType{3, M} where M}
M::Int64
T::Type{Int64}
Body::MyType{3, 9}
1 β Core.NewvarNode(:(M))
β Core.NewvarNode(:(T))
β %3 = ($(Expr(:static_parameter, 1)) β₯ 0)::Core.Const(true)
β %3
βββ goto #3
2 β Core.Const(:(Base.AssertionError("N β₯ 0")))
βββ Core.Const(:(Base.throw(%6)))
3 β (T = Main.typeof($(Expr(:static_parameter, 1))))
β %9 = Main.calcM($(Expr(:static_parameter, 1)))::Core.Const(9)
β (M = Core.typeassert(%9, T::Core.Const(Int64)))
β %11 = Core.apply_type(Main.MyType, $(Expr(:static_parameter, 1)), M::Core.Const(9))::Core.Const(MyType{3, 9})
β %12 = (%11)()::Core.Const(MyType{3, 9}())
βββ return %12
```