Support for float <-> int conversions. (#7275)

Implement support for floating-point <-> integer type conversions as
described in #820 and #845, extended to support `unsafe as` conversions
for the conversions that can't be expressed as either implicit
conversions or `as` conversions.

One tricky part here is conversions from floating-point literals to
integer types. Such literals may have both a very large mantissa and a
corresponding somewhat large negative exponent, and still produce a
result that is in the range of values that a small integer type can
represent. In order to support that while avoiding building very large
2^N or 10^N constants in general, we first compute a conservative
approximation of the number of bits necessary to represent the integer
result, with an early exit if the number is either definitely too large
or definitely zero. The remaining cases have a reasonable bound on the
size of integer necessary to compute the base^exponent multiplicand.

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith
2026-06-03 23:41:20 +00:00
committed by GitHub
parent f2d0c4d0ae
commit 7fe3e35aec
39 changed files with 2118 additions and 351 deletions
+26 -26
View File
@@ -468,42 +468,42 @@ fn F(c: Core.Optional(C*)) -> Core.Optional(C*) {
// CHECK:STDOUT: !105 = !{!14}
// CHECK:STDOUT: !106 = !DILocation(line: 31, column: 12, scope: !103)
// CHECK:STDOUT: !107 = !DILocation(line: 31, column: 5, scope: !103)
// CHECK:STDOUT: !108 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.8c14fbb190d2c4a2:ImplicitAs.ad22d1bbc0605210.Core.4462757cf1994b1f", scope: null, file: !109, line: 40, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !110)
// CHECK:STDOUT: !108 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.8c14fbb190d2c4a2:ImplicitAs.ad22d1bbc0605210.Core.4462757cf1994b1f", scope: null, file: !109, line: 42, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !110)
// CHECK:STDOUT: !109 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
// CHECK:STDOUT: !110 = !{!111}
// CHECK:STDOUT: !111 = !DILocalVariable(arg: 1, scope: !108, type: !7)
// CHECK:STDOUT: !112 = !DILocation(line: 40, column: 45, scope: !108)
// CHECK:STDOUT: !113 = !DILocation(line: 40, column: 38, scope: !108)
// CHECK:STDOUT: !112 = !DILocation(line: 42, column: 45, scope: !108)
// CHECK:STDOUT: !113 = !DILocation(line: 42, column: 38, scope: !108)
// CHECK:STDOUT: !114 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.0a82a05610538fbd:ImplicitAs.dfe7f37cd2946174.Core.5301bd2e5265063e", scope: null, file: !86, line: 105, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !115)
// CHECK:STDOUT: !115 = !{!116}
// CHECK:STDOUT: !116 = !DILocalVariable(arg: 1, scope: !114, type: !7)
// CHECK:STDOUT: !117 = !DILocation(line: 106, column: 12, scope: !114)
// CHECK:STDOUT: !118 = !DILocation(line: 106, column: 5, scope: !114)
// CHECK:STDOUT: !119 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.8c14fbb190d2c4a2:ImplicitAs.ad22d1bbc0605210.Core.bae947e6cb644eb3", scope: null, file: !109, line: 40, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !120)
// CHECK:STDOUT: !119 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.8c14fbb190d2c4a2:ImplicitAs.ad22d1bbc0605210.Core.bae947e6cb644eb3", scope: null, file: !109, line: 42, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !120)
// CHECK:STDOUT: !120 = !{!121}
// CHECK:STDOUT: !121 = !DILocalVariable(arg: 1, scope: !119, type: !7)
// CHECK:STDOUT: !122 = !DILocation(line: 40, column: 45, scope: !119)
// CHECK:STDOUT: !123 = !DILocation(line: 40, column: 38, scope: !119)
// CHECK:STDOUT: !124 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.4462757cf1994b1f", scope: null, file: !109, line: 44, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !125)
// CHECK:STDOUT: !122 = !DILocation(line: 42, column: 45, scope: !119)
// CHECK:STDOUT: !123 = !DILocation(line: 42, column: 38, scope: !119)
// CHECK:STDOUT: !124 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.4462757cf1994b1f", scope: null, file: !109, line: 46, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !125)
// CHECK:STDOUT: !125 = !{!126}
// CHECK:STDOUT: !126 = !DILocalVariable(arg: 1, scope: !124, type: !7)
// CHECK:STDOUT: !127 = !DILocation(line: 44, column: 45, scope: !124)
// CHECK:STDOUT: !128 = !DILocation(line: 44, column: 38, scope: !124)
// CHECK:STDOUT: !129 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.d312635c3eabfce6", scope: null, file: !109, line: 44, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !130)
// CHECK:STDOUT: !127 = !DILocation(line: 46, column: 45, scope: !124)
// CHECK:STDOUT: !128 = !DILocation(line: 46, column: 38, scope: !124)
// CHECK:STDOUT: !129 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.d312635c3eabfce6", scope: null, file: !109, line: 46, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !130)
// CHECK:STDOUT: !130 = !{!131}
// CHECK:STDOUT: !131 = !DILocalVariable(arg: 1, scope: !129, type: !7)
// CHECK:STDOUT: !132 = !DILocation(line: 44, column: 45, scope: !129)
// CHECK:STDOUT: !133 = !DILocation(line: 44, column: 38, scope: !129)
// CHECK:STDOUT: !134 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.bae947e6cb644eb3", scope: null, file: !109, line: 44, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !135)
// CHECK:STDOUT: !132 = !DILocation(line: 46, column: 45, scope: !129)
// CHECK:STDOUT: !133 = !DILocation(line: 46, column: 38, scope: !129)
// CHECK:STDOUT: !134 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.bae947e6cb644eb3", scope: null, file: !109, line: 46, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !135)
// CHECK:STDOUT: !135 = !{!136}
// CHECK:STDOUT: !136 = !DILocalVariable(arg: 1, scope: !134, type: !7)
// CHECK:STDOUT: !137 = !DILocation(line: 44, column: 45, scope: !134)
// CHECK:STDOUT: !138 = !DILocation(line: 44, column: 38, scope: !134)
// CHECK:STDOUT: !139 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.4e32707a29fe420f", scope: null, file: !109, line: 44, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !140)
// CHECK:STDOUT: !137 = !DILocation(line: 46, column: 45, scope: !134)
// CHECK:STDOUT: !138 = !DILocation(line: 46, column: 38, scope: !134)
// CHECK:STDOUT: !139 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.874935b394d32264:ImplicitAs.eb057aa32837c84e.Core.4e32707a29fe420f", scope: null, file: !109, line: 46, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !140)
// CHECK:STDOUT: !140 = !{!141}
// CHECK:STDOUT: !141 = !DILocalVariable(arg: 1, scope: !139, type: !7)
// CHECK:STDOUT: !142 = !DILocation(line: 44, column: 45, scope: !139)
// CHECK:STDOUT: !143 = !DILocation(line: 44, column: 38, scope: !139)
// CHECK:STDOUT: !142 = !DILocation(line: 46, column: 45, scope: !139)
// CHECK:STDOUT: !143 = !DILocation(line: 46, column: 38, scope: !139)
// CHECK:STDOUT: !144 = distinct !DISubprogram(name: "Has", linkageName: "_CHas.e8f8f92d3d08d149:OptionalStorage.Core.5e5386123d4b6287", scope: null, file: !86, line: 172, type: !12, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !145)
// CHECK:STDOUT: !145 = !{!146}
// CHECK:STDOUT: !146 = !DILocalVariable(arg: 1, scope: !144, type: !14)
@@ -533,11 +533,11 @@ fn F(c: Core.Optional(C*)) -> Core.Optional(C*) {
// CHECK:STDOUT: !170 = !DILocalVariable(arg: 1, scope: !168, type: !7)
// CHECK:STDOUT: !171 = !DILocation(line: 34, column: 12, scope: !168)
// CHECK:STDOUT: !172 = !DILocation(line: 34, column: 5, scope: !168)
// CHECK:STDOUT: !173 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.8c14fbb190d2c4a2:ImplicitAs.ad22d1bbc0605210.Core.8c6f821d602abaa4", scope: null, file: !109, line: 40, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !174)
// CHECK:STDOUT: !173 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.8c14fbb190d2c4a2:ImplicitAs.ad22d1bbc0605210.Core.8c6f821d602abaa4", scope: null, file: !109, line: 42, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !174)
// CHECK:STDOUT: !174 = !{!175}
// CHECK:STDOUT: !175 = !DILocalVariable(arg: 1, scope: !173, type: !7)
// CHECK:STDOUT: !176 = !DILocation(line: 40, column: 45, scope: !173)
// CHECK:STDOUT: !177 = !DILocation(line: 40, column: 38, scope: !173)
// CHECK:STDOUT: !176 = !DILocation(line: 42, column: 45, scope: !173)
// CHECK:STDOUT: !177 = !DILocation(line: 42, column: 38, scope: !173)
// CHECK:STDOUT: !178 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.664c9635efe58704", scope: null, file: !86, line: 33, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !179)
// CHECK:STDOUT: !179 = !{!180}
// CHECK:STDOUT: !180 = !DILocalVariable(arg: 1, scope: !178, type: !7)
@@ -549,14 +549,14 @@ fn F(c: Core.Optional(C*)) -> Core.Optional(C*) {
// CHECK:STDOUT: !186 = !DILocation(line: 137, column: 5, scope: !183)
// CHECK:STDOUT: !187 = !DILocation(line: 138, column: 5, scope: !183)
// CHECK:STDOUT: !188 = !DILocation(line: 139, column: 5, scope: !183)
// CHECK:STDOUT: !189 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.667d1d3a0ad99849:ImplicitAs.8b551f392b5250ee.Core.4a088ada889550fc", scope: null, file: !190, line: 62, type: !191, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !193)
// CHECK:STDOUT: !189 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.667d1d3a0ad99849:ImplicitAs.8b551f392b5250ee.Core.4a088ada889550fc", scope: null, file: !190, line: 63, type: !191, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !193)
// CHECK:STDOUT: !190 = !DIFile(filename: "{{.*}}/prelude/types/int.carbon", directory: "")
// CHECK:STDOUT: !191 = !DISubroutineType(types: !192)
// CHECK:STDOUT: !192 = !{!7, !7}
// CHECK:STDOUT: !193 = !{!194}
// CHECK:STDOUT: !194 = !DILocalVariable(arg: 1, scope: !189, type: !7)
// CHECK:STDOUT: !195 = !DILocation(line: 64, column: 17, scope: !189)
// CHECK:STDOUT: !196 = !DILocation(line: 64, column: 5, scope: !189)
// CHECK:STDOUT: !195 = !DILocation(line: 65, column: 17, scope: !189)
// CHECK:STDOUT: !196 = !DILocation(line: 65, column: 5, scope: !189)
// CHECK:STDOUT: !197 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.c70f21296ce3b72c:OptionalStorage.Core.66877768e8b2b97c", scope: null, file: !86, line: 131, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !198)
// CHECK:STDOUT: !198 = !{!199}
// CHECK:STDOUT: !199 = !DILocalVariable(arg: 1, scope: !197, type: !7)
@@ -564,10 +564,10 @@ fn F(c: Core.Optional(C*)) -> Core.Optional(C*) {
// CHECK:STDOUT: !201 = !DILocation(line: 137, column: 28, scope: !197)
// CHECK:STDOUT: !202 = !DILocation(line: 138, column: 5, scope: !197)
// CHECK:STDOUT: !203 = !DILocation(line: 139, column: 5, scope: !197)
// CHECK:STDOUT: !204 = distinct !DISubprogram(name: "AsInt", linkageName: "_CAsInt.Int.9452f4c51951679b.Core:AnyInt.Core.be1e879c1ad406d8", scope: null, file: !190, line: 57, type: !191, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !205)
// CHECK:STDOUT: !204 = distinct !DISubprogram(name: "AsInt", linkageName: "_CAsInt.Int.9452f4c51951679b.Core:AnyInt.Core.be1e879c1ad406d8", scope: null, file: !190, line: 58, type: !191, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !205)
// CHECK:STDOUT: !205 = !{!206}
// CHECK:STDOUT: !206 = !DILocalVariable(arg: 1, scope: !204, type: !7)
// CHECK:STDOUT: !207 = !DILocation(line: 57, column: 36, scope: !204)
// CHECK:STDOUT: !207 = !DILocation(line: 58, column: 36, scope: !204)
// CHECK:STDOUT: !208 = distinct !DISubprogram(name: "Op", linkageName: "_COp.99377c0e95f681c6:Copy.Core.4bee6dcdea6ba756", scope: null, file: !209, line: 19, type: !97, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !210)
// CHECK:STDOUT: !209 = !DIFile(filename: "{{.*}}/prelude/copy.carbon", directory: "")
// CHECK:STDOUT: !210 = !{!211}