Skip to content

Commit b99bc00

Browse files
authored
Deduce arguments against the canonical facet value (#6158)
When deducing an argument against a type that is `<facet value> as type` we don't care about the `as type` part of that expression. We want to find an argument that can convert to the `FacetType` of the facet value for the generic binding that is the `<facet value>`. This was done after-the-fact in the Deduce switch, but we move this canonicalization step to be more explicit and done up front at the start of the Deduce loop. This: - Avoids a trip through the Deduce loop for a `FacetAccessType` parameter, just to deduce through it in the switch, which avoids convert and creation of extraneous constant values. - Uses the `GetCanonicalFacetOrTypeValue()` function so that when we add `SymbolicBindingType` handling to that function it will apply to Deduce as well correctly, instead of needing to handle both in the switch.
1 parent e3b4482 commit b99bc00

7 files changed

+33
-60
lines changed

toolchain/check/deduce.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "toolchain/check/convert.h"
1111
#include "toolchain/check/generic.h"
1212
#include "toolchain/check/subst.h"
13+
#include "toolchain/check/type.h"
1314
#include "toolchain/diagnostics/diagnostic.h"
1415
#include "toolchain/sem_ir/ids.h"
1516
#include "toolchain/sem_ir/impl.h"
@@ -289,7 +290,14 @@ auto DeductionContext::Deduce() -> bool {
289290
if (context().types().Is<SemIR::PatternType>(param_type_id)) {
290291
param_type_id =
291292
SemIR::ExtractScrutineeType(context().sem_ir(), param_type_id);
293+
} else if (context().types().IsFacetType(param_type_id)) {
294+
// Given `fn F[G:! Interface](g: G)`, the type of `g` is `G as type`. For
295+
// deduction, we want to ignore the `as type`, and check that the argument
296+
// can convert to the FacetType of the canonical facet value.
297+
param_id = GetCanonicalFacetOrTypeValue(context(), param_id);
298+
param_type_id = context().insts().Get(param_id).type_id();
292299
}
300+
293301
// If the parameter has a symbolic type, deduce against that.
294302
if (param_type_id.is_symbolic()) {
295303
Add(context().types().GetInstId(param_type_id),
@@ -411,20 +419,6 @@ auto DeductionContext::Deduce() -> bool {
411419
// TODO: Match field name order between param and arg.
412420
break;
413421

414-
case CARBON_KIND(SemIR::FacetAccessType access): {
415-
// Given `fn F[G:! Interface](g: G)`, the type of `g` is `G as type`.
416-
// `G` is a symbolic binding, whose type is a facet type, but `G as
417-
// type` converts into a `FacetAccessType`.
418-
//
419-
// When we see a `FacetAccessType` parameter here, we want to deduce the
420-
// facet type of `G`, not `G as type`, for the argument (so that the
421-
// argument would be a facet value, whose type is the same facet type of
422-
// `G`. So here we "undo" the `as type` operation that's built into the
423-
// `g` parameter's type.
424-
Add(access.facet_value_inst_id, arg_id);
425-
continue;
426-
}
427-
428422
// TODO: Handle more cases.
429423

430424
default:

toolchain/check/testdata/facet/convert_facet_value_to_narrowed_facet_type.carbon

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -694,17 +694,15 @@ fn CallsWithTypeExplicit(U:! type) {
694694
// CHECK:STDOUT: %FeedTame2.ref: %FeedTame2.type = name_ref FeedTame2, file.%FeedTame2.decl [concrete = constants.%FeedTame2]
695695
// CHECK:STDOUT: %w.ref: @HandleTameAnimal2.%W.as_type.loc11_44.1 (%W.as_type) = name_ref w, %w
696696
// CHECK:STDOUT: %W.as_type.loc12_14.1: type = facet_access_type constants.%W [symbolic = %W.as_type.loc11_44.1 (constants.%W.as_type)]
697-
// CHECK:STDOUT: %.loc12_14.1: type = converted constants.%W, %W.as_type.loc12_14.1 [symbolic = %W.as_type.loc11_44.1 (constants.%W.as_type)]
698-
// CHECK:STDOUT: %Animal.facet.loc12_14.1: %Animal.type = facet_value %.loc12_14.1, (constants.%Animal.lookup_impl_witness) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
699-
// CHECK:STDOUT: %.loc12_14.2: %Animal.type = converted %.loc12_14.1, %Animal.facet.loc12_14.1 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
697+
// CHECK:STDOUT: %Animal.facet.loc12_14.1: %Animal.type = facet_value %W.as_type.loc12_14.1, (constants.%Animal.lookup_impl_witness) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
698+
// CHECK:STDOUT: %.loc12_14.1: %Animal.type = converted constants.%W, %Animal.facet.loc12_14.1 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
700699
// CHECK:STDOUT: %facet_value.loc12_14.1: %facet_type.807 = facet_value constants.%W.as_type, (constants.%Eats.lookup_impl_witness, constants.%Tame.lookup_impl_witness) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
701-
// CHECK:STDOUT: %.loc12_14.3: %facet_type.807 = converted constants.%W.as_type, %facet_value.loc12_14.1 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
700+
// CHECK:STDOUT: %.loc12_14.2: %facet_type.807 = converted constants.%W.as_type, %facet_value.loc12_14.1 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
702701
// CHECK:STDOUT: %W.as_type.loc12_14.2: type = facet_access_type constants.%W [symbolic = %W.as_type.loc11_44.1 (constants.%W.as_type)]
703-
// CHECK:STDOUT: %.loc12_14.4: type = converted constants.%W, %W.as_type.loc12_14.2 [symbolic = %W.as_type.loc11_44.1 (constants.%W.as_type)]
704-
// CHECK:STDOUT: %Animal.facet.loc12_14.2: %Animal.type = facet_value %.loc12_14.4, (constants.%Animal.lookup_impl_witness) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
705-
// CHECK:STDOUT: %.loc12_14.5: %Animal.type = converted %.loc12_14.4, %Animal.facet.loc12_14.2 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
702+
// CHECK:STDOUT: %Animal.facet.loc12_14.2: %Animal.type = facet_value %W.as_type.loc12_14.2, (constants.%Animal.lookup_impl_witness) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
703+
// CHECK:STDOUT: %.loc12_14.3: %Animal.type = converted constants.%W, %Animal.facet.loc12_14.2 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)]
706704
// CHECK:STDOUT: %facet_value.loc12_14.2: %facet_type.807 = facet_value constants.%W.as_type, (constants.%Eats.lookup_impl_witness, constants.%Tame.lookup_impl_witness) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
707-
// CHECK:STDOUT: %.loc12_14.6: %facet_type.807 = converted constants.%W.as_type, %facet_value.loc12_14.2 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
705+
// CHECK:STDOUT: %.loc12_14.4: %facet_type.807 = converted constants.%W.as_type, %facet_value.loc12_14.2 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)]
708706
// CHECK:STDOUT: %FeedTame2.specific_fn.loc12_3.1: <specific function> = specific_function %FeedTame2.ref, @FeedTame2(constants.%facet_value) [symbolic = %FeedTame2.specific_fn.loc12_3.2 (constants.%FeedTame2.specific_fn)]
709707
// CHECK:STDOUT: %FeedTame2.call: init %empty_tuple.type = call %FeedTame2.specific_fn.loc12_3.1(%w.ref)
710708
// CHECK:STDOUT: return

toolchain/check/testdata/facet/convert_facet_value_value_to_blanket_impl.carbon

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,16 +183,10 @@ fn HandleAnimal[T:! Animal](a: T) { Feed(a); }
183183
// CHECK:STDOUT: !entry:
184184
// CHECK:STDOUT: %Feed.ref: %Feed.type = name_ref Feed, file.%Feed.decl [concrete = constants.%Feed]
185185
// CHECK:STDOUT: %a.ref: @HandleAnimal.%T.as_type.loc22_32.1 (%T.as_type.855) = name_ref a, %a
186-
// CHECK:STDOUT: %T.as_type.loc22_43.1: type = facet_access_type constants.%T.611 [symbolic = %T.as_type.loc22_32.1 (constants.%T.as_type.855)]
187-
// CHECK:STDOUT: %.loc22_43.1: type = converted constants.%T.611, %T.as_type.loc22_43.1 [symbolic = %T.as_type.loc22_32.1 (constants.%T.as_type.855)]
188-
// CHECK:STDOUT: %.loc22_43.2: %Animal.type = converted %.loc22_43.1, constants.%T.611 [symbolic = %T.loc22_17.1 (constants.%T.611)]
189186
// CHECK:STDOUT: %Eats.facet.loc22_43.1: %Eats.type = facet_value constants.%T.as_type.855, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc22_43.3 (constants.%Eats.facet)]
190-
// CHECK:STDOUT: %.loc22_43.3: %Eats.type = converted constants.%T.as_type.855, %Eats.facet.loc22_43.1 [symbolic = %Eats.facet.loc22_43.3 (constants.%Eats.facet)]
191-
// CHECK:STDOUT: %T.as_type.loc22_43.2: type = facet_access_type constants.%T.611 [symbolic = %T.as_type.loc22_32.1 (constants.%T.as_type.855)]
192-
// CHECK:STDOUT: %.loc22_43.4: type = converted constants.%T.611, %T.as_type.loc22_43.2 [symbolic = %T.as_type.loc22_32.1 (constants.%T.as_type.855)]
193-
// CHECK:STDOUT: %.loc22_43.5: %Animal.type = converted %.loc22_43.4, constants.%T.611 [symbolic = %T.loc22_17.1 (constants.%T.611)]
187+
// CHECK:STDOUT: %.loc22_43.1: %Eats.type = converted constants.%T.as_type.855, %Eats.facet.loc22_43.1 [symbolic = %Eats.facet.loc22_43.3 (constants.%Eats.facet)]
194188
// CHECK:STDOUT: %Eats.facet.loc22_43.2: %Eats.type = facet_value constants.%T.as_type.855, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc22_43.3 (constants.%Eats.facet)]
195-
// CHECK:STDOUT: %.loc22_43.6: %Eats.type = converted constants.%T.as_type.855, %Eats.facet.loc22_43.2 [symbolic = %Eats.facet.loc22_43.3 (constants.%Eats.facet)]
189+
// CHECK:STDOUT: %.loc22_43.2: %Eats.type = converted constants.%T.as_type.855, %Eats.facet.loc22_43.2 [symbolic = %Eats.facet.loc22_43.3 (constants.%Eats.facet)]
196190
// CHECK:STDOUT: %Feed.specific_fn.loc22_37.1: <specific function> = specific_function %Feed.ref, @Feed(constants.%Eats.facet) [symbolic = %Feed.specific_fn.loc22_37.2 (constants.%Feed.specific_fn)]
197191
// CHECK:STDOUT: %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc22_37.1(%a.ref)
198192
// CHECK:STDOUT: return

toolchain/check/testdata/facet/convert_facet_value_value_to_generic_facet_value_value.carbon

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,11 +390,8 @@ fn F() {
390390
// CHECK:STDOUT: %.loc32_76.1: %Edible.type = converted constants.%Food.as_type.e6f, constants.%Food.dcb [symbolic = %Food.loc32_29.1 (constants.%Food.dcb)]
391391
// CHECK:STDOUT: %.loc32_76.2: %Edible.type = converted constants.%Food.as_type.e6f, constants.%Food.dcb [symbolic = %Food.loc32_29.1 (constants.%Food.dcb)]
392392
// CHECK:STDOUT: %.loc32_76.3: %Edible.type = converted constants.%Food.as_type.e6f, constants.%Food.dcb [symbolic = %Food.loc32_29.1 (constants.%Food.dcb)]
393-
// CHECK:STDOUT: %T.as_type.loc32_76: type = facet_access_type constants.%T.611 [symbolic = %T.as_type.loc32_47.1 (constants.%T.as_type.855)]
394-
// CHECK:STDOUT: %.loc32_76.4: type = converted constants.%T.611, %T.as_type.loc32_76 [symbolic = %T.as_type.loc32_47.1 (constants.%T.as_type.855)]
395-
// CHECK:STDOUT: %.loc32_76.5: %Animal.type = converted %.loc32_76.4, constants.%T.611 [symbolic = %T.loc32_17.1 (constants.%T.611)]
396393
// CHECK:STDOUT: %Eats.facet.loc32_76.1: @HandleAnimal.%Eats.type (%Eats.type.130190.2) = facet_value constants.%T.as_type.855, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc32_76.2 (constants.%Eats.facet.7b7)]
397-
// CHECK:STDOUT: %.loc32_76.6: @HandleAnimal.%Eats.type (%Eats.type.130190.2) = converted constants.%T.as_type.855, %Eats.facet.loc32_76.1 [symbolic = %Eats.facet.loc32_76.2 (constants.%Eats.facet.7b7)]
394+
// CHECK:STDOUT: %.loc32_76.4: @HandleAnimal.%Eats.type (%Eats.type.130190.2) = converted constants.%T.as_type.855, %Eats.facet.loc32_76.1 [symbolic = %Eats.facet.loc32_76.2 (constants.%Eats.facet.7b7)]
398395
// CHECK:STDOUT: %Feed.specific_fn.loc32_64.1: <specific function> = specific_function %Feed.ref, @Feed(constants.%Food.dcb, constants.%Eats.facet.7b7) [symbolic = %Feed.specific_fn.loc32_64.2 (constants.%Feed.specific_fn.76b)]
399396
// CHECK:STDOUT: %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc32_64.1(%a.ref, %food.ref)
400397
// CHECK:STDOUT: return

toolchain/check/testdata/generic/template/unimplemented.carbon

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,11 @@ fn F[template T:! Core.Destroy](x: T) {
334334
// CHECK:STDOUT: !definition:
335335
// CHECK:STDOUT: %require_complete.loc4: <witness> = require_complete_type %T.as_type.loc4_36.1 [template = %require_complete.loc4 (constants.%require_complete.f78)]
336336
// CHECK:STDOUT: %ImplicitAs.type.loc14_3.2: type = facet_type <@ImplicitAs, @ImplicitAs(%T.as_type.loc4_36.1)> [template = %ImplicitAs.type.loc14_3.2 (constants.%ImplicitAs.type.57b)]
337-
// CHECK:STDOUT: %.loc14_3.5: <instruction> = access_member_action %ImplicitAs.type.loc14_3.1, Convert [template]
338-
// CHECK:STDOUT: %.loc14_3.6: type = type_of_inst %.loc14_3.5 [template]
337+
// CHECK:STDOUT: %.loc14_3.4: <instruction> = access_member_action %ImplicitAs.type.loc14_3.1, Convert [template]
338+
// CHECK:STDOUT: %.loc14_3.5: type = type_of_inst %.loc14_3.4 [template]
339339
// CHECK:STDOUT: %Destroy.lookup_impl_witness: <witness> = lookup_impl_witness %T.loc4_15.1, @Destroy [template = %Destroy.lookup_impl_witness (constants.%Destroy.lookup_impl_witness)]
340-
// CHECK:STDOUT: %.loc14_3.7: type = fn_type_with_self_type constants.%Destroy.Op.type, %T.loc4_15.1 [template = %.loc14_3.7 (constants.%.8eb)]
341-
// CHECK:STDOUT: %impl.elem0.loc14_3.2: @F.%.loc14_3.7 (%.8eb) = impl_witness_access %Destroy.lookup_impl_witness, element0 [template = %impl.elem0.loc14_3.2 (constants.%impl.elem0.b2e)]
340+
// CHECK:STDOUT: %.loc14_3.6: type = fn_type_with_self_type constants.%Destroy.Op.type, %T.loc4_15.1 [template = %.loc14_3.6 (constants.%.8eb)]
341+
// CHECK:STDOUT: %impl.elem0.loc14_3.2: @F.%.loc14_3.6 (%.8eb) = impl_witness_access %Destroy.lookup_impl_witness, element0 [template = %impl.elem0.loc14_3.2 (constants.%impl.elem0.b2e)]
342342
// CHECK:STDOUT: %specific_impl_fn.loc14_3.2: <specific function> = specific_impl_function %impl.elem0.loc14_3.2, @Destroy.Op(%T.loc4_15.1) [template = %specific_impl_fn.loc14_3.2 (constants.%specific_impl_fn.b6b)]
343343
// CHECK:STDOUT: %ptr: type = ptr_type %T.as_type.loc4_36.1 [template = %ptr (constants.%ptr.983a2f.2)]
344344
// CHECK:STDOUT: %require_complete.loc14: <witness> = require_complete_type %ptr [template = %require_complete.loc14 (constants.%require_complete.a61)]
@@ -352,7 +352,7 @@ fn F[template T:! Core.Destroy](x: T) {
352352
// CHECK:STDOUT: %v.var: ref @F.%T.as_type.loc4_36.1 (%T.as_type.a11) = var %v.var_patt
353353
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0]
354354
// CHECK:STDOUT: %ImplicitAs.type.loc14_3.1: type = facet_type <@ImplicitAs, @ImplicitAs(constants.%T.as_type.a11)> [template = %ImplicitAs.type.loc14_3.2 (constants.%ImplicitAs.type.57b)]
355-
// CHECK:STDOUT: %.loc14_3.1: @F.%.loc14_3.6 (@F.%.loc14_3.6) = splice_inst %.loc14_3.5
355+
// CHECK:STDOUT: %.loc14_3.1: @F.%.loc14_3.5 (@F.%.loc14_3.5) = splice_inst %.loc14_3.4
356356
// CHECK:STDOUT: %.loc14_3.2: @F.%T.as_type.loc4_36.1 (%T.as_type.a11) = converted %int_0, <error> [concrete = <error>]
357357
// CHECK:STDOUT: assign %v.var, <error>
358358
// CHECK:STDOUT: %.loc14_10.1: type = splice_block %.loc14_10.2 [template = %T.as_type.loc4_36.1 (constants.%T.as_type.a11)] {
@@ -370,29 +370,27 @@ fn F[template T:! Core.Destroy](x: T) {
370370
// CHECK:STDOUT: %Copy.facet: %Copy.type = facet_value constants.%i32, (constants.%Copy.impl_witness.dc4) [concrete = constants.%Copy.facet]
371371
// CHECK:STDOUT: %.loc22_3.1: %Copy.type = converted constants.%i32, %Copy.facet [concrete = constants.%Copy.facet]
372372
// CHECK:STDOUT: %T.as_type.loc22: type = facet_access_type constants.%T.9ff [template = %T.as_type.loc4_36.1 (constants.%T.as_type.a11)]
373-
// CHECK:STDOUT: %.loc22_3.2: type = converted constants.%T.9ff, %T.as_type.loc22 [template = %T.as_type.loc4_36.1 (constants.%T.as_type.a11)]
374-
// CHECK:STDOUT: %.loc22_3.3: %i32 = converted %x.ref, <error> [concrete = <error>]
373+
// CHECK:STDOUT: %.loc22_3.2: %i32 = converted %x.ref, <error> [concrete = <error>]
375374
// CHECK:STDOUT: assign %w.var, <error>
376375
// CHECK:STDOUT: %.loc22_10: type = splice_block %i32 [concrete = constants.%i32] {
377376
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
378377
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
379378
// CHECK:STDOUT: }
380379
// CHECK:STDOUT: %w: ref %i32 = bind_name w, %w.var
381380
// CHECK:STDOUT: %facet_value: %type_where = facet_value constants.%i32, () [concrete = constants.%facet_value]
382-
// CHECK:STDOUT: %.loc22_3.4: %type_where = converted constants.%i32, %facet_value [concrete = constants.%facet_value]
381+
// CHECK:STDOUT: %.loc22_3.3: %type_where = converted constants.%i32, %facet_value [concrete = constants.%facet_value]
383382
// CHECK:STDOUT: %DestroyT.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %w.var, constants.%DestroyT.as_type.as.Destroy.impl.Op.cad
384383
// CHECK:STDOUT: %DestroyT.as_type.as.Destroy.impl.Op.specific_fn: <specific function> = specific_function constants.%DestroyT.as_type.as.Destroy.impl.Op.cad, @DestroyT.as_type.as.Destroy.impl.Op(constants.%facet_value) [concrete = constants.%DestroyT.as_type.as.Destroy.impl.Op.specific_fn]
385384
// CHECK:STDOUT: %bound_method.loc22: <bound method> = bound_method %w.var, %DestroyT.as_type.as.Destroy.impl.Op.specific_fn
386385
// CHECK:STDOUT: %addr.loc22: %ptr.235 = addr_of %w.var
387386
// CHECK:STDOUT: %DestroyT.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc22(%addr.loc22)
388387
// CHECK:STDOUT: %T.as_type.loc14_3: type = facet_access_type constants.%T.9ff [template = %T.as_type.loc4_36.1 (constants.%T.as_type.a11)]
389-
// CHECK:STDOUT: %.loc14_3.3: type = converted constants.%T.9ff, %T.as_type.loc14_3 [template = %T.as_type.loc4_36.1 (constants.%T.as_type.a11)]
390-
// CHECK:STDOUT: %impl.elem0.loc14_3.1: @F.%.loc14_3.7 (%.8eb) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [template = %impl.elem0.loc14_3.2 (constants.%impl.elem0.b2e)]
388+
// CHECK:STDOUT: %impl.elem0.loc14_3.1: @F.%.loc14_3.6 (%.8eb) = impl_witness_access constants.%Destroy.lookup_impl_witness, element0 [template = %impl.elem0.loc14_3.2 (constants.%impl.elem0.b2e)]
391389
// CHECK:STDOUT: %bound_method.loc14_3.1: <bound method> = bound_method %v.var, %impl.elem0.loc14_3.1
392390
// CHECK:STDOUT: %specific_impl_fn.loc14_3.1: <specific function> = specific_impl_function %impl.elem0.loc14_3.1, @Destroy.Op(constants.%T.9ff) [template = %specific_impl_fn.loc14_3.2 (constants.%specific_impl_fn.b6b)]
393391
// CHECK:STDOUT: %bound_method.loc14_3.2: <bound method> = bound_method %v.var, %specific_impl_fn.loc14_3.1
394392
// CHECK:STDOUT: %addr.loc14: @F.%ptr (%ptr.983a2f.2) = addr_of %v.var
395-
// CHECK:STDOUT: %.loc14_3.4: init %empty_tuple.type = call %bound_method.loc14_3.2(%addr.loc14)
393+
// CHECK:STDOUT: %.loc14_3.3: init %empty_tuple.type = call %bound_method.loc14_3.2(%addr.loc14)
396394
// CHECK:STDOUT: return
397395
// CHECK:STDOUT: }
398396
// CHECK:STDOUT: }

0 commit comments

Comments
 (0)