Bläddra i källkod

Make Optional support specializing its representation. (#6058)

Switch to using a pair of `MaybeUnformed(T)` and a `bool` as the normal
representation for `Optional(T)`. When `T` is a pointer type, add a
customized representation that uses `MaybeUnformed(T*)`, with a null
representation used for absent values.
Richard Smith 6 månader sedan
förälder
incheckning
851da43c88

+ 76 - 16
core/prelude/types/optional.carbon

@@ -6,30 +6,90 @@ package Core library "prelude/types/optional";
 
 import library "prelude/copy";
 import library "prelude/destroy";
+import library "prelude/operators/as";
 import library "prelude/types/bool";
+import library "prelude/types/maybe_unformed";
+
+// TODO: Decide how to expose this in the public API.
+private interface OptionalStorage {
+  let Type:! type;
+  fn None() -> Type;
+  fn Some[self: Self]() -> Type;
+  fn Has(value: Type) -> bool;
+  fn Get(value: Type) -> Self;
+}
 
-// For now, an `Optional(T)` is stored as a pair of a `bool` and a `T`, with
-// the `T` left uninitialized if the `bool` is `false`. This isn't a viable
-// approach in the longer term, but is the best we can do for now.
-//
-// TODO: Revisit this once we have choice types implemented in the toolchain.
-//
 // TODO: We don't have an approved design for an `Optional` type yet, but it's
 // used by the design for `Iterate`. The API here is a placeholder.
-class Optional(T:! Copy) {
+class Optional(T:! OptionalStorage) {
   fn None() -> Self {
-    returned var me: Self;
-    me.has_value = false;
-    return var;
+    return T.None() as Self;
   }
-
   fn Some(value: T) -> Self {
-    return {.has_value = true, .value = value};
+    return value.Some() as Self;
+  }
+  fn HasValue[self: Self]() -> bool {
+    return T.Has(self as T.Type);
+  }
+  fn Get[self: Self]() -> T {
+    return T.Get(self as T.Type);
   }
 
-  fn HasValue[self: Self]() -> bool { return self.has_value; }
-  fn Get[self: Self]() -> T { return self.value; }
+  impl T as ImplicitAs(Optional(T)) {
+    fn Convert[self: T]() -> Optional(T) {
+      return Some(self);
+    }
+  }
 
-  private var has_value: bool;
-  private var value: T;
+  // TODO: Use `private adapt` or `unsafe adapt` once available.
+  adapt T.Type;
+}
+
+// By default, an `Optional(T)` is stored as a pair of a `bool` and a
+// `MaybeUnformed(T)`, with the `MaybeUnformed(T)` left uninitialized if the
+// `bool` is `false`.
+//
+// TODO: Revisit this once we have choice types implemented in the toolchain.
+private class DefaultOptionalStorage(T:! Copy) {
+  var value: MaybeUnformed(T);
+  var has_value: bool;
+}
+
+impl forall [T:! Copy] T as OptionalStorage
+    where .Type = DefaultOptionalStorage(T) {
+  fn None() -> DefaultOptionalStorage(T) {
+    returned var me: DefaultOptionalStorage(T);
+    me.has_value = false;
+    return var;
+  }
+  fn Some[self: Self]() -> DefaultOptionalStorage(T) {
+    returned var me: DefaultOptionalStorage(T);
+    // TODO: Should be:
+    //   me.value = self as MaybeUnformed(T);
+    me.value unsafe as T = self;
+    me.has_value = true;
+    return var;
+  }
+  fn Has(value: DefaultOptionalStorage(T)) -> bool {
+    return value.has_value;
+  }
+  fn Get(value: DefaultOptionalStorage(T)) -> T {
+    return value.value unsafe as T;
+  }
+}
+
+// For pointers, we use a null pointer value as the "None" value. This allows
+// `Optional(T*)` to be ABI-compatible with a C++ nullable pointer.
+final impl forall [T:! type] T* as OptionalStorage
+    where .Type = MaybeUnformed(T*) {
+  fn None() -> MaybeUnformed(T*) = "pointer.make_null";
+  fn Some[self: Self]() -> MaybeUnformed(T*) {
+    returned var result: MaybeUnformed(T*);
+    result unsafe as T* = self;
+    return var;
+  }
+  fn Has(value: MaybeUnformed(T*)) -> bool = "pointer.is_null";
+  fn Get(value: MaybeUnformed(T*)) -> T* {
+    return value unsafe as T*;
+  }
 }

+ 71 - 66
toolchain/check/testdata/for/actual.carbon

@@ -80,7 +80,6 @@ fn Read() {
 // CHECK:STDOUT:   %assoc0.0f6: %Iterate.assoc_type = assoc_entity element0, imports.%Core.import_ref.61e [concrete]
 // CHECK:STDOUT:   %Copy.type: type = facet_type <@Copy> [concrete]
 // CHECK:STDOUT:   %impl.elem0.5f7: %Copy.type = impl_witness_access %Iterate.lookup_impl_witness.106, element0 [symbolic_self]
-// CHECK:STDOUT:   %T.be8: %Copy.type = bind_symbolic_name T, 0 [symbolic]
 // CHECK:STDOUT:   %Copy.Op.type: type = fn_type @Copy.Op [concrete]
 // CHECK:STDOUT:   %Int.as.Copy.impl.Op.type.afd: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic]
 // CHECK:STDOUT:   %Int.as.Copy.impl.Op.6cd: %Int.as.Copy.impl.Op.type.afd = struct_value () [symbolic]
@@ -89,19 +88,23 @@ fn Read() {
 // CHECK:STDOUT:   %Copy.facet.cd7: %Copy.type = facet_value %Int.49d0e6.1, (%Copy.lookup_impl_witness.ccc) [symbolic]
 // CHECK:STDOUT:   %Iterate_where.type: type = facet_type <@Iterate where %impl.elem1.1c0 = %Int.49d0e6.1 and %impl.elem0.5f7 = %Copy.facet.cd7> [symbolic]
 // CHECK:STDOUT:   %require_complete.c0e: <witness> = require_complete_type %Iterate_where.type [symbolic]
+// CHECK:STDOUT:   %OptionalStorage.type: type = facet_type <@OptionalStorage> [concrete]
 // CHECK:STDOUT:   %Optional.type: type = generic_class_type @Optional [concrete]
 // CHECK:STDOUT:   %Optional.generic: %Optional.type = struct_value () [concrete]
-// CHECK:STDOUT:   %Optional.None.type.3df: type = fn_type @Optional.None, @Optional(%T.be8) [symbolic]
-// CHECK:STDOUT:   %Optional.None.321: %Optional.None.type.3df = struct_value () [symbolic]
-// CHECK:STDOUT:   %Optional.Some.type.48a: type = fn_type @Optional.Some, @Optional(%T.be8) [symbolic]
-// CHECK:STDOUT:   %Optional.Some.a29: %Optional.Some.type.48a = struct_value () [symbolic]
+// CHECK:STDOUT:   %T.76d: %OptionalStorage.type = bind_symbolic_name T, 0 [symbolic]
+// CHECK:STDOUT:   %Optional.None.type.3a2: type = fn_type @Optional.None, @Optional(%T.76d) [symbolic]
+// CHECK:STDOUT:   %Optional.None.96b: %Optional.None.type.3a2 = struct_value () [symbolic]
+// CHECK:STDOUT:   %Optional.Some.type.377: type = fn_type @Optional.Some, @Optional(%T.76d) [symbolic]
+// CHECK:STDOUT:   %Optional.Some.503: %Optional.Some.type.377 = struct_value () [symbolic]
 // CHECK:STDOUT:   %Iterate.impl_witness: <witness> = impl_witness @IntRange.%Iterate.impl_witness_table, @IntRange.as.Iterate.impl(%N) [symbolic]
 // CHECK:STDOUT:   %IntRange.as.Iterate.impl.NewCursor.type: type = fn_type @IntRange.as.Iterate.impl.NewCursor, @IntRange.as.Iterate.impl(%N) [symbolic]
 // CHECK:STDOUT:   %IntRange.as.Iterate.impl.NewCursor: %IntRange.as.Iterate.impl.NewCursor.type = struct_value () [symbolic]
 // CHECK:STDOUT:   %ptr.784: type = ptr_type %Int.49d0e6.1 [symbolic]
 // CHECK:STDOUT:   %pattern_type.4dc: type = pattern_type %ptr.784 [symbolic]
-// CHECK:STDOUT:   %Optional.671: type = class_type @Optional, @Optional(%Copy.facet.cd7) [symbolic]
-// CHECK:STDOUT:   %pattern_type.ff2: type = pattern_type %Optional.671 [symbolic]
+// CHECK:STDOUT:   %OptionalStorage.lookup_impl_witness.664: <witness> = lookup_impl_witness %Int.49d0e6.1, @OptionalStorage [symbolic]
+// CHECK:STDOUT:   %OptionalStorage.facet.169: %OptionalStorage.type = facet_value %Int.49d0e6.1, (%OptionalStorage.lookup_impl_witness.664) [symbolic]
+// CHECK:STDOUT:   %Optional.37d: type = class_type @Optional, @Optional(%OptionalStorage.facet.169) [symbolic]
+// CHECK:STDOUT:   %pattern_type.485: type = pattern_type %Optional.37d [symbolic]
 // CHECK:STDOUT:   %IntRange.as.Iterate.impl.Next.type: type = fn_type @IntRange.as.Iterate.impl.Next, @IntRange.as.Iterate.impl(%N) [symbolic]
 // CHECK:STDOUT:   %IntRange.as.Iterate.impl.Next: %IntRange.as.Iterate.impl.Next.type = struct_value () [symbolic]
 // CHECK:STDOUT:   %IntRange.elem.e7c: type = unbound_element_type %IntRange.349, %Int.49d0e6.1 [symbolic]
@@ -111,11 +114,11 @@ fn Read() {
 // CHECK:STDOUT:   %.8f7: type = fn_type_with_self_type %Copy.Op.type, %Copy.facet.cd7 [symbolic]
 // CHECK:STDOUT:   %impl.elem0.840: %.8f7 = impl_witness_access %Copy.lookup_impl_witness.ccc, element0 [symbolic]
 // CHECK:STDOUT:   %specific_impl_fn.70b: <specific function> = specific_impl_function %impl.elem0.840, @Copy.Op(%Copy.facet.cd7) [symbolic]
-// CHECK:STDOUT:   %Optional.None.type.66e: type = fn_type @Optional.None, @Optional(%Copy.facet.cd7) [symbolic]
-// CHECK:STDOUT:   %Optional.None.016: %Optional.None.type.66e = struct_value () [symbolic]
-// CHECK:STDOUT:   %Optional.Some.type.20f: type = fn_type @Optional.Some, @Optional(%Copy.facet.cd7) [symbolic]
-// CHECK:STDOUT:   %Optional.Some.dff: %Optional.Some.type.20f = struct_value () [symbolic]
-// CHECK:STDOUT:   %require_complete.380: <witness> = require_complete_type %Optional.671 [symbolic]
+// CHECK:STDOUT:   %Optional.None.type.6c4: type = fn_type @Optional.None, @Optional(%OptionalStorage.facet.169) [symbolic]
+// CHECK:STDOUT:   %Optional.None.f70: %Optional.None.type.6c4 = struct_value () [symbolic]
+// CHECK:STDOUT:   %Optional.Some.type.879: type = fn_type @Optional.Some, @Optional(%OptionalStorage.facet.169) [symbolic]
+// CHECK:STDOUT:   %Optional.Some.d45: %Optional.Some.type.879 = struct_value () [symbolic]
+// CHECK:STDOUT:   %require_complete.f48: <witness> = require_complete_type %Optional.37d [symbolic]
 // CHECK:STDOUT:   %require_complete.0f5: <witness> = require_complete_type %ptr.784 [symbolic]
 // CHECK:STDOUT:   %OrderedWith.type.270: type = generic_interface_type @OrderedWith [concrete]
 // CHECK:STDOUT:   %OrderedWith.generic: %OrderedWith.type.270 = struct_value () [concrete]
@@ -126,7 +129,7 @@ fn Read() {
 // CHECK:STDOUT:   %OrderedWith.type.389: type = facet_type <@OrderedWith, @OrderedWith(%Int.49d0e6.1)> [symbolic]
 // CHECK:STDOUT:   %OrderedWith.Less.type.8fe: type = fn_type @OrderedWith.Less, @OrderedWith(%Int.49d0e6.1) [symbolic]
 // CHECK:STDOUT:   %OrderedWith.assoc_type.d92: type = assoc_entity_type @OrderedWith, @OrderedWith(%Int.49d0e6.1) [symbolic]
-// CHECK:STDOUT:   %assoc0.2ae: %OrderedWith.assoc_type.d92 = assoc_entity element0, imports.%Core.import_ref.9108 [symbolic]
+// CHECK:STDOUT:   %assoc0.2ae: %OrderedWith.assoc_type.d92 = assoc_entity element0, imports.%Core.import_ref.910 [symbolic]
 // CHECK:STDOUT:   %require_complete.1fb: <witness> = require_complete_type %OrderedWith.type.389 [symbolic]
 // CHECK:STDOUT:   %assoc0.3c6: %OrderedWith.assoc_type.03c = assoc_entity element0, imports.%Core.import_ref.146ebd.1 [symbolic]
 // CHECK:STDOUT:   %M: Core.IntLiteral = bind_symbolic_name M, 1 [symbolic]
@@ -147,7 +150,7 @@ fn Read() {
 // CHECK:STDOUT:   %.941: type = fn_type_with_self_type %Inc.Op.type, %Inc.facet [symbolic]
 // CHECK:STDOUT:   %impl.elem0.bca: %.941 = impl_witness_access %Inc.lookup_impl_witness, element0 [symbolic]
 // CHECK:STDOUT:   %specific_impl_fn.989: <specific function> = specific_impl_function %impl.elem0.bca, @Inc.Op(%Inc.facet) [symbolic]
-// CHECK:STDOUT:   %Optional.Some.specific_fn: <specific function> = specific_function %Optional.Some.dff, @Optional.Some(%Copy.facet.cd7) [symbolic]
+// CHECK:STDOUT:   %Optional.Some.specific_fn: <specific function> = specific_function %Optional.Some.d45, @Optional.Some(%OptionalStorage.facet.169) [symbolic]
 // CHECK:STDOUT:   %Destroy.type: type = facet_type <@Destroy> [concrete]
 // CHECK:STDOUT:   %Destroy.Op.type: type = fn_type @Destroy.Op [concrete]
 // CHECK:STDOUT:   %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
@@ -161,7 +164,7 @@ fn Read() {
 // CHECK:STDOUT:   %Destroy.facet: %Destroy.type = facet_value %Int.49d0e6.1, (%Destroy.impl_witness.47b) [symbolic]
 // CHECK:STDOUT:   %.944: type = fn_type_with_self_type %Destroy.Op.type, %Destroy.facet [symbolic]
 // CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn: <specific function> = specific_function %DestroyT.binding.as_type.as.Destroy.impl.Op.db2, @DestroyT.binding.as_type.as.Destroy.impl.Op(%facet_value) [symbolic]
-// CHECK:STDOUT:   %Optional.None.specific_fn: <specific function> = specific_function %Optional.None.016, @Optional.None(%Copy.facet.cd7) [symbolic]
+// CHECK:STDOUT:   %Optional.None.specific_fn: <specific function> = specific_function %Optional.None.f70, @Optional.None(%OptionalStorage.facet.169) [symbolic]
 // CHECK:STDOUT:   %int_32: Core.IntLiteral = int_value 32 [concrete]
 // CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
 // CHECK:STDOUT:   %pattern_type.7ce: type = pattern_type %i32 [concrete]
@@ -225,13 +228,13 @@ fn Read() {
 // CHECK:STDOUT:   %ElementType: %Copy.type = assoc_const_decl @ElementType [concrete] {}
 // CHECK:STDOUT:   %Core.import_ref.d0f6: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.afd) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.6cd)]
 // CHECK:STDOUT:   %Copy.impl_witness_table.1ed = impl_witness_table (%Core.import_ref.d0f6), @Int.as.Copy.impl [concrete]
-// CHECK:STDOUT:   %Core.import_ref.725b: @Optional.%Optional.None.type (%Optional.None.type.3df) = import_ref Core//prelude/iterate, inst{{[0-9A-F]+}} [indirect], loaded [symbolic = @Optional.%Optional.None (constants.%Optional.None.321)]
-// CHECK:STDOUT:   %Core.import_ref.9103: @Optional.%Optional.Some.type (%Optional.Some.type.48a) = import_ref Core//prelude/iterate, inst{{[0-9A-F]+}} [indirect], loaded [symbolic = @Optional.%Optional.Some (constants.%Optional.Some.a29)]
+// CHECK:STDOUT:   %Core.import_ref.7dc: @Optional.%Optional.None.type (%Optional.None.type.3a2) = import_ref Core//prelude/iterate, inst{{[0-9A-F]+}} [indirect], loaded [symbolic = @Optional.%Optional.None (constants.%Optional.None.96b)]
+// CHECK:STDOUT:   %Core.import_ref.ea3: @Optional.%Optional.Some.type (%Optional.Some.type.377) = import_ref Core//prelude/iterate, inst{{[0-9A-F]+}} [indirect], loaded [symbolic = @Optional.%Optional.Some (constants.%Optional.Some.503)]
 // CHECK:STDOUT:   %Core.Optional: %Optional.type = import_ref Core//prelude/types/optional, Optional, loaded [concrete = constants.%Optional.generic]
 // CHECK:STDOUT:   %Core.Copy: type = import_ref Core//prelude/copy, Copy, loaded [concrete = constants.%Copy.type]
 // CHECK:STDOUT:   %Core.OrderedWith: %OrderedWith.type.270 = import_ref Core//prelude/operators/comparison, OrderedWith, loaded [concrete = constants.%OrderedWith.generic]
 // CHECK:STDOUT:   %Core.import_ref.1cc: @OrderedWith.%OrderedWith.assoc_type (%OrderedWith.assoc_type.03c) = import_ref Core//prelude/operators/comparison, loc{{\d+_\d+}}, loaded [symbolic = @OrderedWith.%assoc0 (constants.%assoc0.3c6)]
-// CHECK:STDOUT:   %Core.import_ref.9108: @OrderedWith.%OrderedWith.Less.type (%OrderedWith.Less.type.f19) = import_ref Core//prelude/operators/comparison, loc{{\d+_\d+}}, loaded [symbolic = @OrderedWith.%OrderedWith.Less (constants.%OrderedWith.Less.02e)]
+// CHECK:STDOUT:   %Core.import_ref.910: @OrderedWith.%OrderedWith.Less.type (%OrderedWith.Less.type.f19) = import_ref Core//prelude/operators/comparison, loc{{\d+_\d+}}, loaded [symbolic = @OrderedWith.%OrderedWith.Less (constants.%OrderedWith.Less.02e)]
 // CHECK:STDOUT:   %Core.import_ref.146ebd.1 = import_ref Core//prelude/operators/comparison, loc{{\d+_\d+}}, unloaded
 // CHECK:STDOUT:   %Core.import_ref.ab6: @Int.as.OrderedWith.impl.aed.%Int.as.OrderedWith.impl.Less.type (%Int.as.OrderedWith.impl.Less.type.6d6) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.OrderedWith.impl.aed.%Int.as.OrderedWith.impl.Less (constants.%Int.as.OrderedWith.impl.Less.d8b)]
 // CHECK:STDOUT:   %Core.import_ref.54d = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, unloaded
@@ -243,8 +246,8 @@ fn Read() {
 // CHECK:STDOUT:   %Core.import_ref.950: @DestroyT.binding.as_type.as.Destroy.impl.%DestroyT.binding.as_type.as.Destroy.impl.Op.type (%DestroyT.binding.as_type.as.Destroy.impl.Op.type.b5d) = import_ref Core//prelude/destroy, loc{{\d+_\d+}}, loaded [symbolic = @DestroyT.binding.as_type.as.Destroy.impl.%DestroyT.binding.as_type.as.Destroy.impl.Op (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.544)]
 // CHECK:STDOUT:   %Destroy.impl_witness_table = impl_witness_table (%Core.import_ref.950), @DestroyT.binding.as_type.as.Destroy.impl [concrete]
 // CHECK:STDOUT:   %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/operators/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
-// CHECK:STDOUT:   %Core.import_ref.ee7: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.340) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.1c0)]
-// CHECK:STDOUT:   %ImplicitAs.impl_witness_table.9e9 = impl_witness_table (%Core.import_ref.ee7), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
+// CHECK:STDOUT:   %Core.import_ref.ee75: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.340) = import_ref Core//prelude/types/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.1c0)]
+// CHECK:STDOUT:   %ImplicitAs.impl_witness_table.9e9 = impl_witness_table (%Core.import_ref.ee75), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -328,8 +331,8 @@ fn Read() {
 // CHECK:STDOUT:       %self.param_patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_13 (%pattern_type.dcd) = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:       %cursor.patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_25 (%pattern_type.4dc) = binding_pattern cursor [concrete]
 // CHECK:STDOUT:       %cursor.param_patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_25 (%pattern_type.4dc) = value_param_pattern %cursor.patt, call_param1 [concrete]
-// CHECK:STDOUT:       %return.patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_47 (%pattern_type.ff2) = return_slot_pattern [concrete]
-// CHECK:STDOUT:       %return.param_patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_47 (%pattern_type.ff2) = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:       %return.patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_47 (%pattern_type.485) = return_slot_pattern [concrete]
+// CHECK:STDOUT:       %return.param_patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc11_47 (%pattern_type.485) = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:     } {
 // CHECK:STDOUT:       %Core.ref.loc11_50: <namespace> = name_ref Core, imports.%Core [concrete = imports.%Core]
 // CHECK:STDOUT:       %Optional.ref.loc11: %Optional.type = name_ref Optional, imports.%Core.Optional [concrete = constants.%Optional.generic]
@@ -337,9 +340,9 @@ fn Read() {
 // CHECK:STDOUT:       %Int.ref.loc11_68: %Int.type = name_ref Int, imports.%Core.Int [concrete = constants.%Int.generic]
 // CHECK:STDOUT:       %N.ref.loc11_73: Core.IntLiteral = name_ref N, @IntRange.%N.loc4_16.2 [symbolic = %N (constants.%N)]
 // CHECK:STDOUT:       %Int.loc11_74: type = class_type @Int, @Int(constants.%N) [symbolic = %Int.loc11_43.1 (constants.%Int.49d0e6.1)]
-// CHECK:STDOUT:       %Copy.facet.loc11_75.2: %Copy.type = facet_value %Int.loc11_74, (constants.%Copy.lookup_impl_witness.ccc) [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:       %.loc11_75: %Copy.type = converted %Int.loc11_74, %Copy.facet.loc11_75.2 [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:       %Optional.loc11_75.2: type = class_type @Optional, @Optional(constants.%Copy.facet.cd7) [symbolic = %Optional.loc11_75.1 (constants.%Optional.671)]
+// CHECK:STDOUT:       %OptionalStorage.facet.loc11_75.2: %OptionalStorage.type = facet_value %Int.loc11_74, (constants.%OptionalStorage.lookup_impl_witness.664) [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:       %.loc11_75: %OptionalStorage.type = converted %Int.loc11_74, %OptionalStorage.facet.loc11_75.2 [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:       %Optional.loc11_75.2: type = class_type @Optional, @Optional(constants.%OptionalStorage.facet.169) [symbolic = %Optional.loc11_75.1 (constants.%Optional.37d)]
 // CHECK:STDOUT:       %self.param: @IntRange.as.Iterate.impl.Next.%IntRange (%IntRange.349) = value_param call_param0
 // CHECK:STDOUT:       %.loc11_19.1: type = splice_block %Self.ref [symbolic = %IntRange (constants.%IntRange.349)] {
 // CHECK:STDOUT:         %.loc11_19.2: type = specific_constant constants.%IntRange.349, @IntRange(constants.%N) [symbolic = %IntRange (constants.%IntRange.349)]
@@ -355,8 +358,8 @@ fn Read() {
 // CHECK:STDOUT:         %ptr.loc11_44.2: type = ptr_type %Int.loc11_43.2 [symbolic = %ptr.loc11_44.1 (constants.%ptr.784)]
 // CHECK:STDOUT:       }
 // CHECK:STDOUT:       %cursor: @IntRange.as.Iterate.impl.Next.%ptr.loc11_44.1 (%ptr.784) = bind_name cursor, %cursor.param
-// CHECK:STDOUT:       %return.param: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) = out_param call_param2
-// CHECK:STDOUT:       %return: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) = return_slot %return.param
+// CHECK:STDOUT:       %return.param: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) = out_param call_param2
+// CHECK:STDOUT:       %return: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) = return_slot %return.param
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:
 // CHECK:STDOUT:   !members:
@@ -548,25 +551,27 @@ fn Read() {
 // CHECK:STDOUT:   %Int.loc11_43.1: type = class_type @Int, @Int(%N) [symbolic = %Int.loc11_43.1 (constants.%Int.49d0e6.1)]
 // CHECK:STDOUT:   %ptr.loc11_44.1: type = ptr_type %Int.loc11_43.1 [symbolic = %ptr.loc11_44.1 (constants.%ptr.784)]
 // CHECK:STDOUT:   %pattern_type.loc11_25: type = pattern_type %ptr.loc11_44.1 [symbolic = %pattern_type.loc11_25 (constants.%pattern_type.4dc)]
-// CHECK:STDOUT:   %Copy.lookup_impl_witness: <witness> = lookup_impl_witness %Int.loc11_43.1, @Copy [symbolic = %Copy.lookup_impl_witness (constants.%Copy.lookup_impl_witness.ccc)]
-// CHECK:STDOUT:   %Copy.facet.loc11_75.1: %Copy.type = facet_value %Int.loc11_43.1, (%Copy.lookup_impl_witness) [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:   %Optional.loc11_75.1: type = class_type @Optional, @Optional(%Copy.facet.loc11_75.1) [symbolic = %Optional.loc11_75.1 (constants.%Optional.671)]
-// CHECK:STDOUT:   %pattern_type.loc11_47: type = pattern_type %Optional.loc11_75.1 [symbolic = %pattern_type.loc11_47 (constants.%pattern_type.ff2)]
+// CHECK:STDOUT:   %OptionalStorage.lookup_impl_witness: <witness> = lookup_impl_witness %Int.loc11_43.1, @OptionalStorage [symbolic = %OptionalStorage.lookup_impl_witness (constants.%OptionalStorage.lookup_impl_witness.664)]
+// CHECK:STDOUT:   %OptionalStorage.facet.loc11_75.1: %OptionalStorage.type = facet_value %Int.loc11_43.1, (%OptionalStorage.lookup_impl_witness) [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:   %Optional.loc11_75.1: type = class_type @Optional, @Optional(%OptionalStorage.facet.loc11_75.1) [symbolic = %Optional.loc11_75.1 (constants.%Optional.37d)]
+// CHECK:STDOUT:   %pattern_type.loc11_47: type = pattern_type %Optional.loc11_75.1 [symbolic = %pattern_type.loc11_47 (constants.%pattern_type.485)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %require_complete.loc11_47: <witness> = require_complete_type %Optional.loc11_75.1 [symbolic = %require_complete.loc11_47 (constants.%require_complete.380)]
+// CHECK:STDOUT:   %require_complete.loc11_47: <witness> = require_complete_type %Optional.loc11_75.1 [symbolic = %require_complete.loc11_47 (constants.%require_complete.f48)]
 // CHECK:STDOUT:   %require_complete.loc11_17: <witness> = require_complete_type %IntRange [symbolic = %require_complete.loc11_17 (constants.%require_complete.524)]
 // CHECK:STDOUT:   %require_complete.loc11_31: <witness> = require_complete_type %ptr.loc11_44.1 [symbolic = %require_complete.loc11_31 (constants.%require_complete.0f5)]
 // CHECK:STDOUT:   %require_complete.loc12: <witness> = require_complete_type %Int.loc11_43.1 [symbolic = %require_complete.loc12 (constants.%require_complete.b4f426.1)]
 // CHECK:STDOUT:   %pattern_type.loc12: type = pattern_type %Int.loc11_43.1 [symbolic = %pattern_type.loc12 (constants.%pattern_type.8963eb.1)]
-// CHECK:STDOUT:   %.loc12_32.4: type = fn_type_with_self_type constants.%Copy.Op.type, %Copy.facet.loc11_75.1 [symbolic = %.loc12_32.4 (constants.%.8f7)]
+// CHECK:STDOUT:   %Copy.lookup_impl_witness: <witness> = lookup_impl_witness %Int.loc11_43.1, @Copy [symbolic = %Copy.lookup_impl_witness (constants.%Copy.lookup_impl_witness.ccc)]
+// CHECK:STDOUT:   %Copy.facet: %Copy.type = facet_value %Int.loc11_43.1, (%Copy.lookup_impl_witness) [symbolic = %Copy.facet (constants.%Copy.facet.cd7)]
+// CHECK:STDOUT:   %.loc12_32.4: type = fn_type_with_self_type constants.%Copy.Op.type, %Copy.facet [symbolic = %.loc12_32.4 (constants.%.8f7)]
 // CHECK:STDOUT:   %impl.elem0.loc12_32.2: @IntRange.as.Iterate.impl.Next.%.loc12_32.4 (%.8f7) = impl_witness_access %Copy.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc12_32.2 (constants.%impl.elem0.840)]
-// CHECK:STDOUT:   %specific_impl_fn.loc12_32.2: <specific function> = specific_impl_function %impl.elem0.loc12_32.2, @Copy.Op(%Copy.facet.loc11_75.1) [symbolic = %specific_impl_fn.loc12_32.2 (constants.%specific_impl_fn.70b)]
+// CHECK:STDOUT:   %specific_impl_fn.loc12_32.2: <specific function> = specific_impl_function %impl.elem0.loc12_32.2, @Copy.Op(%Copy.facet) [symbolic = %specific_impl_fn.loc12_32.2 (constants.%specific_impl_fn.70b)]
 // CHECK:STDOUT:   %IntRange.elem: type = unbound_element_type %IntRange, %Int.loc11_43.1 [symbolic = %IntRange.elem (constants.%IntRange.elem.e7c)]
 // CHECK:STDOUT:   %OrderedWith.type.loc13_17.2: type = facet_type <@OrderedWith, @OrderedWith(%Int.loc11_43.1)> [symbolic = %OrderedWith.type.loc13_17.2 (constants.%OrderedWith.type.389)]
 // CHECK:STDOUT:   %require_complete.loc13: <witness> = require_complete_type %OrderedWith.type.loc13_17.2 [symbolic = %require_complete.loc13 (constants.%require_complete.1fb)]
 // CHECK:STDOUT:   %OrderedWith.assoc_type: type = assoc_entity_type @OrderedWith, @OrderedWith(%Int.loc11_43.1) [symbolic = %OrderedWith.assoc_type (constants.%OrderedWith.assoc_type.d92)]
-// CHECK:STDOUT:   %assoc0: @IntRange.as.Iterate.impl.Next.%OrderedWith.assoc_type (%OrderedWith.assoc_type.d92) = assoc_entity element0, imports.%Core.import_ref.9108 [symbolic = %assoc0 (constants.%assoc0.2ae)]
+// CHECK:STDOUT:   %assoc0: @IntRange.as.Iterate.impl.Next.%OrderedWith.assoc_type (%OrderedWith.assoc_type.d92) = assoc_entity element0, imports.%Core.import_ref.910 [symbolic = %assoc0 (constants.%assoc0.2ae)]
 // CHECK:STDOUT:   %OrderedWith.impl_witness: <witness> = impl_witness imports.%OrderedWith.impl_witness_table.95f, @Int.as.OrderedWith.impl.aed(%N, %N) [symbolic = %OrderedWith.impl_witness (constants.%OrderedWith.impl_witness.cef)]
 // CHECK:STDOUT:   %OrderedWith.Less.type: type = fn_type @OrderedWith.Less, @OrderedWith(%Int.loc11_43.1) [symbolic = %OrderedWith.Less.type (constants.%OrderedWith.Less.type.8fe)]
 // CHECK:STDOUT:   %OrderedWith.facet: @IntRange.as.Iterate.impl.Next.%OrderedWith.type.loc13_17.2 (%OrderedWith.type.389) = facet_value %Int.loc11_43.1, (%OrderedWith.impl_witness) [symbolic = %OrderedWith.facet (constants.%OrderedWith.facet)]
@@ -579,9 +584,9 @@ fn Read() {
 // CHECK:STDOUT:   %.loc14_9.2: type = fn_type_with_self_type constants.%Inc.Op.type, %Inc.facet [symbolic = %.loc14_9.2 (constants.%.941)]
 // CHECK:STDOUT:   %impl.elem0.loc14_9.2: @IntRange.as.Iterate.impl.Next.%.loc14_9.2 (%.941) = impl_witness_access %Inc.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc14_9.2 (constants.%impl.elem0.bca)]
 // CHECK:STDOUT:   %specific_impl_fn.loc14_9.2: <specific function> = specific_impl_function %impl.elem0.loc14_9.2, @Inc.Op(%Inc.facet) [symbolic = %specific_impl_fn.loc14_9.2 (constants.%specific_impl_fn.989)]
-// CHECK:STDOUT:   %Optional.Some.type: type = fn_type @Optional.Some, @Optional(%Copy.facet.loc11_75.1) [symbolic = %Optional.Some.type (constants.%Optional.Some.type.20f)]
-// CHECK:STDOUT:   %Optional.Some: @IntRange.as.Iterate.impl.Next.%Optional.Some.type (%Optional.Some.type.20f) = struct_value () [symbolic = %Optional.Some (constants.%Optional.Some.dff)]
-// CHECK:STDOUT:   %Optional.Some.specific_fn.loc15_42.2: <specific function> = specific_function %Optional.Some, @Optional.Some(%Copy.facet.loc11_75.1) [symbolic = %Optional.Some.specific_fn.loc15_42.2 (constants.%Optional.Some.specific_fn)]
+// CHECK:STDOUT:   %Optional.Some.type: type = fn_type @Optional.Some, @Optional(%OptionalStorage.facet.loc11_75.1) [symbolic = %Optional.Some.type (constants.%Optional.Some.type.879)]
+// CHECK:STDOUT:   %Optional.Some: @IntRange.as.Iterate.impl.Next.%Optional.Some.type (%Optional.Some.type.879) = struct_value () [symbolic = %Optional.Some (constants.%Optional.Some.d45)]
+// CHECK:STDOUT:   %Optional.Some.specific_fn.loc15_42.2: <specific function> = specific_function %Optional.Some, @Optional.Some(%OptionalStorage.facet.loc11_75.1) [symbolic = %Optional.Some.specific_fn.loc15_42.2 (constants.%Optional.Some.specific_fn)]
 // CHECK:STDOUT:   %facet_value: %type_where = facet_value %Int.loc11_43.1, () [symbolic = %facet_value (constants.%facet_value)]
 // CHECK:STDOUT:   %Destroy.impl_witness: <witness> = impl_witness imports.%Destroy.impl_witness_table, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [symbolic = %Destroy.impl_witness (constants.%Destroy.impl_witness.47b)]
 // CHECK:STDOUT:   %Destroy.facet: %Destroy.type = facet_value %Int.loc11_43.1, (%Destroy.impl_witness) [symbolic = %Destroy.facet (constants.%Destroy.facet)]
@@ -589,11 +594,11 @@ fn Read() {
 // CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.type: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op.type (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.type.c3b)]
 // CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op: @IntRange.as.Iterate.impl.Next.%DestroyT.binding.as_type.as.Destroy.impl.Op.type (%DestroyT.binding.as_type.as.Destroy.impl.Op.type.c3b) = struct_value () [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.db2)]
 // CHECK:STDOUT:   %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn: <specific function> = specific_function %DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl.Op(%facet_value) [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn)]
-// CHECK:STDOUT:   %Optional.None.type: type = fn_type @Optional.None, @Optional(%Copy.facet.loc11_75.1) [symbolic = %Optional.None.type (constants.%Optional.None.type.66e)]
-// CHECK:STDOUT:   %Optional.None: @IntRange.as.Iterate.impl.Next.%Optional.None.type (%Optional.None.type.66e) = struct_value () [symbolic = %Optional.None (constants.%Optional.None.016)]
-// CHECK:STDOUT:   %Optional.None.specific_fn.loc17_42.2: <specific function> = specific_function %Optional.None, @Optional.None(%Copy.facet.loc11_75.1) [symbolic = %Optional.None.specific_fn.loc17_42.2 (constants.%Optional.None.specific_fn)]
+// CHECK:STDOUT:   %Optional.None.type: type = fn_type @Optional.None, @Optional(%OptionalStorage.facet.loc11_75.1) [symbolic = %Optional.None.type (constants.%Optional.None.type.6c4)]
+// CHECK:STDOUT:   %Optional.None: @IntRange.as.Iterate.impl.Next.%Optional.None.type (%Optional.None.type.6c4) = struct_value () [symbolic = %Optional.None (constants.%Optional.None.f70)]
+// CHECK:STDOUT:   %Optional.None.specific_fn.loc17_42.2: <specific function> = specific_function %Optional.None, @Optional.None(%OptionalStorage.facet.loc11_75.1) [symbolic = %Optional.None.specific_fn.loc17_42.2 (constants.%Optional.None.specific_fn)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn(%self.param: @IntRange.as.Iterate.impl.Next.%IntRange (%IntRange.349), %cursor.param: @IntRange.as.Iterate.impl.Next.%ptr.loc11_44.1 (%ptr.784)) -> %return.param: @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) {
+// CHECK:STDOUT:   fn(%self.param: @IntRange.as.Iterate.impl.Next.%IntRange (%IntRange.349), %cursor.param: @IntRange.as.Iterate.impl.Next.%ptr.loc11_44.1 (%ptr.784)) -> %return.param: @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) {
 // CHECK:STDOUT:   !entry:
 // CHECK:STDOUT:     name_binding_decl {
 // CHECK:STDOUT:       %value.patt: @IntRange.as.Iterate.impl.Next.%pattern_type.loc12 (%pattern_type.8963eb.1) = binding_pattern value [concrete]
@@ -649,20 +654,20 @@ fn Read() {
 // CHECK:STDOUT:     %Int.ref.loc15: %Int.type = name_ref Int, imports.%Core.Int [concrete = constants.%Int.generic]
 // CHECK:STDOUT:     %N.ref.loc15: Core.IntLiteral = name_ref N, @IntRange.%N.loc4_16.2 [symbolic = %N (constants.%N)]
 // CHECK:STDOUT:     %Int.loc15: type = class_type @Int, @Int(constants.%N) [symbolic = %Int.loc11_43.1 (constants.%Int.49d0e6.1)]
-// CHECK:STDOUT:     %Copy.facet.loc15_41: %Copy.type = facet_value %Int.loc15, (constants.%Copy.lookup_impl_witness.ccc) [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %.loc15_41: %Copy.type = converted %Int.loc15, %Copy.facet.loc15_41 [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %Optional.loc15: type = class_type @Optional, @Optional(constants.%Copy.facet.cd7) [symbolic = %Optional.loc11_75.1 (constants.%Optional.671)]
-// CHECK:STDOUT:     %.loc15_42: @IntRange.as.Iterate.impl.Next.%Optional.Some.type (%Optional.Some.type.20f) = specific_constant imports.%Core.import_ref.9103, @Optional(constants.%Copy.facet.cd7) [symbolic = %Optional.Some (constants.%Optional.Some.dff)]
-// CHECK:STDOUT:     %Some.ref: @IntRange.as.Iterate.impl.Next.%Optional.Some.type (%Optional.Some.type.20f) = name_ref Some, %.loc15_42 [symbolic = %Optional.Some (constants.%Optional.Some.dff)]
+// CHECK:STDOUT:     %OptionalStorage.facet.loc15_41: %OptionalStorage.type = facet_value %Int.loc15, (constants.%OptionalStorage.lookup_impl_witness.664) [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %.loc15_41: %OptionalStorage.type = converted %Int.loc15, %OptionalStorage.facet.loc15_41 [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %Optional.loc15: type = class_type @Optional, @Optional(constants.%OptionalStorage.facet.169) [symbolic = %Optional.loc11_75.1 (constants.%Optional.37d)]
+// CHECK:STDOUT:     %.loc15_42: @IntRange.as.Iterate.impl.Next.%Optional.Some.type (%Optional.Some.type.879) = specific_constant imports.%Core.import_ref.ea3, @Optional(constants.%OptionalStorage.facet.169) [symbolic = %Optional.Some (constants.%Optional.Some.d45)]
+// CHECK:STDOUT:     %Some.ref: @IntRange.as.Iterate.impl.Next.%Optional.Some.type (%Optional.Some.type.879) = name_ref Some, %.loc15_42 [symbolic = %Optional.Some (constants.%Optional.Some.d45)]
 // CHECK:STDOUT:     %value.ref.loc15: ref @IntRange.as.Iterate.impl.Next.%Int.loc11_43.1 (%Int.49d0e6.1) = name_ref value, %value
-// CHECK:STDOUT:     %Copy.facet.loc15_53.1: %Copy.type = facet_value constants.%Int.49d0e6.1, (constants.%Copy.lookup_impl_witness.ccc) [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %.loc15_53.1: %Copy.type = converted constants.%Int.49d0e6.1, %Copy.facet.loc15_53.1 [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %Copy.facet.loc15_53.2: %Copy.type = facet_value constants.%Int.49d0e6.1, (constants.%Copy.lookup_impl_witness.ccc) [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %.loc15_53.2: %Copy.type = converted constants.%Int.49d0e6.1, %Copy.facet.loc15_53.2 [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %Optional.Some.specific_fn.loc15_42.1: <specific function> = specific_function %Some.ref, @Optional.Some(constants.%Copy.facet.cd7) [symbolic = %Optional.Some.specific_fn.loc15_42.2 (constants.%Optional.Some.specific_fn)]
-// CHECK:STDOUT:     %.loc11_47.1: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) = splice_block %return {}
+// CHECK:STDOUT:     %OptionalStorage.facet.loc15_53.1: %OptionalStorage.type = facet_value constants.%Int.49d0e6.1, (constants.%OptionalStorage.lookup_impl_witness.664) [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %.loc15_53.1: %OptionalStorage.type = converted constants.%Int.49d0e6.1, %OptionalStorage.facet.loc15_53.1 [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %OptionalStorage.facet.loc15_53.2: %OptionalStorage.type = facet_value constants.%Int.49d0e6.1, (constants.%OptionalStorage.lookup_impl_witness.664) [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %.loc15_53.2: %OptionalStorage.type = converted constants.%Int.49d0e6.1, %OptionalStorage.facet.loc15_53.2 [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %Optional.Some.specific_fn.loc15_42.1: <specific function> = specific_function %Some.ref, @Optional.Some(constants.%OptionalStorage.facet.169) [symbolic = %Optional.Some.specific_fn.loc15_42.2 (constants.%Optional.Some.specific_fn)]
+// CHECK:STDOUT:     %.loc11_47.1: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) = splice_block %return {}
 // CHECK:STDOUT:     %.loc15_48: @IntRange.as.Iterate.impl.Next.%Int.loc11_43.1 (%Int.49d0e6.1) = bind_value %value.ref.loc15
-// CHECK:STDOUT:     %Optional.Some.call: init @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) = call %Optional.Some.specific_fn.loc15_42.1(%.loc15_48) to %.loc11_47.1
+// CHECK:STDOUT:     %Optional.Some.call: init @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) = call %Optional.Some.specific_fn.loc15_42.1(%.loc15_48) to %.loc11_47.1
 // CHECK:STDOUT:     %impl.elem0.loc12_7.1: @IntRange.as.Iterate.impl.Next.%.loc12_7 (%.944) = impl_witness_access constants.%Destroy.impl_witness.47b, element0 [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.db2)]
 // CHECK:STDOUT:     %bound_method.loc12_7.1: <bound method> = bound_method %value.var, %impl.elem0.loc12_7.1
 // CHECK:STDOUT:     %specific_fn.loc12_7.1: <specific function> = specific_function %impl.elem0.loc12_7.1, @DestroyT.binding.as_type.as.Destroy.impl.Op(constants.%facet_value) [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn)]
@@ -678,14 +683,14 @@ fn Read() {
 // CHECK:STDOUT:     %Int.ref.loc17: %Int.type = name_ref Int, imports.%Core.Int [concrete = constants.%Int.generic]
 // CHECK:STDOUT:     %N.ref.loc17: Core.IntLiteral = name_ref N, @IntRange.%N.loc4_16.2 [symbolic = %N (constants.%N)]
 // CHECK:STDOUT:     %Int.loc17: type = class_type @Int, @Int(constants.%N) [symbolic = %Int.loc11_43.1 (constants.%Int.49d0e6.1)]
-// CHECK:STDOUT:     %Copy.facet.loc17: %Copy.type = facet_value %Int.loc17, (constants.%Copy.lookup_impl_witness.ccc) [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %.loc17_41: %Copy.type = converted %Int.loc17, %Copy.facet.loc17 [symbolic = %Copy.facet.loc11_75.1 (constants.%Copy.facet.cd7)]
-// CHECK:STDOUT:     %Optional.loc17: type = class_type @Optional, @Optional(constants.%Copy.facet.cd7) [symbolic = %Optional.loc11_75.1 (constants.%Optional.671)]
-// CHECK:STDOUT:     %.loc17_42: @IntRange.as.Iterate.impl.Next.%Optional.None.type (%Optional.None.type.66e) = specific_constant imports.%Core.import_ref.725b, @Optional(constants.%Copy.facet.cd7) [symbolic = %Optional.None (constants.%Optional.None.016)]
-// CHECK:STDOUT:     %None.ref: @IntRange.as.Iterate.impl.Next.%Optional.None.type (%Optional.None.type.66e) = name_ref None, %.loc17_42 [symbolic = %Optional.None (constants.%Optional.None.016)]
-// CHECK:STDOUT:     %Optional.None.specific_fn.loc17_42.1: <specific function> = specific_function %None.ref, @Optional.None(constants.%Copy.facet.cd7) [symbolic = %Optional.None.specific_fn.loc17_42.2 (constants.%Optional.None.specific_fn)]
-// CHECK:STDOUT:     %.loc11_47.2: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) = splice_block %return {}
-// CHECK:STDOUT:     %Optional.None.call: init @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.671) = call %Optional.None.specific_fn.loc17_42.1() to %.loc11_47.2
+// CHECK:STDOUT:     %OptionalStorage.facet.loc17: %OptionalStorage.type = facet_value %Int.loc17, (constants.%OptionalStorage.lookup_impl_witness.664) [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %.loc17_41: %OptionalStorage.type = converted %Int.loc17, %OptionalStorage.facet.loc17 [symbolic = %OptionalStorage.facet.loc11_75.1 (constants.%OptionalStorage.facet.169)]
+// CHECK:STDOUT:     %Optional.loc17: type = class_type @Optional, @Optional(constants.%OptionalStorage.facet.169) [symbolic = %Optional.loc11_75.1 (constants.%Optional.37d)]
+// CHECK:STDOUT:     %.loc17_42: @IntRange.as.Iterate.impl.Next.%Optional.None.type (%Optional.None.type.6c4) = specific_constant imports.%Core.import_ref.7dc, @Optional(constants.%OptionalStorage.facet.169) [symbolic = %Optional.None (constants.%Optional.None.f70)]
+// CHECK:STDOUT:     %None.ref: @IntRange.as.Iterate.impl.Next.%Optional.None.type (%Optional.None.type.6c4) = name_ref None, %.loc17_42 [symbolic = %Optional.None (constants.%Optional.None.f70)]
+// CHECK:STDOUT:     %Optional.None.specific_fn.loc17_42.1: <specific function> = specific_function %None.ref, @Optional.None(constants.%OptionalStorage.facet.169) [symbolic = %Optional.None.specific_fn.loc17_42.2 (constants.%Optional.None.specific_fn)]
+// CHECK:STDOUT:     %.loc11_47.2: ref @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) = splice_block %return {}
+// CHECK:STDOUT:     %Optional.None.call: init @IntRange.as.Iterate.impl.Next.%Optional.loc11_75.1 (%Optional.37d) = call %Optional.None.specific_fn.loc17_42.1() to %.loc11_47.2
 // CHECK:STDOUT:     %impl.elem0.loc12_7.2: @IntRange.as.Iterate.impl.Next.%.loc12_7 (%.944) = impl_witness_access constants.%Destroy.impl_witness.47b, element0 [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.db2)]
 // CHECK:STDOUT:     %bound_method.loc12_7.3: <bound method> = bound_method %value.var, %impl.elem0.loc12_7.2
 // CHECK:STDOUT:     %specific_fn.loc12_7.2: <specific function> = specific_function %impl.elem0.loc12_7.2, @DestroyT.binding.as_type.as.Destroy.impl.Op(constants.%facet_value) [symbolic = %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn (constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn)]
@@ -772,10 +777,10 @@ fn Read() {
 // CHECK:STDOUT:   %Int.loc11_43.1 => constants.%Int.49d0e6.1
 // CHECK:STDOUT:   %ptr.loc11_44.1 => constants.%ptr.784
 // CHECK:STDOUT:   %pattern_type.loc11_25 => constants.%pattern_type.4dc
-// CHECK:STDOUT:   %Copy.lookup_impl_witness => constants.%Copy.lookup_impl_witness.ccc
-// CHECK:STDOUT:   %Copy.facet.loc11_75.1 => constants.%Copy.facet.cd7
-// CHECK:STDOUT:   %Optional.loc11_75.1 => constants.%Optional.671
-// CHECK:STDOUT:   %pattern_type.loc11_47 => constants.%pattern_type.ff2
+// CHECK:STDOUT:   %OptionalStorage.lookup_impl_witness => constants.%OptionalStorage.lookup_impl_witness.664
+// CHECK:STDOUT:   %OptionalStorage.facet.loc11_75.1 => constants.%OptionalStorage.facet.169
+// CHECK:STDOUT:   %Optional.loc11_75.1 => constants.%Optional.37d
+// CHECK:STDOUT:   %pattern_type.loc11_47 => constants.%pattern_type.485
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @IntRange(constants.%int_32) {

+ 81 - 48
toolchain/lower/testdata/array/iterate.carbon

@@ -30,7 +30,7 @@ fn F() {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %.loc16_43.3.temp = alloca [6 x i32], align 4, !dbg !7
 // CHECK:STDOUT:   %var = alloca i32, align 4, !dbg !8
-// CHECK:STDOUT:   %.loc17_19.1.temp = alloca { i1, i32 }, align 8, !dbg !8
+// CHECK:STDOUT:   %.loc17_19.1.temp = alloca { i32, i1 }, align 8, !dbg !8
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc16_43.3.temp), !dbg !7
 // CHECK:STDOUT:   %.loc16_43.4.array.index = getelementptr inbounds [6 x i32], ptr %.loc16_43.3.temp, i32 0, i64 0, !dbg !7
 // CHECK:STDOUT:   %.loc16_43.7.array.index = getelementptr inbounds [6 x i32], ptr %.loc16_43.3.temp, i32 0, i64 1, !dbg !7
@@ -47,11 +47,11 @@ fn F() {
 // CHECK:STDOUT: for.next:                                         ; preds = %for.body, %entry
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc17_19.1.temp), !dbg !8
 // CHECK:STDOUT:   call void @"_CNext.25e6cb2a64776520:Iterate.Core.c71fd8c166af9f17"(ptr %.loc17_19.1.temp, ptr %.loc16_43.3.temp, ptr %var), !dbg !8
-// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.de631560529e9861(ptr %.loc17_19.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.30bf744b66445e68(ptr %.loc17_19.1.temp), !dbg !8
 // CHECK:STDOUT:   br i1 %Optional.HasValue.call, label %for.body, label %for.done, !dbg !8
 // CHECK:STDOUT:
 // CHECK:STDOUT: for.body:                                         ; preds = %for.next
-// CHECK:STDOUT:   %Optional.Get.call = call i32 @_CGet.Optional.Core.de631560529e9861(ptr %.loc17_19.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.Get.call = call i32 @_CGet.Optional.Core.30bf744b66445e68(ptr %.loc17_19.1.temp), !dbg !8
 // CHECK:STDOUT:   call void @_CG.Main(i32 %Optional.Get.call), !dbg !9
 // CHECK:STDOUT:   br label %for.next, !dbg !10
 // CHECK:STDOUT:
@@ -69,7 +69,7 @@ fn F() {
 // CHECK:STDOUT:   ret i32 0, !dbg !14
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_CNext.25e6cb2a64776520:Iterate.Core.c71fd8c166af9f17"(ptr sret({ i1, i32 }) %return, ptr %self, ptr %cursor) !dbg !15 {
+// CHECK:STDOUT: define linkonce_odr void @"_CNext.25e6cb2a64776520:Iterate.Core.c71fd8c166af9f17"(ptr sret({ i32, i1 }) %return, ptr %self, ptr %cursor) !dbg !15 {
 // CHECK:STDOUT:   %1 = load i32, ptr %cursor, align 4, !dbg !16
 // CHECK:STDOUT:   %2 = icmp slt i32 %1, 6, !dbg !16
 // CHECK:STDOUT:   br i1 %2, label %3, label %7, !dbg !17
@@ -80,24 +80,21 @@ fn F() {
 // CHECK:STDOUT:   %5 = sub i32 %4, 1, !dbg !19
 // CHECK:STDOUT:   %array.index = getelementptr inbounds [6 x i32], ptr %self, i32 0, i32 %5, !dbg !20
 // CHECK:STDOUT:   %6 = load i32, ptr %array.index, align 4, !dbg !20
-// CHECK:STDOUT:   call void @_CSome.Optional.Core.de631560529e9861(ptr %return, i32 %6), !dbg !21
+// CHECK:STDOUT:   call void @_CSome.Optional.Core.30bf744b66445e68(ptr %return, i32 %6), !dbg !21
 // CHECK:STDOUT:   ret void, !dbg !22
 // CHECK:STDOUT:
 // CHECK:STDOUT: 7:                                                ; preds = %0
-// CHECK:STDOUT:   call void @_CNone.Optional.Core.de631560529e9861(ptr %return), !dbg !23
+// CHECK:STDOUT:   call void @_CNone.Optional.Core.30bf744b66445e68(ptr %return), !dbg !23
 // CHECK:STDOUT:   ret void, !dbg !24
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.de631560529e9861(ptr %self) !dbg !25 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %self, i32 0, i32 0, !dbg !27
-// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !27
-// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !27
-// CHECK:STDOUT:   ret i1 %2, !dbg !28
+// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.30bf744b66445e68(ptr %self) !dbg !25 {
+// CHECK:STDOUT:   %1 = call i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %self), !dbg !27
+// CHECK:STDOUT:   ret i1 %1, !dbg !28
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i32 @_CGet.Optional.Core.de631560529e9861(ptr %self) !dbg !29 {
-// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i1, i32 }, ptr %self, i32 0, i32 1, !dbg !30
-// CHECK:STDOUT:   %1 = load i32, ptr %value, align 4, !dbg !30
+// CHECK:STDOUT: define linkonce_odr i32 @_CGet.Optional.Core.30bf744b66445e68(ptr %self) !dbg !29 {
+// CHECK:STDOUT:   %1 = call i32 @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %self), !dbg !30
 // CHECK:STDOUT:   ret i32 %1, !dbg !31
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -106,30 +103,53 @@ fn F() {
 // CHECK:STDOUT:   ret void, !dbg !35
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.de631560529e9861(ptr sret({ i1, i32 }) %return, i32 %value) !dbg !36 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 0, !dbg !37
-// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 1, !dbg !37
-// CHECK:STDOUT:   store i32 %value, ptr %value1, align 4, !dbg !37
-// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !37
+// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.30bf744b66445e68(ptr sret({ i32, i1 }) %return, i32 %value) !dbg !36 {
+// CHECK:STDOUT:   call void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return, i32 %value), !dbg !37
 // CHECK:STDOUT:   ret void, !dbg !38
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.de631560529e9861(ptr sret({ i1, i32 }) %return) !dbg !39 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 0, !dbg !40
-// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !40
+// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.30bf744b66445e68(ptr sret({ i32, i1 }) %return) !dbg !39 {
+// CHECK:STDOUT:   call void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return), !dbg !40
 // CHECK:STDOUT:   ret void, !dbg !41
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_COp:thunk.Int.Core:AddAssignWith.Core.406b182375ada471"(ptr %self, i32 %other) !dbg !42 {
-// CHECK:STDOUT:   %1 = call i32 @"_CConvert.549023863aee3dc2:ImplicitAs.Core.b502b6d26692ae95"(i32 %other), !dbg !43
-// CHECK:STDOUT:   %2 = load i32, ptr %self, align 4, !dbg !44
-// CHECK:STDOUT:   %3 = add i32 %2, %1, !dbg !44
-// CHECK:STDOUT:   store i32 %3, ptr %self, align 4, !dbg !44
-// CHECK:STDOUT:   ret void, !dbg !44
+// CHECK:STDOUT: define linkonce_odr i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %value) !dbg !42 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %value, i32 0, i32 1, !dbg !43
+// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !43
+// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !43
+// CHECK:STDOUT:   ret i1 %2, !dbg !44
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i32 @"_CConvert.549023863aee3dc2:ImplicitAs.Core.b502b6d26692ae95"(i32 %self) !dbg !45 {
-// CHECK:STDOUT:   ret i32 %self, !dbg !47
+// CHECK:STDOUT: define linkonce_odr i32 @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %value) !dbg !45 {
+// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { i32, i1 }, ptr %value, i32 0, i32 0, !dbg !46
+// CHECK:STDOUT:   %1 = load i32, ptr %value1, align 4, !dbg !46
+// CHECK:STDOUT:   ret i32 %1, !dbg !47
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_COp:thunk.Int.Core:AddAssignWith.Core.406b182375ada471"(ptr %self, i32 %other) !dbg !48 {
+// CHECK:STDOUT:   %1 = call i32 @"_CConvert.549023863aee3dc2:ImplicitAs.Core.b502b6d26692ae95"(i32 %other), !dbg !49
+// CHECK:STDOUT:   %2 = load i32, ptr %self, align 4, !dbg !50
+// CHECK:STDOUT:   %3 = add i32 %2, %1, !dbg !50
+// CHECK:STDOUT:   store i32 %3, ptr %self, align 4, !dbg !50
+// CHECK:STDOUT:   ret void, !dbg !50
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return, i32 %self) !dbg !51 {
+// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 0, !dbg !52
+// CHECK:STDOUT:   store i32 %self, ptr %value, align 4, !dbg !52
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !53
+// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !53
+// CHECK:STDOUT:   ret void, !dbg !54
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return) !dbg !55 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !56
+// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !56
+// CHECK:STDOUT:   ret void, !dbg !57
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr i32 @"_CConvert.549023863aee3dc2:ImplicitAs.Core.b502b6d26692ae95"(i32 %self) !dbg !58 {
+// CHECK:STDOUT:   ret i32 %self, !dbg !60
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; uselistorder directives
@@ -166,26 +186,39 @@ fn F() {
 // CHECK:STDOUT: !22 = !DILocation(line: 27, column: 7, scope: !15)
 // CHECK:STDOUT: !23 = !DILocation(line: 29, column: 14, scope: !15)
 // CHECK:STDOUT: !24 = !DILocation(line: 29, column: 7, scope: !15)
-// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.de631560529e9861", scope: null, file: !26, line: 30, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.30bf744b66445e68", scope: null, file: !26, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !26 = !DIFile(filename: "{{.*}}/prelude/types/optional.carbon", directory: "")
-// CHECK:STDOUT: !27 = !DILocation(line: 30, column: 46, scope: !25)
-// CHECK:STDOUT: !28 = !DILocation(line: 30, column: 39, scope: !25)
-// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.de631560529e9861", scope: null, file: !26, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !30 = !DILocation(line: 31, column: 38, scope: !29)
-// CHECK:STDOUT: !31 = !DILocation(line: 31, column: 31, scope: !29)
+// CHECK:STDOUT: !27 = !DILocation(line: 32, column: 12, scope: !25)
+// CHECK:STDOUT: !28 = !DILocation(line: 32, column: 5, scope: !25)
+// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.30bf744b66445e68", scope: null, file: !26, line: 34, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !30 = !DILocation(line: 35, column: 12, scope: !29)
+// CHECK:STDOUT: !31 = !DILocation(line: 35, column: 5, scope: !29)
 // CHECK:STDOUT: !32 = distinct !DISubprogram(name: "Op", linkageName: "_COp.Int.Core:Inc.Core.be1e879c1ad406d8", scope: null, file: !33, line: 339, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !33 = !DIFile(filename: "{{.*}}/prelude/types/int.carbon", directory: "")
 // CHECK:STDOUT: !34 = !DILocation(line: 341, column: 5, scope: !32)
 // CHECK:STDOUT: !35 = !DILocation(line: 339, column: 3, scope: !32)
-// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.de631560529e9861", scope: null, file: !26, line: 26, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !37 = !DILocation(line: 27, column: 12, scope: !36)
-// CHECK:STDOUT: !38 = !DILocation(line: 27, column: 5, scope: !36)
-// CHECK:STDOUT: !39 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.de631560529e9861", scope: null, file: !26, line: 20, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !40 = !DILocation(line: 22, column: 5, scope: !39)
-// CHECK:STDOUT: !41 = !DILocation(line: 23, column: 5, scope: !39)
-// CHECK:STDOUT: !42 = distinct !DISubprogram(name: "Op", linkageName: "_COp:thunk.Int.Core:AddAssignWith.Core.406b182375ada471", scope: null, file: !33, line: 275, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !43 = !DILocation(line: 4294967295, scope: !42)
-// CHECK:STDOUT: !44 = !DILocation(line: 275, column: 3, scope: !42)
-// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.549023863aee3dc2:ImplicitAs.Core.b502b6d26692ae95", scope: null, file: !46, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !46 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
-// CHECK:STDOUT: !47 = !DILocation(line: 24, column: 38, scope: !45)
+// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.30bf744b66445e68", scope: null, file: !26, line: 28, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !37 = !DILocation(line: 29, column: 12, scope: !36)
+// CHECK:STDOUT: !38 = !DILocation(line: 29, column: 5, scope: !36)
+// CHECK:STDOUT: !39 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.30bf744b66445e68", scope: null, file: !26, line: 25, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !40 = !DILocation(line: 26, column: 12, scope: !39)
+// CHECK:STDOUT: !41 = !DILocation(line: 26, column: 5, scope: !39)
+// CHECK:STDOUT: !42 = distinct !DISubprogram(name: "Has", linkageName: "_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !26, line: 73, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !43 = !DILocation(line: 74, column: 12, scope: !42)
+// CHECK:STDOUT: !44 = !DILocation(line: 74, column: 5, scope: !42)
+// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !26, line: 76, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !46 = !DILocation(line: 77, column: 12, scope: !45)
+// CHECK:STDOUT: !47 = !DILocation(line: 77, column: 5, scope: !45)
+// CHECK:STDOUT: !48 = distinct !DISubprogram(name: "Op", linkageName: "_COp:thunk.Int.Core:AddAssignWith.Core.406b182375ada471", scope: null, file: !33, line: 275, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !49 = !DILocation(line: 4294967295, scope: !48)
+// CHECK:STDOUT: !50 = !DILocation(line: 275, column: 3, scope: !48)
+// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !26, line: 65, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !52 = !DILocation(line: 69, column: 5, scope: !51)
+// CHECK:STDOUT: !53 = !DILocation(line: 70, column: 5, scope: !51)
+// CHECK:STDOUT: !54 = !DILocation(line: 71, column: 5, scope: !51)
+// CHECK:STDOUT: !55 = distinct !DISubprogram(name: "None", linkageName: "_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !26, line: 60, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !56 = !DILocation(line: 62, column: 5, scope: !55)
+// CHECK:STDOUT: !57 = !DILocation(line: 63, column: 5, scope: !55)
+// CHECK:STDOUT: !58 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.549023863aee3dc2:ImplicitAs.Core.b502b6d26692ae95", scope: null, file: !59, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !59 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
+// CHECK:STDOUT: !60 = !DILocation(line: 24, column: 38, scope: !58)

+ 64 - 40
toolchain/lower/testdata/for/bindings.carbon

@@ -42,7 +42,7 @@ fn For() {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %r.var = alloca {}, align 8, !dbg !7
 // CHECK:STDOUT:   %var = alloca {}, align 8, !dbg !8
-// CHECK:STDOUT:   %.loc29_33.1.temp = alloca { i1, { i32, i32 } }, align 8, !dbg !8
+// CHECK:STDOUT:   %.loc29_33.1.temp = alloca { { i32, i32 }, i1 }, align 8, !dbg !8
 // CHECK:STDOUT:   %n.var = alloca i32, align 4, !dbg !9
 // CHECK:STDOUT:   %.loc29_33.8.temp = alloca { i32, i32 }, align 8, !dbg !8
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %r.var), !dbg !7
@@ -54,13 +54,13 @@ fn For() {
 // CHECK:STDOUT: for.next:                                         ; preds = %for.body, %entry
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc29_33.1.temp), !dbg !8
 // CHECK:STDOUT:   call void @"_CNext.EmptyRange.Main:Iterate.Core.54ec9394d5df5464"(ptr %.loc29_33.1.temp, ptr %r.var, ptr %var), !dbg !8
-// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.54ec9394d5df5464(ptr %.loc29_33.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.c1549343e56492e8(ptr %.loc29_33.1.temp), !dbg !8
 // CHECK:STDOUT:   br i1 %Optional.HasValue.call, label %for.body, label %for.done, !dbg !8
 // CHECK:STDOUT:
 // CHECK:STDOUT: for.body:                                         ; preds = %for.next
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %n.var), !dbg !9
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc29_33.8.temp), !dbg !8
-// CHECK:STDOUT:   call void @_CGet.Optional.Core.54ec9394d5df5464(ptr %.loc29_33.8.temp, ptr %.loc29_33.1.temp), !dbg !8
+// CHECK:STDOUT:   call void @_CGet.Optional.Core.c1549343e56492e8(ptr %.loc29_33.8.temp, ptr %.loc29_33.1.temp), !dbg !8
 // CHECK:STDOUT:   %tuple.elem0.tuple.elem = getelementptr inbounds nuw { i32, i32 }, ptr %.loc29_33.8.temp, i32 0, i32 0, !dbg !8
 // CHECK:STDOUT:   %tuple.elem1.tuple.elem = getelementptr inbounds nuw { i32, i32 }, ptr %.loc29_33.8.temp, i32 0, i32 1, !dbg !8
 // CHECK:STDOUT:   %.loc29_33.11 = load i32, ptr %tuple.elem0.tuple.elem, align 4, !dbg !8
@@ -84,43 +84,58 @@ fn For() {
 // CHECK:STDOUT:   ret void, !dbg !14
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_CNext.EmptyRange.Main:Iterate.Core.54ec9394d5df5464"(ptr sret({ i1, { i32, i32 } }) %return, ptr %self, ptr %cursor) !dbg !15 {
+// CHECK:STDOUT: define linkonce_odr void @"_CNext.EmptyRange.Main:Iterate.Core.54ec9394d5df5464"(ptr sret({ { i32, i32 }, i1 }) %return, ptr %self, ptr %cursor) !dbg !15 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   call void @_CNone.Optional.Core.54ec9394d5df5464(ptr %return), !dbg !16
+// CHECK:STDOUT:   call void @_CNone.Optional.Core.c1549343e56492e8(ptr %return), !dbg !16
 // CHECK:STDOUT:   ret void, !dbg !17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.54ec9394d5df5464(ptr %self) !dbg !18 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, { i32, i32 } }, ptr %self, i32 0, i32 0, !dbg !20
-// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !20
-// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !20
-// CHECK:STDOUT:   ret i1 %2, !dbg !21
+// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.c1549343e56492e8(ptr %self) !dbg !18 {
+// CHECK:STDOUT:   %1 = call i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464"(ptr %self), !dbg !20
+// CHECK:STDOUT:   ret i1 %1, !dbg !21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CGet.Optional.Core.54ec9394d5df5464(ptr sret({ i32, i32 }) %return, ptr %self) !dbg !22 {
-// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i1, { i32, i32 } }, ptr %self, i32 0, i32 1, !dbg !23
-// CHECK:STDOUT:   call void @"_COp.0f13b78cd2788a9b:Copy.Core.58c6957df82926a9"(ptr %return, ptr %value), !dbg !23
+// CHECK:STDOUT: define linkonce_odr void @_CGet.Optional.Core.c1549343e56492e8(ptr sret({ i32, i32 }) %return, ptr %self) !dbg !22 {
+// CHECK:STDOUT:   call void @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464"(ptr %return, ptr %self), !dbg !23
 // CHECK:STDOUT:   ret void, !dbg !24
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.54ec9394d5df5464(ptr sret({ i1, { i32, i32 } }) %return) !dbg !25 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, { i32, i32 } }, ptr %return, i32 0, i32 0, !dbg !26
-// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !26
+// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.c1549343e56492e8(ptr sret({ { i32, i32 }, i1 }) %return) !dbg !25 {
+// CHECK:STDOUT:   call void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464"(ptr %return), !dbg !26
 // CHECK:STDOUT:   ret void, !dbg !27
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_COp.0f13b78cd2788a9b:Copy.Core.58c6957df82926a9"(ptr sret({ i32, i32 }) %return, ptr %self) !dbg !28 {
-// CHECK:STDOUT:   %tuple.elem = getelementptr inbounds nuw { i32, i32 }, ptr %self, i32 0, i32 0, !dbg !30
-// CHECK:STDOUT:   %tuple.elem.load = load i32, ptr %tuple.elem, align 4, !dbg !30
-// CHECK:STDOUT:   %tuple.elem1 = getelementptr inbounds nuw { i32, i32 }, ptr %return, i32 0, i32 0, !dbg !31
-// CHECK:STDOUT:   %tuple.elem2 = getelementptr inbounds nuw { i32, i32 }, ptr %self, i32 0, i32 1, !dbg !32
-// CHECK:STDOUT:   %tuple.elem.load3 = load i32, ptr %tuple.elem2, align 4, !dbg !32
-// CHECK:STDOUT:   %tuple.elem4 = getelementptr inbounds nuw { i32, i32 }, ptr %return, i32 0, i32 1, !dbg !31
-// CHECK:STDOUT:   store i32 %tuple.elem.load, ptr %tuple.elem1, align 4, !dbg !31
-// CHECK:STDOUT:   store i32 %tuple.elem.load3, ptr %tuple.elem4, align 4, !dbg !31
+// CHECK:STDOUT: define linkonce_odr i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464"(ptr %value) !dbg !28 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { { i32, i32 }, i1 }, ptr %value, i32 0, i32 1, !dbg !29
+// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !29
+// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !29
+// CHECK:STDOUT:   ret i1 %2, !dbg !30
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464"(ptr sret({ i32, i32 }) %return, ptr %value) !dbg !31 {
+// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { { i32, i32 }, i1 }, ptr %value, i32 0, i32 0, !dbg !32
+// CHECK:STDOUT:   call void @"_COp.0f13b78cd2788a9b:Copy.Core.58c6957df82926a9"(ptr %return, ptr %value1), !dbg !32
 // CHECK:STDOUT:   ret void, !dbg !33
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464"(ptr sret({ { i32, i32 }, i1 }) %return) !dbg !34 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { { i32, i32 }, i1 }, ptr %return, i32 0, i32 1, !dbg !35
+// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !35
+// CHECK:STDOUT:   ret void, !dbg !36
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_COp.0f13b78cd2788a9b:Copy.Core.58c6957df82926a9"(ptr sret({ i32, i32 }) %return, ptr %self) !dbg !37 {
+// CHECK:STDOUT:   %tuple.elem = getelementptr inbounds nuw { i32, i32 }, ptr %self, i32 0, i32 0, !dbg !39
+// CHECK:STDOUT:   %tuple.elem.load = load i32, ptr %tuple.elem, align 4, !dbg !39
+// CHECK:STDOUT:   %tuple.elem1 = getelementptr inbounds nuw { i32, i32 }, ptr %return, i32 0, i32 0, !dbg !40
+// CHECK:STDOUT:   %tuple.elem2 = getelementptr inbounds nuw { i32, i32 }, ptr %self, i32 0, i32 1, !dbg !41
+// CHECK:STDOUT:   %tuple.elem.load3 = load i32, ptr %tuple.elem2, align 4, !dbg !41
+// CHECK:STDOUT:   %tuple.elem4 = getelementptr inbounds nuw { i32, i32 }, ptr %return, i32 0, i32 1, !dbg !40
+// CHECK:STDOUT:   store i32 %tuple.elem.load, ptr %tuple.elem1, align 4, !dbg !40
+// CHECK:STDOUT:   store i32 %tuple.elem.load3, ptr %tuple.elem4, align 4, !dbg !40
+// CHECK:STDOUT:   ret void, !dbg !42
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: ; uselistorder directives
 // CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 4, 3, 2, 1, 0 }
 // CHECK:STDOUT:
@@ -148,19 +163,28 @@ fn For() {
 // CHECK:STDOUT: !15 = distinct !DISubprogram(name: "Next", linkageName: "_CNext.EmptyRange.Main:Iterate.Core.54ec9394d5df5464", scope: null, file: !3, line: 18, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !16 = !DILocation(line: 19, column: 14, scope: !15)
 // CHECK:STDOUT: !17 = !DILocation(line: 19, column: 7, scope: !15)
-// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.54ec9394d5df5464", scope: null, file: !19, line: 30, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.c1549343e56492e8", scope: null, file: !19, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !19 = !DIFile(filename: "{{.*}}/prelude/types/optional.carbon", directory: "")
-// CHECK:STDOUT: !20 = !DILocation(line: 30, column: 46, scope: !18)
-// CHECK:STDOUT: !21 = !DILocation(line: 30, column: 39, scope: !18)
-// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.54ec9394d5df5464", scope: null, file: !19, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !23 = !DILocation(line: 31, column: 38, scope: !22)
-// CHECK:STDOUT: !24 = !DILocation(line: 31, column: 31, scope: !22)
-// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.54ec9394d5df5464", scope: null, file: !19, line: 20, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !26 = !DILocation(line: 22, column: 5, scope: !25)
-// CHECK:STDOUT: !27 = !DILocation(line: 23, column: 5, scope: !25)
-// CHECK:STDOUT: !28 = distinct !DISubprogram(name: "Op", linkageName: "_COp.0f13b78cd2788a9b:Copy.Core.58c6957df82926a9", scope: null, file: !29, line: 58, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !29 = !DIFile(filename: "{{.*}}/prelude/copy.carbon", directory: "")
-// CHECK:STDOUT: !30 = !DILocation(line: 59, column: 13, scope: !28)
-// CHECK:STDOUT: !31 = !DILocation(line: 59, column: 12, scope: !28)
-// CHECK:STDOUT: !32 = !DILocation(line: 59, column: 26, scope: !28)
-// CHECK:STDOUT: !33 = !DILocation(line: 59, column: 5, scope: !28)
+// CHECK:STDOUT: !20 = !DILocation(line: 32, column: 12, scope: !18)
+// CHECK:STDOUT: !21 = !DILocation(line: 32, column: 5, scope: !18)
+// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.c1549343e56492e8", scope: null, file: !19, line: 34, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !23 = !DILocation(line: 35, column: 12, scope: !22)
+// CHECK:STDOUT: !24 = !DILocation(line: 35, column: 5, scope: !22)
+// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.c1549343e56492e8", scope: null, file: !19, line: 25, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !26 = !DILocation(line: 26, column: 12, scope: !25)
+// CHECK:STDOUT: !27 = !DILocation(line: 26, column: 5, scope: !25)
+// CHECK:STDOUT: !28 = distinct !DISubprogram(name: "Has", linkageName: "_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464", scope: null, file: !19, line: 73, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !29 = !DILocation(line: 74, column: 12, scope: !28)
+// CHECK:STDOUT: !30 = !DILocation(line: 74, column: 5, scope: !28)
+// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464", scope: null, file: !19, line: 76, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !32 = !DILocation(line: 77, column: 12, scope: !31)
+// CHECK:STDOUT: !33 = !DILocation(line: 77, column: 5, scope: !31)
+// CHECK:STDOUT: !34 = distinct !DISubprogram(name: "None", linkageName: "_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.54ec9394d5df5464", scope: null, file: !19, line: 60, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !35 = !DILocation(line: 62, column: 5, scope: !34)
+// CHECK:STDOUT: !36 = !DILocation(line: 63, column: 5, scope: !34)
+// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.0f13b78cd2788a9b:Copy.Core.58c6957df82926a9", scope: null, file: !38, line: 58, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !38 = !DIFile(filename: "{{.*}}/prelude/copy.carbon", directory: "")
+// CHECK:STDOUT: !39 = !DILocation(line: 59, column: 13, scope: !37)
+// CHECK:STDOUT: !40 = !DILocation(line: 59, column: 12, scope: !37)
+// CHECK:STDOUT: !41 = !DILocation(line: 59, column: 26, scope: !37)
+// CHECK:STDOUT: !42 = !DILocation(line: 59, column: 5, scope: !37)

+ 81 - 48
toolchain/lower/testdata/for/break_continue.carbon

@@ -37,7 +37,7 @@ fn For() {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %.loc20_32.1.temp = alloca { i32, i32 }, align 8, !dbg !7
 // CHECK:STDOUT:   %var = alloca i32, align 4, !dbg !8
-// CHECK:STDOUT:   %.loc20_33.1.temp = alloca { i1, i32 }, align 8, !dbg !8
+// CHECK:STDOUT:   %.loc20_33.1.temp = alloca { i32, i1 }, align 8, !dbg !8
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc20_32.1.temp), !dbg !7
 // CHECK:STDOUT:   call void @_CRange.Core(ptr %.loc20_32.1.temp, i32 100), !dbg !7
 // CHECK:STDOUT:   %IntRange.as.Iterate.impl.NewCursor.call = call i32 @"_CNewCursor.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr %.loc20_32.1.temp), !dbg !8
@@ -48,11 +48,11 @@ fn For() {
 // CHECK:STDOUT: for.next:                                         ; preds = %if.else.loc22, %if.then.loc22, %entry
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc20_33.1.temp), !dbg !8
 // CHECK:STDOUT:   call void @"_CNext.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr %.loc20_33.1.temp, ptr %.loc20_32.1.temp, ptr %var), !dbg !8
-// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.de631560529e9861(ptr %.loc20_33.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.30bf744b66445e68(ptr %.loc20_33.1.temp), !dbg !8
 // CHECK:STDOUT:   br i1 %Optional.HasValue.call, label %for.body, label %for.done, !dbg !8
 // CHECK:STDOUT:
 // CHECK:STDOUT: for.body:                                         ; preds = %for.next
-// CHECK:STDOUT:   %Optional.Get.call = call i32 @_CGet.Optional.Core.de631560529e9861(ptr %.loc20_33.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.Get.call = call i32 @_CGet.Optional.Core.30bf744b66445e68(ptr %.loc20_33.1.temp), !dbg !8
 // CHECK:STDOUT:   %F.call = call i1 @_CF.Main(), !dbg !9
 // CHECK:STDOUT:   br i1 %F.call, label %if.then.loc21, label %if.else.loc21, !dbg !10
 // CHECK:STDOUT:
@@ -85,7 +85,7 @@ fn For() {
 // CHECK:STDOUT:   ret i32 %1, !dbg !21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_CNext.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr sret({ i1, i32 }) %return, ptr %self, ptr %cursor) !dbg !22 {
+// CHECK:STDOUT: define linkonce_odr void @"_CNext.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr sret({ i32, i1 }) %return, ptr %self, ptr %cursor) !dbg !22 {
 // CHECK:STDOUT:   %1 = alloca i32, align 4, !dbg !23
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %1), !dbg !23
 // CHECK:STDOUT:   %2 = load i32, ptr %cursor, align 4, !dbg !24
@@ -99,24 +99,21 @@ fn For() {
 // CHECK:STDOUT: 6:                                                ; preds = %0
 // CHECK:STDOUT:   call void @"_COp.Int.Core:Inc.Core.be1e879c1ad406d8"(ptr %cursor), !dbg !28
 // CHECK:STDOUT:   %7 = load i32, ptr %1, align 4, !dbg !29
-// CHECK:STDOUT:   call void @_CSome.Optional.Core.de631560529e9861(ptr %return, i32 %7), !dbg !30
+// CHECK:STDOUT:   call void @_CSome.Optional.Core.30bf744b66445e68(ptr %return, i32 %7), !dbg !30
 // CHECK:STDOUT:   ret void, !dbg !31
 // CHECK:STDOUT:
 // CHECK:STDOUT: 8:                                                ; preds = %0
-// CHECK:STDOUT:   call void @_CNone.Optional.Core.de631560529e9861(ptr %return), !dbg !32
+// CHECK:STDOUT:   call void @_CNone.Optional.Core.30bf744b66445e68(ptr %return), !dbg !32
 // CHECK:STDOUT:   ret void, !dbg !33
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.de631560529e9861(ptr %self) !dbg !34 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %self, i32 0, i32 0, !dbg !36
-// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !36
-// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !36
-// CHECK:STDOUT:   ret i1 %2, !dbg !37
+// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.30bf744b66445e68(ptr %self) !dbg !34 {
+// CHECK:STDOUT:   %1 = call i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %self), !dbg !36
+// CHECK:STDOUT:   ret i1 %1, !dbg !37
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i32 @_CGet.Optional.Core.de631560529e9861(ptr %self) !dbg !38 {
-// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i1, i32 }, ptr %self, i32 0, i32 1, !dbg !39
-// CHECK:STDOUT:   %1 = load i32, ptr %value, align 4, !dbg !39
+// CHECK:STDOUT: define linkonce_odr i32 @_CGet.Optional.Core.30bf744b66445e68(ptr %self) !dbg !38 {
+// CHECK:STDOUT:   %1 = call i32 @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %self), !dbg !39
 // CHECK:STDOUT:   ret i32 %1, !dbg !40
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -127,30 +124,53 @@ fn For() {
 // CHECK:STDOUT:   ret void, !dbg !44
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.de631560529e9861(ptr sret({ i1, i32 }) %return, i32 %value) !dbg !45 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 0, !dbg !46
-// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 1, !dbg !46
-// CHECK:STDOUT:   store i32 %value, ptr %value1, align 4, !dbg !46
-// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !46
+// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.30bf744b66445e68(ptr sret({ i32, i1 }) %return, i32 %value) !dbg !45 {
+// CHECK:STDOUT:   call void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return, i32 %value), !dbg !46
 // CHECK:STDOUT:   ret void, !dbg !47
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.de631560529e9861(ptr sret({ i1, i32 }) %return) !dbg !48 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 0, !dbg !49
-// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !49
+// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.30bf744b66445e68(ptr sret({ i32, i1 }) %return) !dbg !48 {
+// CHECK:STDOUT:   call void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return), !dbg !49
 // CHECK:STDOUT:   ret void, !dbg !50
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d"(ptr %self, i32 %other) !dbg !51 {
-// CHECK:STDOUT:   %1 = call i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %other), !dbg !52
-// CHECK:STDOUT:   %2 = load i32, ptr %self, align 4, !dbg !53
-// CHECK:STDOUT:   %3 = add i32 %2, %1, !dbg !53
-// CHECK:STDOUT:   store i32 %3, ptr %self, align 4, !dbg !53
-// CHECK:STDOUT:   ret void, !dbg !53
+// CHECK:STDOUT: define linkonce_odr i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %value) !dbg !51 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %value, i32 0, i32 1, !dbg !52
+// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !52
+// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !52
+// CHECK:STDOUT:   ret i1 %2, !dbg !53
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %self) !dbg !54 {
-// CHECK:STDOUT:   ret i32 %self, !dbg !56
+// CHECK:STDOUT: define linkonce_odr i32 @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %value) !dbg !54 {
+// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { i32, i1 }, ptr %value, i32 0, i32 0, !dbg !55
+// CHECK:STDOUT:   %1 = load i32, ptr %value1, align 4, !dbg !55
+// CHECK:STDOUT:   ret i32 %1, !dbg !56
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d"(ptr %self, i32 %other) !dbg !57 {
+// CHECK:STDOUT:   %1 = call i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %other), !dbg !58
+// CHECK:STDOUT:   %2 = load i32, ptr %self, align 4, !dbg !59
+// CHECK:STDOUT:   %3 = add i32 %2, %1, !dbg !59
+// CHECK:STDOUT:   store i32 %3, ptr %self, align 4, !dbg !59
+// CHECK:STDOUT:   ret void, !dbg !59
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return, i32 %self) !dbg !60 {
+// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 0, !dbg !61
+// CHECK:STDOUT:   store i32 %self, ptr %value, align 4, !dbg !61
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !62
+// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !62
+// CHECK:STDOUT:   ret void, !dbg !63
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return) !dbg !64 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !65
+// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !65
+// CHECK:STDOUT:   ret void, !dbg !66
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %self) !dbg !67 {
+// CHECK:STDOUT:   ret i32 %self, !dbg !69
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; uselistorder directives
@@ -195,26 +215,39 @@ fn For() {
 // CHECK:STDOUT: !31 = !DILocation(line: 30, column: 9, scope: !22)
 // CHECK:STDOUT: !32 = !DILocation(line: 32, column: 16, scope: !22)
 // CHECK:STDOUT: !33 = !DILocation(line: 32, column: 9, scope: !22)
-// CHECK:STDOUT: !34 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.de631560529e9861", scope: null, file: !35, line: 30, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !34 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.30bf744b66445e68", scope: null, file: !35, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !35 = !DIFile(filename: "{{.*}}/prelude/types/optional.carbon", directory: "")
-// CHECK:STDOUT: !36 = !DILocation(line: 30, column: 46, scope: !34)
-// CHECK:STDOUT: !37 = !DILocation(line: 30, column: 39, scope: !34)
-// CHECK:STDOUT: !38 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.de631560529e9861", scope: null, file: !35, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !39 = !DILocation(line: 31, column: 38, scope: !38)
-// CHECK:STDOUT: !40 = !DILocation(line: 31, column: 31, scope: !38)
+// CHECK:STDOUT: !36 = !DILocation(line: 32, column: 12, scope: !34)
+// CHECK:STDOUT: !37 = !DILocation(line: 32, column: 5, scope: !34)
+// CHECK:STDOUT: !38 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.30bf744b66445e68", scope: null, file: !35, line: 34, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !39 = !DILocation(line: 35, column: 12, scope: !38)
+// CHECK:STDOUT: !40 = !DILocation(line: 35, column: 5, scope: !38)
 // CHECK:STDOUT: !41 = distinct !DISubprogram(name: "Op", linkageName: "_COp.Int.Core:Inc.Core.be1e879c1ad406d8", scope: null, file: !42, line: 339, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !42 = !DIFile(filename: "{{.*}}/prelude/types/int.carbon", directory: "")
 // CHECK:STDOUT: !43 = !DILocation(line: 341, column: 5, scope: !41)
 // CHECK:STDOUT: !44 = !DILocation(line: 339, column: 3, scope: !41)
-// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.de631560529e9861", scope: null, file: !35, line: 26, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !46 = !DILocation(line: 27, column: 12, scope: !45)
-// CHECK:STDOUT: !47 = !DILocation(line: 27, column: 5, scope: !45)
-// CHECK:STDOUT: !48 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.de631560529e9861", scope: null, file: !35, line: 20, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !49 = !DILocation(line: 22, column: 5, scope: !48)
-// CHECK:STDOUT: !50 = !DILocation(line: 23, column: 5, scope: !48)
-// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Op", linkageName: "_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d", scope: null, file: !42, line: 275, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !52 = !DILocation(line: 4294967295, scope: !51)
-// CHECK:STDOUT: !53 = !DILocation(line: 275, column: 3, scope: !51)
-// CHECK:STDOUT: !54 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861", scope: null, file: !55, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !55 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
-// CHECK:STDOUT: !56 = !DILocation(line: 24, column: 38, scope: !54)
+// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.30bf744b66445e68", scope: null, file: !35, line: 28, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !46 = !DILocation(line: 29, column: 12, scope: !45)
+// CHECK:STDOUT: !47 = !DILocation(line: 29, column: 5, scope: !45)
+// CHECK:STDOUT: !48 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.30bf744b66445e68", scope: null, file: !35, line: 25, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !49 = !DILocation(line: 26, column: 12, scope: !48)
+// CHECK:STDOUT: !50 = !DILocation(line: 26, column: 5, scope: !48)
+// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Has", linkageName: "_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !35, line: 73, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !52 = !DILocation(line: 74, column: 12, scope: !51)
+// CHECK:STDOUT: !53 = !DILocation(line: 74, column: 5, scope: !51)
+// CHECK:STDOUT: !54 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !35, line: 76, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !55 = !DILocation(line: 77, column: 12, scope: !54)
+// CHECK:STDOUT: !56 = !DILocation(line: 77, column: 5, scope: !54)
+// CHECK:STDOUT: !57 = distinct !DISubprogram(name: "Op", linkageName: "_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d", scope: null, file: !42, line: 275, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !58 = !DILocation(line: 4294967295, scope: !57)
+// CHECK:STDOUT: !59 = !DILocation(line: 275, column: 3, scope: !57)
+// CHECK:STDOUT: !60 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !35, line: 65, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !61 = !DILocation(line: 69, column: 5, scope: !60)
+// CHECK:STDOUT: !62 = !DILocation(line: 70, column: 5, scope: !60)
+// CHECK:STDOUT: !63 = !DILocation(line: 71, column: 5, scope: !60)
+// CHECK:STDOUT: !64 = distinct !DISubprogram(name: "None", linkageName: "_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !35, line: 60, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !65 = !DILocation(line: 62, column: 5, scope: !64)
+// CHECK:STDOUT: !66 = !DILocation(line: 63, column: 5, scope: !64)
+// CHECK:STDOUT: !67 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861", scope: null, file: !68, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !68 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
+// CHECK:STDOUT: !69 = !DILocation(line: 24, column: 38, scope: !67)

+ 81 - 48
toolchain/lower/testdata/for/for.carbon

@@ -37,7 +37,7 @@ fn For() {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %.loc21_32.1.temp = alloca { i32, i32 }, align 8, !dbg !7
 // CHECK:STDOUT:   %var = alloca i32, align 4, !dbg !8
-// CHECK:STDOUT:   %.loc21_33.1.temp = alloca { i1, i32 }, align 8, !dbg !8
+// CHECK:STDOUT:   %.loc21_33.1.temp = alloca { i32, i1 }, align 8, !dbg !8
 // CHECK:STDOUT:   call void @_CF.Main(), !dbg !9
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc21_32.1.temp), !dbg !7
 // CHECK:STDOUT:   call void @_CRange.Core(ptr %.loc21_32.1.temp, i32 100), !dbg !7
@@ -49,11 +49,11 @@ fn For() {
 // CHECK:STDOUT: for.next:                                         ; preds = %for.body, %entry
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc21_33.1.temp), !dbg !8
 // CHECK:STDOUT:   call void @"_CNext.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr %.loc21_33.1.temp, ptr %.loc21_32.1.temp, ptr %var), !dbg !8
-// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.de631560529e9861(ptr %.loc21_33.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.30bf744b66445e68(ptr %.loc21_33.1.temp), !dbg !8
 // CHECK:STDOUT:   br i1 %Optional.HasValue.call, label %for.body, label %for.done, !dbg !8
 // CHECK:STDOUT:
 // CHECK:STDOUT: for.body:                                         ; preds = %for.next
-// CHECK:STDOUT:   %Optional.Get.call = call i32 @_CGet.Optional.Core.de631560529e9861(ptr %.loc21_33.1.temp), !dbg !8
+// CHECK:STDOUT:   %Optional.Get.call = call i32 @_CGet.Optional.Core.30bf744b66445e68(ptr %.loc21_33.1.temp), !dbg !8
 // CHECK:STDOUT:   call void @_CG.Main(), !dbg !10
 // CHECK:STDOUT:   br label %for.next, !dbg !11
 // CHECK:STDOUT:
@@ -73,7 +73,7 @@ fn For() {
 // CHECK:STDOUT:   ret i32 %1, !dbg !17
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_CNext.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr sret({ i1, i32 }) %return, ptr %self, ptr %cursor) !dbg !18 {
+// CHECK:STDOUT: define linkonce_odr void @"_CNext.IntRange.Core:Iterate.Core.be1e879c1ad406d8"(ptr sret({ i32, i1 }) %return, ptr %self, ptr %cursor) !dbg !18 {
 // CHECK:STDOUT:   %1 = alloca i32, align 4, !dbg !19
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %1), !dbg !19
 // CHECK:STDOUT:   %2 = load i32, ptr %cursor, align 4, !dbg !20
@@ -87,24 +87,21 @@ fn For() {
 // CHECK:STDOUT: 6:                                                ; preds = %0
 // CHECK:STDOUT:   call void @"_COp.Int.Core:Inc.Core.be1e879c1ad406d8"(ptr %cursor), !dbg !24
 // CHECK:STDOUT:   %7 = load i32, ptr %1, align 4, !dbg !25
-// CHECK:STDOUT:   call void @_CSome.Optional.Core.de631560529e9861(ptr %return, i32 %7), !dbg !26
+// CHECK:STDOUT:   call void @_CSome.Optional.Core.30bf744b66445e68(ptr %return, i32 %7), !dbg !26
 // CHECK:STDOUT:   ret void, !dbg !27
 // CHECK:STDOUT:
 // CHECK:STDOUT: 8:                                                ; preds = %0
-// CHECK:STDOUT:   call void @_CNone.Optional.Core.de631560529e9861(ptr %return), !dbg !28
+// CHECK:STDOUT:   call void @_CNone.Optional.Core.30bf744b66445e68(ptr %return), !dbg !28
 // CHECK:STDOUT:   ret void, !dbg !29
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.de631560529e9861(ptr %self) !dbg !30 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %self, i32 0, i32 0, !dbg !32
-// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !32
-// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !32
-// CHECK:STDOUT:   ret i1 %2, !dbg !33
+// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.30bf744b66445e68(ptr %self) !dbg !30 {
+// CHECK:STDOUT:   %1 = call i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %self), !dbg !32
+// CHECK:STDOUT:   ret i1 %1, !dbg !33
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i32 @_CGet.Optional.Core.de631560529e9861(ptr %self) !dbg !34 {
-// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i1, i32 }, ptr %self, i32 0, i32 1, !dbg !35
-// CHECK:STDOUT:   %1 = load i32, ptr %value, align 4, !dbg !35
+// CHECK:STDOUT: define linkonce_odr i32 @_CGet.Optional.Core.30bf744b66445e68(ptr %self) !dbg !34 {
+// CHECK:STDOUT:   %1 = call i32 @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %self), !dbg !35
 // CHECK:STDOUT:   ret i32 %1, !dbg !36
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -115,30 +112,53 @@ fn For() {
 // CHECK:STDOUT:   ret void, !dbg !40
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.de631560529e9861(ptr sret({ i1, i32 }) %return, i32 %value) !dbg !41 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 0, !dbg !42
-// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 1, !dbg !42
-// CHECK:STDOUT:   store i32 %value, ptr %value1, align 4, !dbg !42
-// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !42
+// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.30bf744b66445e68(ptr sret({ i32, i1 }) %return, i32 %value) !dbg !41 {
+// CHECK:STDOUT:   call void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return, i32 %value), !dbg !42
 // CHECK:STDOUT:   ret void, !dbg !43
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.de631560529e9861(ptr sret({ i1, i32 }) %return) !dbg !44 {
-// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i1, i32 }, ptr %return, i32 0, i32 0, !dbg !45
-// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !45
+// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.30bf744b66445e68(ptr sret({ i32, i1 }) %return) !dbg !44 {
+// CHECK:STDOUT:   call void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return), !dbg !45
 // CHECK:STDOUT:   ret void, !dbg !46
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr void @"_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d"(ptr %self, i32 %other) !dbg !47 {
-// CHECK:STDOUT:   %1 = call i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %other), !dbg !48
-// CHECK:STDOUT:   %2 = load i32, ptr %self, align 4, !dbg !49
-// CHECK:STDOUT:   %3 = add i32 %2, %1, !dbg !49
-// CHECK:STDOUT:   store i32 %3, ptr %self, align 4, !dbg !49
-// CHECK:STDOUT:   ret void, !dbg !49
+// CHECK:STDOUT: define linkonce_odr i1 @"_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %value) !dbg !47 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %value, i32 0, i32 1, !dbg !48
+// CHECK:STDOUT:   %1 = load i8, ptr %has_value, align 1, !dbg !48
+// CHECK:STDOUT:   %2 = trunc i8 %1 to i1, !dbg !48
+// CHECK:STDOUT:   ret i1 %2, !dbg !49
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: define linkonce_odr i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %self) !dbg !50 {
-// CHECK:STDOUT:   ret i32 %self, !dbg !52
+// CHECK:STDOUT: define linkonce_odr i32 @"_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %value) !dbg !50 {
+// CHECK:STDOUT:   %value1 = getelementptr inbounds nuw { i32, i1 }, ptr %value, i32 0, i32 0, !dbg !51
+// CHECK:STDOUT:   %1 = load i32, ptr %value1, align 4, !dbg !51
+// CHECK:STDOUT:   ret i32 %1, !dbg !52
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d"(ptr %self, i32 %other) !dbg !53 {
+// CHECK:STDOUT:   %1 = call i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %other), !dbg !54
+// CHECK:STDOUT:   %2 = load i32, ptr %self, align 4, !dbg !55
+// CHECK:STDOUT:   %3 = add i32 %2, %1, !dbg !55
+// CHECK:STDOUT:   store i32 %3, ptr %self, align 4, !dbg !55
+// CHECK:STDOUT:   ret void, !dbg !55
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return, i32 %self) !dbg !56 {
+// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 0, !dbg !57
+// CHECK:STDOUT:   store i32 %self, ptr %value, align 4, !dbg !57
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !58
+// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !58
+// CHECK:STDOUT:   ret void, !dbg !59
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return) !dbg !60 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !61
+// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !61
+// CHECK:STDOUT:   ret void, !dbg !62
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr i32 @"_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861"(i32 %self) !dbg !63 {
+// CHECK:STDOUT:   ret i32 %self, !dbg !65
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; uselistorder directives
@@ -179,26 +199,39 @@ fn For() {
 // CHECK:STDOUT: !27 = !DILocation(line: 30, column: 9, scope: !18)
 // CHECK:STDOUT: !28 = !DILocation(line: 32, column: 16, scope: !18)
 // CHECK:STDOUT: !29 = !DILocation(line: 32, column: 9, scope: !18)
-// CHECK:STDOUT: !30 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.de631560529e9861", scope: null, file: !31, line: 30, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !30 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.30bf744b66445e68", scope: null, file: !31, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !31 = !DIFile(filename: "{{.*}}/prelude/types/optional.carbon", directory: "")
-// CHECK:STDOUT: !32 = !DILocation(line: 30, column: 46, scope: !30)
-// CHECK:STDOUT: !33 = !DILocation(line: 30, column: 39, scope: !30)
-// CHECK:STDOUT: !34 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.de631560529e9861", scope: null, file: !31, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !35 = !DILocation(line: 31, column: 38, scope: !34)
-// CHECK:STDOUT: !36 = !DILocation(line: 31, column: 31, scope: !34)
+// CHECK:STDOUT: !32 = !DILocation(line: 32, column: 12, scope: !30)
+// CHECK:STDOUT: !33 = !DILocation(line: 32, column: 5, scope: !30)
+// CHECK:STDOUT: !34 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.30bf744b66445e68", scope: null, file: !31, line: 34, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !35 = !DILocation(line: 35, column: 12, scope: !34)
+// CHECK:STDOUT: !36 = !DILocation(line: 35, column: 5, scope: !34)
 // CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.Int.Core:Inc.Core.be1e879c1ad406d8", scope: null, file: !38, line: 339, type: !5, spFlags: DISPFlagDefinition, unit: !2)
 // CHECK:STDOUT: !38 = !DIFile(filename: "{{.*}}/prelude/types/int.carbon", directory: "")
 // CHECK:STDOUT: !39 = !DILocation(line: 341, column: 5, scope: !37)
 // CHECK:STDOUT: !40 = !DILocation(line: 339, column: 3, scope: !37)
-// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.de631560529e9861", scope: null, file: !31, line: 26, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !42 = !DILocation(line: 27, column: 12, scope: !41)
-// CHECK:STDOUT: !43 = !DILocation(line: 27, column: 5, scope: !41)
-// CHECK:STDOUT: !44 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.de631560529e9861", scope: null, file: !31, line: 20, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !45 = !DILocation(line: 22, column: 5, scope: !44)
-// CHECK:STDOUT: !46 = !DILocation(line: 23, column: 5, scope: !44)
-// CHECK:STDOUT: !47 = distinct !DISubprogram(name: "Op", linkageName: "_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d", scope: null, file: !38, line: 275, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !48 = !DILocation(line: 4294967295, scope: !47)
-// CHECK:STDOUT: !49 = !DILocation(line: 275, column: 3, scope: !47)
-// CHECK:STDOUT: !50 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861", scope: null, file: !51, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
-// CHECK:STDOUT: !51 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
-// CHECK:STDOUT: !52 = !DILocation(line: 24, column: 38, scope: !50)
+// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.30bf744b66445e68", scope: null, file: !31, line: 28, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !42 = !DILocation(line: 29, column: 12, scope: !41)
+// CHECK:STDOUT: !43 = !DILocation(line: 29, column: 5, scope: !41)
+// CHECK:STDOUT: !44 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.30bf744b66445e68", scope: null, file: !31, line: 25, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !45 = !DILocation(line: 26, column: 12, scope: !44)
+// CHECK:STDOUT: !46 = !DILocation(line: 26, column: 5, scope: !44)
+// CHECK:STDOUT: !47 = distinct !DISubprogram(name: "Has", linkageName: "_CHas.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !31, line: 73, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !48 = !DILocation(line: 74, column: 12, scope: !47)
+// CHECK:STDOUT: !49 = !DILocation(line: 74, column: 5, scope: !47)
+// CHECK:STDOUT: !50 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !31, line: 76, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !51 = !DILocation(line: 77, column: 12, scope: !50)
+// CHECK:STDOUT: !52 = !DILocation(line: 77, column: 5, scope: !50)
+// CHECK:STDOUT: !53 = distinct !DISubprogram(name: "Op", linkageName: "_COp:thunk.Int.Core:AddAssignWith.Core.2122e6c8c4f4206d", scope: null, file: !38, line: 275, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !54 = !DILocation(line: 4294967295, scope: !53)
+// CHECK:STDOUT: !55 = !DILocation(line: 275, column: 3, scope: !53)
+// CHECK:STDOUT: !56 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !31, line: 65, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !57 = !DILocation(line: 69, column: 5, scope: !56)
+// CHECK:STDOUT: !58 = !DILocation(line: 70, column: 5, scope: !56)
+// CHECK:STDOUT: !59 = !DILocation(line: 71, column: 5, scope: !56)
+// CHECK:STDOUT: !60 = distinct !DISubprogram(name: "None", linkageName: "_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !31, line: 60, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !61 = !DILocation(line: 62, column: 5, scope: !60)
+// CHECK:STDOUT: !62 = !DILocation(line: 63, column: 5, scope: !60)
+// CHECK:STDOUT: !63 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.2a0d145dae8e0e7f:ImplicitAs.Core.de631560529e9861", scope: null, file: !64, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !64 = !DIFile(filename: "{{.*}}/prelude/operators/as.carbon", directory: "")
+// CHECK:STDOUT: !65 = !DILocation(line: 24, column: 38, scope: !63)

+ 136 - 0
toolchain/lower/testdata/primitives/optional.carbon

@@ -0,0 +1,136 @@
+// 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
+//
+// This is an integration test for the Core.Optional in the prelude, so use the
+// real prelude.
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/full.carbon
+// EXTRA-ARGS: --target=x86_64-linux-gnu
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/primitives/optional.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/primitives/optional.carbon
+
+fn Convert(o: Core.Optional(i32*)) -> Core.Optional(i32) {
+  if (o.HasValue()) {
+    return *o.Get();
+  }
+  return Core.Optional(i32).None();
+}
+
+// CHECK:STDOUT: ; ModuleID = 'optional.carbon'
+// CHECK:STDOUT: source_filename = "optional.carbon"
+// CHECK:STDOUT:
+// CHECK:STDOUT: define void @_CConvert.Main(ptr sret({ i32, i1 }) %return, ptr %o) !dbg !4 {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT:   %.loc18_20.1.temp = alloca { i32, i1 }, align 8, !dbg !7
+// CHECK:STDOUT:   %Optional.HasValue.call = call i1 @_CHasValue.Optional.Core.a5473232b4618d29(ptr %o), !dbg !8
+// CHECK:STDOUT:   br i1 %Optional.HasValue.call, label %if.then, label %if.else, !dbg !9
+// CHECK:STDOUT:
+// CHECK:STDOUT: if.then:                                          ; preds = %entry
+// CHECK:STDOUT:   %Optional.Get.call = call ptr @_CGet.Optional.Core.a5473232b4618d29(ptr %o), !dbg !10
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc18_20.1.temp), !dbg !7
+// CHECK:STDOUT:   %.loc18_12.2 = load i32, ptr %Optional.Get.call, align 4, !dbg !11
+// CHECK:STDOUT:   call void @"_CConvert.b97494f2edbcdd31:ImplicitAs.Core.e126642f41a9ea1c"(ptr %.loc18_20.1.temp, i32 %.loc18_12.2), !dbg !7
+// CHECK:STDOUT:   ret void, !dbg !7
+// CHECK:STDOUT:
+// CHECK:STDOUT: if.else:                                          ; preds = %entry
+// CHECK:STDOUT:   call void @_CNone.Optional.Core.e126642f41a9ea1c(ptr %return), !dbg !12
+// CHECK:STDOUT:   ret void, !dbg !13
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr i1 @_CHasValue.Optional.Core.a5473232b4618d29(ptr %self) !dbg !14 {
+// CHECK:STDOUT:   %1 = load ptr, ptr %self, align 8, !dbg !16
+// CHECK:STDOUT:   %2 = icmp eq ptr %1, null, !dbg !16
+// CHECK:STDOUT:   ret i1 %2, !dbg !17
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr ptr @_CGet.Optional.Core.a5473232b4618d29(ptr %self) !dbg !18 {
+// CHECK:STDOUT:   %1 = call ptr @"_CGet.79f1318a93915de5:OptionalStorage.Core.b88d1103f417c6d4"(ptr %self), !dbg !19
+// CHECK:STDOUT:   ret ptr %1, !dbg !20
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #0
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CConvert.b97494f2edbcdd31:ImplicitAs.Core.e126642f41a9ea1c"(ptr sret({ i32, i1 }) %return, i32 %self) !dbg !21 {
+// CHECK:STDOUT:   call void @_CSome.Optional.Core.e126642f41a9ea1c(ptr %return, i32 %self), !dbg !22
+// CHECK:STDOUT:   ret void, !dbg !23
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @_CNone.Optional.Core.e126642f41a9ea1c(ptr sret({ i32, i1 }) %return) !dbg !24 {
+// CHECK:STDOUT:   call void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return), !dbg !25
+// CHECK:STDOUT:   ret void, !dbg !26
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr ptr @"_CGet.79f1318a93915de5:OptionalStorage.Core.b88d1103f417c6d4"(ptr %value) !dbg !27 {
+// CHECK:STDOUT:   %1 = load ptr, ptr %value, align 8, !dbg !28
+// CHECK:STDOUT:   ret ptr %1, !dbg !29
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @_CSome.Optional.Core.e126642f41a9ea1c(ptr sret({ i32, i1 }) %return, i32 %value) !dbg !30 {
+// CHECK:STDOUT:   call void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr %return, i32 %value), !dbg !31
+// CHECK:STDOUT:   ret void, !dbg !32
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return) !dbg !33 {
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !34
+// CHECK:STDOUT:   store i8 0, ptr %has_value, align 1, !dbg !34
+// CHECK:STDOUT:   ret void, !dbg !35
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define linkonce_odr void @"_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861"(ptr sret({ i32, i1 }) %return, i32 %self) !dbg !36 {
+// CHECK:STDOUT:   %value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 0, !dbg !37
+// CHECK:STDOUT:   store i32 %self, ptr %value, align 4, !dbg !37
+// CHECK:STDOUT:   %has_value = getelementptr inbounds nuw { i32, i1 }, ptr %return, i32 0, i32 1, !dbg !38
+// CHECK:STDOUT:   store i8 1, ptr %has_value, align 1, !dbg !38
+// CHECK:STDOUT:   ret void, !dbg !39
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
+// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
+// CHECK:STDOUT:
+// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
+// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
+// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+// CHECK:STDOUT: !3 = !DIFile(filename: "optional.carbon", directory: "")
+// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.Main", scope: null, file: !3, line: 16, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
+// CHECK:STDOUT: !6 = !{}
+// CHECK:STDOUT: !7 = !DILocation(line: 18, column: 5, scope: !4)
+// CHECK:STDOUT: !8 = !DILocation(line: 17, column: 7, scope: !4)
+// CHECK:STDOUT: !9 = !DILocation(line: 17, column: 6, scope: !4)
+// CHECK:STDOUT: !10 = !DILocation(line: 18, column: 13, scope: !4)
+// CHECK:STDOUT: !11 = !DILocation(line: 18, column: 12, scope: !4)
+// CHECK:STDOUT: !12 = !DILocation(line: 20, column: 10, scope: !4)
+// CHECK:STDOUT: !13 = !DILocation(line: 20, column: 3, scope: !4)
+// CHECK:STDOUT: !14 = distinct !DISubprogram(name: "HasValue", linkageName: "_CHasValue.Optional.Core.a5473232b4618d29", scope: null, file: !15, line: 31, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !15 = !DIFile(filename: "{{.*}}/prelude/types/optional.carbon", directory: "")
+// CHECK:STDOUT: !16 = !DILocation(line: 32, column: 12, scope: !14)
+// CHECK:STDOUT: !17 = !DILocation(line: 32, column: 5, scope: !14)
+// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.Optional.Core.a5473232b4618d29", scope: null, file: !15, line: 34, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !19 = !DILocation(line: 35, column: 12, scope: !18)
+// CHECK:STDOUT: !20 = !DILocation(line: 35, column: 5, scope: !18)
+// CHECK:STDOUT: !21 = distinct !DISubprogram(name: "Convert", linkageName: "_CConvert.b97494f2edbcdd31:ImplicitAs.Core.e126642f41a9ea1c", scope: null, file: !15, line: 39, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !22 = !DILocation(line: 40, column: 14, scope: !21)
+// CHECK:STDOUT: !23 = !DILocation(line: 40, column: 7, scope: !21)
+// CHECK:STDOUT: !24 = distinct !DISubprogram(name: "None", linkageName: "_CNone.Optional.Core.e126642f41a9ea1c", scope: null, file: !15, line: 25, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !25 = !DILocation(line: 26, column: 12, scope: !24)
+// CHECK:STDOUT: !26 = !DILocation(line: 26, column: 5, scope: !24)
+// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "Get", linkageName: "_CGet.79f1318a93915de5:OptionalStorage.Core.b88d1103f417c6d4", scope: null, file: !15, line: 92, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !28 = !DILocation(line: 93, column: 12, scope: !27)
+// CHECK:STDOUT: !29 = !DILocation(line: 93, column: 5, scope: !27)
+// CHECK:STDOUT: !30 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.Optional.Core.e126642f41a9ea1c", scope: null, file: !15, line: 28, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !31 = !DILocation(line: 29, column: 12, scope: !30)
+// CHECK:STDOUT: !32 = !DILocation(line: 29, column: 5, scope: !30)
+// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "None", linkageName: "_CNone.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !15, line: 60, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !34 = !DILocation(line: 62, column: 5, scope: !33)
+// CHECK:STDOUT: !35 = !DILocation(line: 63, column: 5, scope: !33)
+// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "Some", linkageName: "_CSome.2a0d145dae8e0e7f:OptionalStorage.Core.de631560529e9861", scope: null, file: !15, line: 65, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !37 = !DILocation(line: 69, column: 5, scope: !36)
+// CHECK:STDOUT: !38 = !DILocation(line: 70, column: 5, scope: !36)
+// CHECK:STDOUT: !39 = !DILocation(line: 71, column: 5, scope: !36)