mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 06:11:05 +01:00
Don't convert to f64 until we know that's the type that we actually want. Also reimplement the conversion from RealId to FloatId to perform an exact conversion with a real check for overflow, rather than performing an approximate conversion via the host `double` type. Unfortunately, LLVM doesn't expose its integer mantissa and exponent to APFloat conversion, so we convert the RealId back to a string for now. The LLVM conversion also detects overflow only if the literal would round to having an out-of-range exponent, not if the literal is outside the range of values of the type as the Carbon design expects. It's not clear to me which rule we actually want here, so for simplicitly I'm using the LLVM rule for now. In preparation for adding other floating-point types beyond f64.
164 lines
15 KiB
Plaintext
164 lines
15 KiB
Plaintext
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon
|
|
// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
|
|
// EXTRA-ARGS: --dump-sem-ir-ranges=if-present
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/struct/member_access.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/member_access.carbon
|
|
|
|
var x: {.a: f64, .b: i32} = {.a = 0.0, .b = 1};
|
|
var y: i32 = x.b;
|
|
var z: i32 = y;
|
|
|
|
// CHECK:STDOUT: --- member_access.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete]
|
|
// CHECK:STDOUT: %Float.type: type = generic_class_type @Float [concrete]
|
|
// CHECK:STDOUT: %Float.generic: %Float.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %f64.d77: type = class_type @Float, @Float(%int_64) [concrete]
|
|
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
|
|
// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete]
|
|
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
|
|
// CHECK:STDOUT: %struct_type.a.b.d2f: type = struct_type {.a: %f64.d77, .b: %i32} [concrete]
|
|
// CHECK:STDOUT: %pattern_type.a7a: type = pattern_type %struct_type.a.b.d2f [concrete]
|
|
// CHECK:STDOUT: %float.1f7: Core.FloatLiteral = float_literal_value 0e-1 [concrete]
|
|
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
|
|
// CHECK:STDOUT: %struct_type.a.b.0cc: type = struct_type {.a: Core.FloatLiteral, .b: Core.IntLiteral} [concrete]
|
|
// CHECK:STDOUT: %.bc0: ref %f64.d77 = struct_access file.%x.var, element0 [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.type.6ec: type = facet_type <@ImplicitAs, @ImplicitAs(%f64.d77)> [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.Convert.type.726: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%f64.d77) [concrete]
|
|
// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.644: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%To) [symbolic]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.b45: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.644 = struct_value () [symbolic]
|
|
// CHECK:STDOUT: %ImplicitAs.impl_witness.857: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.f22, @Core.FloatLiteral.as.ImplicitAs.impl(%int_64) [concrete]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.baf: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%int_64) [concrete]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.a03: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.baf = struct_value () [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.facet.8d0: %ImplicitAs.type.6ec = facet_value Core.FloatLiteral, (%ImplicitAs.impl_witness.857) [concrete]
|
|
// CHECK:STDOUT: %.678: type = fn_type_with_self_type %ImplicitAs.Convert.type.726, %ImplicitAs.facet.8d0 [concrete]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %float.1f7, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.a03 [concrete]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.FloatLiteral.as.ImplicitAs.impl.Convert.a03, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(%int_64) [concrete]
|
|
// CHECK:STDOUT: %bound_method.728: <bound method> = bound_method %float.1f7, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
|
|
// CHECK:STDOUT: %float.0a8: %f64.d77 = float_value 0 [concrete]
|
|
// CHECK:STDOUT: %.a00: ref %i32 = struct_access file.%x.var, element1 [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.f06: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9 = struct_value () [symbolic]
|
|
// CHECK:STDOUT: %ImplicitAs.impl_witness.c75: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.956: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035 = struct_value () [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.facet.921: %ImplicitAs.type.205 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.c75) [concrete]
|
|
// CHECK:STDOUT: %.9c3: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet.921 [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete]
|
|
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.956, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
|
|
// CHECK:STDOUT: %bound_method.9a1: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
|
|
// CHECK:STDOUT: %int_1.5d2: %i32 = int_value 1 [concrete]
|
|
// CHECK:STDOUT: %struct: %struct_type.a.b.d2f = struct_value (%float.0a8, %int_1.5d2) [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: imports {
|
|
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
|
// CHECK:STDOUT: .Float = %Core.Float
|
|
// CHECK:STDOUT: .Int = %Core.Int
|
|
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
|
|
// CHECK:STDOUT: import Core//prelude
|
|
// CHECK:STDOUT: import Core//prelude/...
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.Float: %Float.type = import_ref Core//prelude/parts/float, Float, loaded [concrete = constants.%Float.generic]
|
|
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic]
|
|
// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/parts/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
|
|
// CHECK:STDOUT: %Core.import_ref.c0c: @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type (%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.644) = import_ref Core//prelude/parts/float, loc15_41, loaded [symbolic = @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert (constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.b45)]
|
|
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.f22 = impl_witness_table (%Core.import_ref.c0c), @Core.FloatLiteral.as.ImplicitAs.impl [concrete]
|
|
// CHECK:STDOUT: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)]
|
|
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: file {
|
|
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
|
// CHECK:STDOUT: .Core = imports.%Core
|
|
// CHECK:STDOUT: .x = %x
|
|
// CHECK:STDOUT: .y = %y
|
|
// CHECK:STDOUT: .z = %z
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.import = import Core
|
|
// CHECK:STDOUT: name_binding_decl {
|
|
// CHECK:STDOUT: %x.patt: %pattern_type.a7a = binding_pattern x [concrete]
|
|
// CHECK:STDOUT: %x.var_patt: %pattern_type.a7a = var_pattern %x.patt [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %x.var: ref %struct_type.a.b.d2f = var %x.var_patt [concrete]
|
|
// CHECK:STDOUT: %.loc15: type = splice_block %struct_type.a.b [concrete = constants.%struct_type.a.b.d2f] {
|
|
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
|
|
// CHECK:STDOUT: %f64: type = class_type @Float, @Float(constants.%int_64) [concrete = constants.%f64.d77]
|
|
// CHECK:STDOUT: %int_32.loc15: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
|
|
// CHECK:STDOUT: %i32.loc15: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
|
|
// CHECK:STDOUT: %struct_type.a.b: type = struct_type {.a: %f64.d77, .b: %i32} [concrete = constants.%struct_type.a.b.d2f]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %x: ref %struct_type.a.b.d2f = bind_name x, %x.var [concrete = %x.var]
|
|
// CHECK:STDOUT: name_binding_decl {
|
|
// CHECK:STDOUT: %y.patt: %pattern_type.7ce = binding_pattern y [concrete]
|
|
// CHECK:STDOUT: %y.var_patt: %pattern_type.7ce = var_pattern %y.patt [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %y.var: ref %i32 = var %y.var_patt [concrete]
|
|
// CHECK:STDOUT: %.loc16: type = splice_block %i32.loc16 [concrete = constants.%i32] {
|
|
// CHECK:STDOUT: %int_32.loc16: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
|
|
// CHECK:STDOUT: %i32.loc16: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %y: ref %i32 = bind_name y, %y.var [concrete = %y.var]
|
|
// CHECK:STDOUT: name_binding_decl {
|
|
// CHECK:STDOUT: %z.patt: %pattern_type.7ce = binding_pattern z [concrete]
|
|
// CHECK:STDOUT: %z.var_patt: %pattern_type.7ce = var_pattern %z.patt [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %z.var: ref %i32 = var %z.var_patt [concrete]
|
|
// CHECK:STDOUT: %.loc17: type = splice_block %i32.loc17 [concrete = constants.%i32] {
|
|
// CHECK:STDOUT: %int_32.loc17: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
|
|
// CHECK:STDOUT: %i32.loc17: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %z: ref %i32 = bind_name z, %z.var [concrete = %z.var]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: fn @__global_init() {
|
|
// CHECK:STDOUT: !entry:
|
|
// CHECK:STDOUT: %float: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f7]
|
|
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
|
|
// CHECK:STDOUT: %.loc15_46.1: %struct_type.a.b.0cc = struct_literal (%float, %int_1)
|
|
// CHECK:STDOUT: %impl.elem0.loc15_46.1: %.678 = impl_witness_access constants.%ImplicitAs.impl_witness.857, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.a03]
|
|
// CHECK:STDOUT: %bound_method.loc15_46.1: <bound method> = bound_method %float, %impl.elem0.loc15_46.1 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound]
|
|
// CHECK:STDOUT: %specific_fn.loc15_46.1: <specific function> = specific_function %impl.elem0.loc15_46.1, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn]
|
|
// CHECK:STDOUT: %bound_method.loc15_46.2: <bound method> = bound_method %float, %specific_fn.loc15_46.1 [concrete = constants.%bound_method.728]
|
|
// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call: init %f64.d77 = call %bound_method.loc15_46.2(%float) [concrete = constants.%float.0a8]
|
|
// CHECK:STDOUT: %.loc15_46.2: init %f64.d77 = converted %float, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%float.0a8]
|
|
// CHECK:STDOUT: %.loc15_46.3: ref %f64.d77 = struct_access file.%x.var, element0 [concrete = constants.%.bc0]
|
|
// CHECK:STDOUT: %.loc15_46.4: init %f64.d77 = initialize_from %.loc15_46.2 to %.loc15_46.3 [concrete = constants.%float.0a8]
|
|
// CHECK:STDOUT: %impl.elem0.loc15_46.2: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956]
|
|
// CHECK:STDOUT: %bound_method.loc15_46.3: <bound method> = bound_method %int_1, %impl.elem0.loc15_46.2 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
|
|
// CHECK:STDOUT: %specific_fn.loc15_46.2: <specific function> = specific_function %impl.elem0.loc15_46.2, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
|
|
// CHECK:STDOUT: %bound_method.loc15_46.4: <bound method> = bound_method %int_1, %specific_fn.loc15_46.2 [concrete = constants.%bound_method.9a1]
|
|
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc15_46.4(%int_1) [concrete = constants.%int_1.5d2]
|
|
// CHECK:STDOUT: %.loc15_46.5: init %i32 = converted %int_1, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.5d2]
|
|
// CHECK:STDOUT: %.loc15_46.6: ref %i32 = struct_access file.%x.var, element1 [concrete = constants.%.a00]
|
|
// CHECK:STDOUT: %.loc15_46.7: init %i32 = initialize_from %.loc15_46.5 to %.loc15_46.6 [concrete = constants.%int_1.5d2]
|
|
// CHECK:STDOUT: %.loc15_46.8: init %struct_type.a.b.d2f = struct_init (%.loc15_46.4, %.loc15_46.7) to file.%x.var [concrete = constants.%struct]
|
|
// CHECK:STDOUT: %.loc15_1: init %struct_type.a.b.d2f = converted %.loc15_46.1, %.loc15_46.8 [concrete = constants.%struct]
|
|
// CHECK:STDOUT: assign file.%x.var, %.loc15_1
|
|
// CHECK:STDOUT: %x.ref: ref %struct_type.a.b.d2f = name_ref x, file.%x [concrete = file.%x.var]
|
|
// CHECK:STDOUT: %.loc16_15.1: ref %i32 = struct_access %x.ref, element1 [concrete = constants.%.a00]
|
|
// CHECK:STDOUT: %.loc16_15.2: %i32 = bind_value %.loc16_15.1
|
|
// CHECK:STDOUT: assign file.%y.var, %.loc16_15.2
|
|
// CHECK:STDOUT: %y.ref: ref %i32 = name_ref y, file.%y [concrete = file.%y.var]
|
|
// CHECK:STDOUT: %.loc17: %i32 = bind_value %y.ref
|
|
// CHECK:STDOUT: assign file.%z.var, %.loc17
|
|
// CHECK:STDOUT: return
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|