Compile time assertion / checking?


(Jens Persson) #1

Sorry if this has been asked before (searched but couldn't find anything).
I'll explain what I mean by an example of a situation where I think it
would be reasonable to expect a compile time error rather than the current
runtime error:

import simd
let a: float4 = [1, 2, 3]
print(a)

The SIMD float4 type conforms to ArrayLiteralConvertible, and the required
initializer has a check that makes sure the array literal has 4 elements.
The check can only be performed at runtime even though the number of
elements of that array literal is (presumably) statically knowable, as is
the number it is checked against (i.e. it probably ends up being an integer
literal 4 somewhere (although I haven't actually checked the code)).

I assume that there are good reasons for why this is currently a runtime
check, but I'd like to know what these reasons are, i.e. why isn't there
something like C++'s static_assert?

Any pointers to previous discussions or information about how Swift relates
to this and similar topics (static computation / constexpr, macro system)
would be highly appreciated.

/Jens


(Joe Groff) #2

We haven't designed any facilities for any of this yet, or really had serious discussions about them that I know of. They're definitely interesting directions for the future. There is some infrastructure for limited compile-time evaluation and diagnostics based on SIL; for instance, we produce diagnostics when literal integer expressions overflow their target type, as in `let x: Int8 = 128`, by doing constant-folding of `@_transparent` functions. There's a more generalized compile-time reporting mechanism we prototyped, but I don't think we currently take advantage of it; grep around for `staticReport`. `staticReport` in @_transparent function together could approximate static_assert in cases the compiler knows how to constant-fold.

-Joe

···

On Dec 21, 2015, at 8:16 AM, Jens Persson via swift-evolution <swift-evolution@swift.org> wrote:

Sorry if this has been asked before (searched but couldn't find anything).
I'll explain what I mean by an example of a situation where I think it would be reasonable to expect a compile time error rather than the current runtime error:

import simd
let a: float4 = [1, 2, 3]
print(a)

The SIMD float4 type conforms to ArrayLiteralConvertible, and the required initializer has a check that makes sure the array literal has 4 elements.
The check can only be performed at runtime even though the number of elements of that array literal is (presumably) statically knowable, as is the number it is checked against (i.e. it probably ends up being an integer literal 4 somewhere (although I haven't actually checked the code)).

I assume that there are good reasons for why this is currently a runtime check, but I'd like to know what these reasons are, i.e. why isn't there something like C++'s static_assert?

Any pointers to previous discussions or information about how Swift relates to this and similar topics (static computation / constexpr, macro system) would be highly appreciated.


(Jens Persson) #3

Thanks!
(As a side note related to overflow, I filed
https://bugs.swift.org/browse/SR-297 demonstrating that a
T : UnsignedIntegerType can be set to eg literal -1 without trapping the
overflow.)

···

On Mon, Dec 21, 2015 at 7:22 PM, Joe Groff <jgroff@apple.com> wrote:

> On Dec 21, 2015, at 8:16 AM, Jens Persson via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Sorry if this has been asked before (searched but couldn't find
anything).
> I'll explain what I mean by an example of a situation where I think it
would be reasonable to expect a compile time error rather than the current
runtime error:
>
> import simd
> let a: float4 = [1, 2, 3]
> print(a)
>
> The SIMD float4 type conforms to ArrayLiteralConvertible, and the
required initializer has a check that makes sure the array literal has 4
elements.
> The check can only be performed at runtime even though the number of
elements of that array literal is (presumably) statically knowable, as is
the number it is checked against (i.e. it probably ends up being an integer
literal 4 somewhere (although I haven't actually checked the code)).
>
> I assume that there are good reasons for why this is currently a runtime
check, but I'd like to know what these reasons are, i.e. why isn't there
something like C++'s static_assert?
>
> Any pointers to previous discussions or information about how Swift
relates to this and similar topics (static computation / constexpr, macro
system) would be highly appreciated.

We haven't designed any facilities for any of this yet, or really had
serious discussions about them that I know of. They're definitely
interesting directions for the future. There is some infrastructure for
limited compile-time evaluation and diagnostics based on SIL; for instance,
we produce diagnostics when literal integer expressions overflow their
target type, as in `let x: Int8 = 128`, by doing constant-folding of
`@_transparent` functions. There's a more generalized compile-time
reporting mechanism we prototyped, but I don't think we currently take
advantage of it; grep around for `staticReport`. `staticReport` in
@_transparent function together could approximate static_assert in cases
the compiler knows how to constant-fold.

-Joe

--
bitCycle AB | Smedjegatan 12 | 742 32 Östhammar | Sweden
http://www.bitcycle.com/
Phone: +46-73-753 24 62
E-mail: jens@bitcycle.com


(marc hoffman) #4

Joe,

quick side question: is @_transparent documented somewhere? I’ve seen it in the standard library source code, but i cannot see out covered in any of the docs…

thanx!
marc

···

On Dec 21, 2015, at 2:22 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 21, 2015, at 8:16 AM, Jens Persson via swift-evolution <swift-evolution@swift.org> wrote:

Sorry if this has been asked before (searched but couldn't find anything).
I'll explain what I mean by an example of a situation where I think it would be reasonable to expect a compile time error rather than the current runtime error:

import simd
let a: float4 = [1, 2, 3]
print(a)

The SIMD float4 type conforms to ArrayLiteralConvertible, and the required initializer has a check that makes sure the array literal has 4 elements.
The check can only be performed at runtime even though the number of elements of that array literal is (presumably) statically knowable, as is the number it is checked against (i.e. it probably ends up being an integer literal 4 somewhere (although I haven't actually checked the code)).

I assume that there are good reasons for why this is currently a runtime check, but I'd like to know what these reasons are, i.e. why isn't there something like C++'s static_assert?

Any pointers to previous discussions or information about how Swift relates to this and similar topics (static computation / constexpr, macro system) would be highly appreciated.

We haven't designed any facilities for any of this yet, or really had serious discussions about them that I know of. They're definitely interesting directions for the future. There is some infrastructure for limited compile-time evaluation and diagnostics based on SIL; for instance, we produce diagnostics when literal integer expressions overflow their target type, as in `let x: Int8 = 128`, by doing constant-folding of `@_transparent` functions. There's a more generalized compile-time reporting mechanism we prototyped, but I don't think we currently take advantage of it; grep around for `staticReport`. `staticReport` in @_transparent function together could approximate static_assert in cases the compiler knows how to constant-fold.

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #5

Thanks! Yeah, we only ever handled overflow in concrete integer types. Compile-time diagnostics for protocol invariants would be another interesting thing to add. It might be possible by refactoring how IntegerLiteralConvertible interfaces with _BuiltinIntegerLiteralConvertible, making the diagnostics occur while narrowing Builtin.Int2048 to the literal type.

-Joe

···

On Dec 21, 2015, at 11:18 PM, Jens Persson <jens@bitcycle.com> wrote:

Thanks!
(As a side note related to overflow, I filed https://bugs.swift.org/browse/SR-297 demonstrating that a
T : UnsignedIntegerType can be set to eg literal -1 without trapping the overflow.)


(Joe Groff) #6

It's not publicly documented, because it's intended to be an implementation detail. It only really works within the standard library, and is likely to be replaced by our proper resilience model for cross-module inlining. Check out docs/TransparentAttr.rst for the internal documentation.

-Joe

···

On Dec 22, 2015, at 7:26 AM, marc hoffman via swift-evolution <swift-evolution@swift.org> wrote:

Joe,

quick side question: is @_transparent documented somewhere? I’ve seen it in the standard library source code, but i cannot see out covered in any of the docs…


(marc hoffman) #7

Thanx!

i understand it’s internal, but i’m asking because i work on http://www.elementscompiler.com/silver, and eventually we’d love to be able to compile parts of the standard library ourselves :wink:

—marc

···

On Dec 22, 2015, at 11:29 AM, Joe Groff <jgroff@apple.com> wrote:

On Dec 22, 2015, at 7:26 AM, marc hoffman via swift-evolution <swift-evolution@swift.org> wrote:

Joe,

quick side question: is @_transparent documented somewhere? I’ve seen it in the standard library source code, but i cannot see out covered in any of the docs…

It's not publicly documented, because it's intended to be an implementation detail. It only really works within the standard library, and is likely to be replaced by our proper resilience model for cross-module inlining. Check out docs/TransparentAttr.rst for the internal documentation.

-Joe


(Joe Groff) #8

Thanx!

i understand it’s internal, but i’m asking because i work on http://www.elementscompiler.com/silver, and eventually we’d love to be able to compile parts of the standard library ourselves :wink:

Given the deep dependence in our standard library on LLVM primitives and semantics, as well as the rather messy interactions between our compiler, stdlib, and runtime in general, I'm not sure that's a practical goal. Maybe if there were a better-factored 'core' that defined the basic interfaces in terms of the substrate, giving you Int/String/etc. in terms of LLVM/CLR/JavaScript/WebAssembly/whatever primitives, that was isolated from the higher-level parts of the stdlib, but that's a sizable effort in itself. I know you all already define your own versions of stdlib interfaces in terms of common .NET/JVM abstractions, and change semantics in many places as a result.

-Joe

···

On Dec 22, 2015, at 10:03 AM, marc hoffman via swift-evolution <swift-evolution@swift.org> wrote:

—marc

On Dec 22, 2015, at 11:29 AM, Joe Groff <jgroff@apple.com> wrote:

On Dec 22, 2015, at 7:26 AM, marc hoffman via swift-evolution <swift-evolution@swift.org> wrote:

Joe,

quick side question: is @_transparent documented somewhere? I’ve seen it in the standard library source code, but i cannot see out covered in any of the docs…

It's not publicly documented, because it's intended to be an implementation detail. It only really works within the standard library, and is likely to be replaced by our proper resilience model for cross-module inlining. Check out docs/TransparentAttr.rst for the internal documentation.

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(marc hoffman) #9

Joe,

Given the deep dependence in our standard library on LLVM primitives and semantics, as well as the rather messy interactions between our compiler, stdlib, and runtime in general, I'm not sure that's a practical goal.

Probably not no. I just figured, the more syntax — even internal/hidden/unsupported ones - we can support, the easier it will be to move stuff over or keep it in sync. Reviewing the official standard lib and bringing our up to speed with it (on the outside) is my next big goal, and even just being able to copy a class skeleton over can help ;)_

Maybe if there were a better-factored 'core' that defined the basic interfaces in terms of the substrate, giving you Int/String/etc. in terms of LLVM/CLR/JavaScript/WebAssembly/whatever primitives, that was isolated from the higher-level parts of the stdlib, but that's a sizable effort in itself. I know you all already define your own versions of stdlib interfaces in terms of common .NET/JVM abstractions, and change semantics in many places as a result.

Yeah.

—marc