Skip to main content

charon_lib/minirust/
types.rs

1use super::*;
2
3impl<T: mini::Target> TranslateCtx<'_, T> {
4    pub(super) fn ty(&self, span: Span, ty: &Ty) -> Result<mini::Type> {
5        Ok(match ty.kind() {
6            TyKind::Scalar(ScalarTy::Integer(integer)) => mini::Type::Int(self.int_type(*integer)),
7            TyKind::Scalar(ScalarTy::Bool) => mini::Type::Bool,
8            TyKind::Scalar(ScalarTy::Char) => mb::int_ty(mini::Signedness::Unsigned, mini_size(4)),
9            TyKind::Scalar(ScalarTy::Float(_)) => {
10                raise!(span, "MiniRust has no floating-point types")
11            }
12            TyKind::Array(elem_ty, len, _) => mini::Type::Array {
13                elem: mini::GcCow::new(self.ty(span, elem_ty)?),
14                count: mini::Int::from(
15                    len.as_usize_literal()
16                        .ok_or("non-concrete array length")
17                        .context(span)?,
18                ),
19            },
20            TyKind::Slice(elem_ty, _) => mini::Type::Slice {
21                elem: mini::GcCow::new(self.ty(span, elem_ty)?),
22            },
23            TyKind::Adt(tref) if tref.is_box() => {
24                let pointee = ty
25                    .builtin_deref(self.krate)
26                    .ok_or("Box type is missing its pointee")
27                    .context(span)?;
28                mini::Type::Ptr(mini::PtrType::Box {
29                    pointee: self.pointee_info(span, pointee)?,
30                })
31            }
32            TyKind::Adt(tref) => self.adt_type(span, tref)?,
33            TyKind::Ref(_, pointee, kind) => mini::Type::Ptr(mini::PtrType::Ref {
34                mutbl: match kind {
35                    RefKind::Mut => mini::Mutability::Mutable,
36                    RefKind::Shared => mini::Mutability::Immutable,
37                },
38                pointee: self.pointee_info(span, pointee)?,
39            }),
40            TyKind::RawPtr(pointee, _) => mini::Type::Ptr(mini::PtrType::Raw {
41                meta_kind: self.metadata_kind(span, pointee)?,
42            }),
43            TyKind::FnDef(_) => mini::unit_ty(),
44            TyKind::FnPtr(_) => mini::Type::Ptr(mini::PtrType::FnPtr),
45            TyKind::Never => mini::Type::Enum {
46                variants: Default::default(),
47                discriminant_ty: self.int_type(IntegerTy::Unsigned(UIntTy::U8)),
48                discriminator: mini::Discriminator::Invalid,
49                size: mini_size(0),
50                align: mini_align(span, 1)?,
51            },
52            TyKind::Pattern(base, _) => self.ty(span, base)?,
53            TyKind::PtrMetadata(pointee) => match self.metadata_kind(span, pointee)? {
54                mini::PointerMetaKind::None => mini::unit_ty(),
55                mini::PointerMetaKind::ElementCount => {
56                    mb::int_ty(mini::Signedness::Unsigned, T::PTR_SIZE)
57                }
58                mini::PointerMetaKind::VTablePointer(trait_name) => {
59                    mini::Type::Ptr(mini::PtrType::VTablePtr(trait_name))
60                }
61            },
62            TyKind::DynTrait(pred) => mini::Type::TraitObject(
63                self.trait_name(
64                    pred.vtable_ref(self.krate)
65                        .ok_or("missing vtable for dyn trait")
66                        .context(span)?
67                        .id,
68                ),
69            ),
70            TyKind::TypeVar(_) | TyKind::TraitType(..) => {
71                raise!(
72                    span,
73                    "MiniRust output requires a monomorphized crate: {}",
74                    ty.with_ctx(&self.fmt)
75                )
76            }
77            TyKind::Error(error) => raise!(span, "type error: {error}"),
78        })
79    }
80
81    fn adt_type(&self, span: Span, tref: &TypeDeclRef) -> Result<mini::Type> {
82        let tdecl = self
83            .krate
84            .type_decls
85            .get(tref.id)
86            .ok_or_else(|| format!("missing type declaration {}", tref.id.with_ctx(&self.fmt)))
87            .context(span)?;
88        let layout = tdecl
89            .layout
90            .get(self.target_name)
91            .ok_or_else(|| {
92                format!(
93                    "missing layout for {}",
94                    tdecl.item_meta.name.with_ctx(&self.fmt)
95                )
96            })
97            .context(span)?;
98        Ok(match &tdecl.kind {
99            TypeDeclKind::Struct(fields) => {
100                let variant_layout = layout.variant_layouts[VariantId::ZERO].as_ref();
101                self.tuple_type(span, fields, variant_layout, layout, &tref.generics)?
102            }
103            TypeDeclKind::Union(fields) => {
104                let variant_layout = layout.variant_layouts[VariantId::ZERO]
105                    .as_ref()
106                    .ok_or("union has no fields layout")
107                    .context(span)?;
108                let fields = fields
109                    .iter_enumerated()
110                    .map(|(id, field)| -> Result<_> {
111                        let offset = variant_layout.field_offsets[id]
112                            .chosen
113                            .ok_or("missing field offset in union layout")
114                            .context(span)?;
115                        let ty = self.ty(span, &field.ty.clone().substitute(&tref.generics))?;
116                        Ok((mini_size(offset), ty))
117                    })
118                    .try_collect()?;
119                let size = mini_size(self.size(span, &layout.size)?);
120                let align = mini_align(span, self.size(span, &layout.align)?)?;
121                mini::Type::Union {
122                    fields,
123                    // FIXME(minirust): Some bytes may be padding.
124                    chunks: [(mini::Size::ZERO, size)].into_iter().collect(),
125                    size,
126                    align,
127                }
128            }
129            TypeDeclKind::Enum(variants) => {
130                let size = mini_size(self.size(span, &layout.size)?);
131                let align = mini_align(span, self.size(span, &layout.align)?)?;
132                let discriminant_ty = self.int_type(
133                    variants
134                        .first()
135                        .map(|variant| variant.discriminant.ty())
136                        .unwrap_or(IntegerTy::Unsigned(UIntTy::U8)),
137                );
138                let mini_variants = variants
139                    .iter_enumerated()
140                    .map(|(id, variant)| -> Result<_> {
141                        let variant_layout = layout.variant_layouts[id].as_ref();
142                        let ty = self.tuple_type(
143                            span,
144                            &variant.fields,
145                            variant_layout,
146                            layout,
147                            &tref.generics,
148                        )?;
149                        let tagger = variant_layout
150                            .map(|layout| {
151                                layout
152                                    .tagger
153                                    .iter()
154                                    .map(|(offset, value)| {
155                                        (
156                                            mini_size(*offset),
157                                            (self.int_type(value.ty()), mini_int(*value)),
158                                        )
159                                    })
160                                    .collect()
161                            })
162                            .unwrap_or_default();
163                        Ok((mini_int(variant.discriminant), mini::Variant { ty, tagger }))
164                    })
165                    .try_collect()?;
166                let discriminator = if let Some(discriminator) = &layout.discriminator {
167                    self.discriminator(span, variants, discriminator)?
168                } else {
169                    mini::Discriminator::Invalid
170                };
171                mini::Type::Enum {
172                    variants: mini_variants,
173                    discriminant_ty,
174                    discriminator,
175                    size,
176                    align,
177                }
178            }
179            TypeDeclKind::Alias(ty) => self.ty(span, &ty.clone().substitute(&tref.generics))?,
180            TypeDeclKind::Opaque => {
181                raise!(span, "opaque type is not representable in MiniRust")
182            }
183            TypeDeclKind::Error(error) => raise!(span, "type error: {error}"),
184        })
185    }
186
187    fn tuple_type(
188        &self,
189        span: Span,
190        fields: &IndexVec<FieldId, Field>,
191        variant_layout: Option<&VariantLayout>,
192        layout: &crate::ast::Layout,
193        generics: &GenericArgs,
194    ) -> Result<mini::Type> {
195        let (repr_align, packed_align) = match layout.repr.align_modif {
196            Some(AlignmentModifier::Pack(bytes)) => {
197                (mini::Align::ONE, Some(mini_align(span, bytes)?))
198            }
199            Some(AlignmentModifier::Align(bytes)) => (mini_align(span, bytes)?, None),
200            None => (mini::Align::ONE, None),
201        };
202        let mut sized_fields = mini::Fields::new();
203        let mut head_align = repr_align;
204        let mut unsized_field = None;
205        let mut tail_offset = None;
206        for (id, field) in fields.iter_enumerated() {
207            let ty = self.ty(span, &field.ty.clone().substitute(generics))?;
208            let offset = match variant_layout {
209                Some(layout) => layout.field_offsets[id]
210                    .chosen
211                    .ok_or("missing field offset in ADT layout")
212                    .context(span)?,
213                // An elided enum variant can only contain zero-sized fields.
214                None => 0,
215            };
216            match ty.layout::<T>() {
217                mini::LayoutStrategy::Sized(_, field_align) => {
218                    head_align = head_align
219                        .max(packed_align.map_or(field_align, |packed| field_align.min(packed)));
220                    sized_fields.push((mini_size(offset), ty));
221                }
222                _ => {
223                    check!(
224                        span,
225                        id.index() + 1 == fields.len(),
226                        "non-tail field is unsized"
227                    );
228                    unsized_field = Some(ty);
229                    tail_offset = Some(offset);
230                }
231            }
232        }
233        let (end, head_align) = match tail_offset {
234            // Include any padding before the tail in the head.
235            Some(offset) => (mini_size(offset), head_align),
236            None => (
237                mini_size(self.size(span, &layout.size)?),
238                mini_align(span, self.size(span, &layout.align)?)?,
239            ),
240        };
241        Ok(mini::Type::Tuple {
242            sized_fields,
243            sized_head_layout: mini::TupleHeadLayout {
244                end,
245                align: head_align,
246                // Sized field offsets already encode packing; MiniRust only needs this for a DST tail.
247                packed_align: if tail_offset.is_some() {
248                    packed_align
249                } else {
250                    None
251                },
252            },
253            unsized_field: mini::GcCow::new(unsized_field),
254        })
255    }
256
257    fn discriminator(
258        &self,
259        span: Span,
260        variants: &IndexVec<VariantId, Variant>,
261        value: &Discriminator,
262    ) -> Result<mini::Discriminator> {
263        Ok(match value {
264            Discriminator::Known(variant) => {
265                mini::Discriminator::Known(mini_int(variants[*variant].discriminant))
266            }
267            Discriminator::Invalid => mini::Discriminator::Invalid,
268            Discriminator::Branch {
269                offset,
270                int_ty,
271                children,
272                fallback,
273            } => mini::Discriminator::Branch {
274                offset: mini_size(
275                    offset
276                        .chosen
277                        .ok_or("non-concrete discriminator offset")
278                        .context(span)?,
279                ),
280                value_type: self.int_type(*int_ty),
281                fallback: mini::GcCow::new(self.discriminator(span, variants, fallback)?),
282                children: children
283                    .iter()
284                    .map(|(range, child)| -> Result<_> {
285                        let start = mini_int(*range.start());
286                        let end = mini_int(*range.end()) + 1;
287                        Ok(((start, end), self.discriminator(span, variants, child)?))
288                    })
289                    .try_collect()?,
290            },
291        })
292    }
293
294    pub(super) fn variant_discriminant(
295        &self,
296        span: Span,
297        ty: &Ty,
298        variant: VariantId,
299    ) -> Result<mini::Int> {
300        let tref = ty.as_adt().ok_or("variant on non-ADT").context(span)?;
301        self.variant_discriminant_for_tref(span, tref, variant)
302    }
303
304    pub(super) fn variant_discriminant_for_tref(
305        &self,
306        span: Span,
307        tref: &TypeDeclRef,
308        variant: VariantId,
309    ) -> Result<mini::Int> {
310        let tdecl = self
311            .krate
312            .type_decls
313            .get(tref.id)
314            .ok_or("missing enum declaration")
315            .context(span)?;
316        let variants = tdecl
317            .kind
318            .as_enum()
319            .ok_or("variant on non-enum")
320            .context(span)?;
321        Ok(mini_int(variants[variant].discriminant))
322    }
323
324    pub(super) fn pointee_info(&self, span: Span, ty: &Ty) -> Result<mini::PointeeInfo> {
325        let mini_ty = self.ty(span, ty)?;
326        let layout = mini_ty.layout::<T>();
327        let inhabited = !ty
328            .inhabited_predicate(self.krate, Some(self.target_name))
329            .always_false();
330        let unsafe_cells = self.unsafe_cell_strategy(span, ty)?;
331        let (freeze, unpin) = self.freeze_and_unpin(span, ty)?;
332        Ok(mini::PointeeInfo {
333            layout,
334            inhabited,
335            unsafe_cells,
336            freeze,
337            unpin,
338        })
339    }
340
341    fn freeze_and_unpin(&self, span: Span, ty: &Ty) -> Result<(bool, bool)> {
342        Ok(match ty.kind() {
343            TyKind::Array(element, ..) | TyKind::Slice(element, ..) => {
344                self.freeze_and_unpin(span, element)?
345            }
346            TyKind::Adt(tref) => {
347                let marker_traits = self
348                    .krate
349                    .type_decls
350                    .get(tref.id)
351                    .and_then(|decl| decl.marker_traits.as_deref())
352                    .ok_or("missing marker-trait information for this type")
353                    .context(span)?;
354                (marker_traits.is_freeze, marker_traits.is_unpin)
355            }
356            TyKind::Pattern(ty, _) => self.freeze_and_unpin(span, ty)?,
357            TyKind::TypeVar(_) | TyKind::TraitType(..) => raise!(
358                span,
359                "MiniRust output requires a monomorphized crate: {}",
360                ty.with_ctx(&self.fmt)
361            ),
362            TyKind::DynTrait(pred) => {
363                let has_bound = |lang_item| {
364                    pred.binder.params.trait_clauses.iter().any(|clause| {
365                        self.krate
366                            .trait_decls
367                            .get(clause.trait_.skip_binder.id)
368                            .is_some_and(|decl| {
369                                decl.item_meta.lang_item.as_ref() == Some(&lang_item)
370                            })
371                    })
372                };
373                (has_bound(LangItem::Freeze), has_bound(LangItem::Unpin))
374            }
375            TyKind::Error(error) => raise!(span, "type error: {error}"),
376            TyKind::Scalar(_)
377            | TyKind::Ref(..)
378            | TyKind::RawPtr(..)
379            | TyKind::FnDef(_)
380            | TyKind::FnPtr(_)
381            | TyKind::Never
382            | TyKind::PtrMetadata(_) => (true, true),
383        })
384    }
385
386    pub(super) fn unsafe_cell_strategy(
387        &self,
388        span: Span,
389        ty: &Ty,
390    ) -> Result<mini::UnsafeCellStrategy> {
391        /// Strategy that labels every byte as a cell.
392        fn all_cells_strategy(layout: mini::LayoutStrategy) -> mini::UnsafeCellStrategy {
393            let whole_range = |size| {
394                if size == mini::Size::ZERO {
395                    mini::List::new()
396                } else {
397                    [(mini::Size::ZERO, size)].into_iter().collect()
398                }
399            };
400            match layout {
401                mini::LayoutStrategy::Sized(size, _) => mini::UnsafeCellStrategy::Sized {
402                    cells: whole_range(size),
403                },
404                mini::LayoutStrategy::Slice(element_size, _) => mini::UnsafeCellStrategy::Slice {
405                    element_cells: whole_range(element_size),
406                },
407                mini::LayoutStrategy::Tuple { head, tail } => mini::UnsafeCellStrategy::Tuple {
408                    head_cells: whole_range(head.end),
409                    tail_cells: mini::GcCow::new(all_cells_strategy(tail.extract())),
410                },
411                mini::LayoutStrategy::TraitObject(_) => mini::UnsafeCellStrategy::TraitObject,
412            }
413        }
414
415        Ok(match ty.kind() {
416            TyKind::Adt(tref) => {
417                let tdecl = self
418                    .krate
419                    .type_decls
420                    .get(tref.id)
421                    .ok_or("untranslated type decl")
422                    .context(span)?;
423                if matches!(
424                    tdecl.item_meta.lang_item.as_ref(),
425                    Some(LangItem::UnsafeCell)
426                ) {
427                    let mini_ty = self.ty(span, ty)?;
428                    all_cells_strategy(mini_ty.layout::<T>())
429                } else {
430                    let layout = tdecl
431                        .layout
432                        .get(self.target_name)
433                        .ok_or("missing layout for ADT")
434                        .context(span)?;
435
436                    let mut sized_cells: Vec<(mini::Size, mini::Size)> = Vec::new();
437                    let mut tail_cells = None;
438                    // Add the fields of this variant.
439                    let mut add_fields = |fields: &IndexVec<FieldId, Field>,
440                                          variant_layout: Option<&VariantLayout>|
441                     -> Result<()> {
442                        for (field_id, field) in fields.iter_enumerated() {
443                            let offset = match variant_layout {
444                                Some(layout) => layout
445                                    .field_offsets
446                                    .get(field_id)
447                                    .and_then(|offset| offset.chosen)
448                                    .ok_or("missing field offset in ADT layout")
449                                    .context(span)?,
450                                None => 0,
451                            };
452                            let field_ty = field.ty.clone().substitute(&tref.generics);
453                            match self.unsafe_cell_strategy(span, &field_ty)? {
454                                mini::UnsafeCellStrategy::Sized { cells: field_cells } => {
455                                    for (field_cell_offset, cell_size) in field_cells {
456                                        let field_cell_offset =
457                                            size_bytes(span, field_cell_offset)?;
458                                        let offset = offset
459                                            .checked_add(field_cell_offset)
460                                            .ok_or("UnsafeCell offset overflows u64")
461                                            .context(span)?;
462                                        sized_cells.push((mini_size(offset), cell_size));
463                                    }
464                                }
465                                strategy => {
466                                    check!(
467                                        span,
468                                        field_id.index() + 1 == fields.len()
469                                            && tail_cells.is_none(),
470                                        "non-tail field is unsized"
471                                    );
472                                    tail_cells = Some(strategy);
473                                }
474                            }
475                        }
476                        Ok(())
477                    };
478
479                    match &tdecl.kind {
480                        TypeDeclKind::Struct(fields) => {
481                            let variant_layout = layout.variant_layouts[VariantId::ZERO].as_ref();
482                            add_fields(fields, variant_layout)?;
483                        }
484                        TypeDeclKind::Enum(variants) => {
485                            for (variant_id, variant) in variants.iter_enumerated() {
486                                if let Some(variant_layout) =
487                                    layout.variant_layouts[variant_id].as_ref()
488                                {
489                                    add_fields(&variant.fields, Some(variant_layout))?;
490                                }
491                            }
492                            check!(
493                                span,
494                                tail_cells.is_none(),
495                                "enum variant has an unsized field"
496                            );
497                        }
498                        TypeDeclKind::Union(fields) => {
499                            let variant_layout = layout.variant_layouts[VariantId::ZERO].as_ref();
500                            add_fields(fields, variant_layout)?;
501                            check!(span, tail_cells.is_none(), "union has an unsized field");
502                        }
503                        TypeDeclKind::Opaque => {
504                            raise!(span, "opaque type is not representable in MiniRust")
505                        }
506                        TypeDeclKind::Alias(alias) => {
507                            return self.unsafe_cell_strategy(
508                                span,
509                                &alias.clone().substitute(&tref.generics),
510                            );
511                        }
512                        TypeDeclKind::Error(error) => raise!(span, "type error: {error}"),
513                    };
514
515                    // Cells from different enum variants may overlap.
516                    sized_cells.sort_unstable();
517                    let mut merged_ranges: Vec<(u64, u64)> = Vec::new();
518                    for (offset, size) in sized_cells {
519                        let start = size_bytes(span, offset)?;
520                        let size = size_bytes(span, size)?;
521                        let end = start
522                            .checked_add(size)
523                            .ok_or("UnsafeCell range overflows u64")
524                            .context(span)?;
525                        if let Some((_, previous_end)) = merged_ranges.last_mut()
526                            && start <= *previous_end
527                        {
528                            *previous_end = (*previous_end).max(end);
529                        } else {
530                            merged_ranges.push((start, end));
531                        }
532                    }
533                    let sized_cells = merged_ranges
534                        .into_iter()
535                        .map(|(start, end)| (mini_size(start), mini_size(end - start)))
536                        .collect();
537
538                    match tail_cells {
539                        None => mini::UnsafeCellStrategy::Sized { cells: sized_cells },
540                        Some(tail_cells) => mini::UnsafeCellStrategy::Tuple {
541                            head_cells: sized_cells,
542                            tail_cells: mini::GcCow::new(tail_cells),
543                        },
544                    }
545                }
546            }
547            TyKind::Array(elem_ty, len, ..) => {
548                let len = len
549                    .as_usize_literal()
550                    .ok_or("non-concrete array length")
551                    .context(span)?;
552                let (elem_size, _) = self.size_and_align(span, elem_ty)?;
553                let mini::UnsafeCellStrategy::Sized { cells } =
554                    self.unsafe_cell_strategy(span, elem_ty)?
555                else {
556                    unreachable!()
557                };
558                let cells = cells.into_iter().collect_vec(); // Make the iterator `Clone`
559                mini::UnsafeCellStrategy::Sized {
560                    cells: (0u128..len)
561                        .cartesian_product(cells.iter().copied())
562                        .map(|(index, (offset, cell_size))| -> Result<_> {
563                            let index = u64::try_from(index)
564                                .map_err(|_| "array index does not fit u64")
565                                .context(span)?;
566                            let elem_start = index
567                                .checked_mul(elem_size)
568                                .ok_or("array cell offset overflows u64")
569                                .context(span)?;
570                            Ok((mini_size(elem_start) + offset, cell_size))
571                        })
572                        .try_collect()?,
573                }
574            }
575            TyKind::Slice(elem_ty, ..) => {
576                let mini::UnsafeCellStrategy::Sized { cells } =
577                    self.unsafe_cell_strategy(span, elem_ty)?
578                else {
579                    unreachable!()
580                };
581                mini::UnsafeCellStrategy::Slice {
582                    element_cells: cells,
583                }
584            }
585            TyKind::Pattern(ty, _) => self.unsafe_cell_strategy(span, ty)?,
586            TyKind::TypeVar(_) | TyKind::TraitType(..) => raise!(
587                span,
588                "MiniRust output requires a monomorphized crate: {}",
589                ty.with_ctx(&self.fmt)
590            ),
591            TyKind::DynTrait(_) => mini::UnsafeCellStrategy::TraitObject,
592            TyKind::Error(error) => raise!(span, "type error: {error}"),
593            TyKind::Scalar(_)
594            | TyKind::Ref(..)
595            | TyKind::RawPtr(..)
596            | TyKind::FnDef(_)
597            | TyKind::FnPtr(_)
598            | TyKind::Never
599            | TyKind::PtrMetadata(_) => mini::UnsafeCellStrategy::Sized {
600                cells: Default::default(),
601            },
602        })
603    }
604
605    pub(super) fn size_and_align(&self, span: Span, ty: &Ty) -> Result<(u64, u64)> {
606        let ty = self.ty(span, ty)?;
607        Ok(match ty.layout::<T>() {
608            mini::LayoutStrategy::Sized(size, align) => {
609                (size_bytes(span, size)?, align_bytes(span, align)?)
610            }
611            _ => raise!(span, "expected a sized type"),
612        })
613    }
614
615    pub(super) fn metadata_kind(&self, span: Span, ty: &Ty) -> Result<mini::PointerMetaKind> {
616        Ok(match ty.get_ptr_metadata(self.krate) {
617            PtrMetadata::None => mini::PointerMetaKind::None,
618            PtrMetadata::Length => mini::PointerMetaKind::ElementCount,
619            PtrMetadata::VTable(tref) => {
620                mini::PointerMetaKind::VTablePointer(self.trait_name(tref.id))
621            }
622            PtrMetadata::InheritFrom(_) => raise!(span, "unresolved pointer metadata"),
623        })
624    }
625
626    pub(super) fn int_type(&self, ty: IntegerTy) -> mini::IntType {
627        let signed = match ty {
628            IntegerTy::Signed(_) => mini::Signedness::Signed,
629            IntegerTy::Unsigned(_) => mini::Signedness::Unsigned,
630        };
631        mini::IntType {
632            signed,
633            size: mini::Size::from_bytes(ty.target_size(self.target.target_pointer_size)).unwrap(),
634        }
635    }
636
637    pub(super) fn size(&self, span: Span, size: &crate::ast::Size) -> Result<u64> {
638        let expr = size
639            .chosen
640            .as_ref()
641            .ok_or("layout has no concrete size")
642            .context(span)?;
643        match expr.kind() {
644            SizeExprKind::Constant(value) => {
645                if let Some(value) = value.as_usize_literal() {
646                    u64::try_from(value)
647                        .map_err(|_| "layout size does not fit u64")
648                        .context(span)
649                } else {
650                    Ok(match value.kind() {
651                        ConstantExprKind::SizeOf(ty) => self.size_and_align(span, ty)?.0,
652                        ConstantExprKind::AlignOf(ty) => self.size_and_align(span, ty)?.1,
653                        _ => raise!(span, "layout has no concrete size"),
654                    })
655                }
656            }
657            _ => raise!(span, "layout has no concrete size"),
658        }
659    }
660}