|
1 | 1 | //! This file groups everything which is linked to implementations about [crate::types] |
2 | 2 | use crate::ast::*; |
| 3 | +use crate::formatter::IntoFormatter; |
3 | 4 | use crate::ids::Vector; |
| 5 | +use crate::pretty::FmtWithCtx; |
4 | 6 | use derive_generic_visitor::*; |
5 | 7 | use std::collections::HashSet; |
6 | 8 | use std::convert::Infallible; |
@@ -597,6 +599,211 @@ impl Ty { |
597 | 599 | } |
598 | 600 | } |
599 | 601 |
|
| 602 | + pub fn needs_drop(&self, translated: &TranslatedCrate) -> Result<bool, String> { |
| 603 | + match self.kind() { |
| 604 | + TyKind::Adt(type_decl_ref) => match type_decl_ref.id { |
| 605 | + TypeId::Adt(type_decl_id) => { |
| 606 | + let type_decl = translated.type_decls.get(type_decl_id).ok_or_else(|| { |
| 607 | + format!( |
| 608 | + "Type declaration for {} not found", |
| 609 | + type_decl_id.with_ctx(&translated.into_fmt()) |
| 610 | + ) |
| 611 | + })?; |
| 612 | + Ok(type_decl.drop_glue.is_some()) |
| 613 | + } |
| 614 | + TypeId::Tuple => { |
| 615 | + let tuple_generics = &type_decl_ref.generics.types; |
| 616 | + // A tuple needs drop if any of its elements need drop |
| 617 | + for element_ty in tuple_generics.iter() { |
| 618 | + if element_ty.needs_drop(translated)? { |
| 619 | + return Ok(true); |
| 620 | + } |
| 621 | + } |
| 622 | + Ok(false) |
| 623 | + } |
| 624 | + TypeId::Builtin(builtin_ty) => match builtin_ty { |
| 625 | + BuiltinTy::Box => Ok(true), // Box always needs drop |
| 626 | + BuiltinTy::Array => { |
| 627 | + let element_ty = &type_decl_ref.generics.types[0]; |
| 628 | + element_ty.needs_drop(translated) |
| 629 | + } |
| 630 | + BuiltinTy::Str | BuiltinTy::Slice => Ok(false), // str & [T] does not need drop |
| 631 | + }, |
| 632 | + }, |
| 633 | + TyKind::DynTrait(..) => Ok(false), |
| 634 | + TyKind::Literal(..) => Ok(false), // Literal types do not need drop |
| 635 | + TyKind::Ref(..) | TyKind::RawPtr(..) => Ok(false), // References and raw pointers do not need drop |
| 636 | + TyKind::FnPtr(..) => Ok(false), // Function pointers do not need drop |
| 637 | + TyKind::FnDef(..) => Ok(false), // Function definitions do not need drop |
| 638 | + TyKind::TraitType(..) | TyKind::TypeVar(..) | TyKind::Never | TyKind::Error(_) => { |
| 639 | + Err(format!( |
| 640 | + "Cannot determine if type {} needs drop", |
| 641 | + self.with_ctx(&translated.into_fmt()) |
| 642 | + )) |
| 643 | + } |
| 644 | + } |
| 645 | + } |
| 646 | + |
| 647 | + /// Returns either the layout of this type, or a string with the reason why we couldn't compute it. |
| 648 | + pub fn layout(&self, translated: &TranslatedCrate) -> Result<Layout, String> { |
| 649 | + match self.kind() { |
| 650 | + TyKind::Adt(type_decl_ref) => { |
| 651 | + match &type_decl_ref.id { |
| 652 | + TypeId::Adt(type_decl_id) => { |
| 653 | + let type_decl = |
| 654 | + translated.type_decls.get(*type_decl_id).ok_or_else(|| { |
| 655 | + format!( |
| 656 | + "Type declaration for {} not found", |
| 657 | + type_decl_id.with_ctx(&translated.into_fmt()) |
| 658 | + ) |
| 659 | + })?; |
| 660 | + let layout = type_decl |
| 661 | + .layout |
| 662 | + .as_ref() |
| 663 | + .ok_or("Layout not available for ADT")?; |
| 664 | + Ok(layout.clone()) |
| 665 | + } |
| 666 | + TypeId::Tuple => { |
| 667 | + // Get the tuple element types from generics |
| 668 | + let element_types = &type_decl_ref.generics.types; |
| 669 | + // Compute layout for tuple elements |
| 670 | + let mut total_size: Option<u64> = Some(0); |
| 671 | + let mut max_align: Option<u64> = Some(1); |
| 672 | + let mut is_uninhabited = false; |
| 673 | + |
| 674 | + for element_ty in element_types.iter() { |
| 675 | + let element_layout = element_ty.layout(translated)?; |
| 676 | + if element_layout.uninhabited { |
| 677 | + is_uninhabited = true; |
| 678 | + } |
| 679 | + |
| 680 | + match ( |
| 681 | + total_size, |
| 682 | + element_layout.size, |
| 683 | + element_layout.align, |
| 684 | + max_align, |
| 685 | + ) { |
| 686 | + ( |
| 687 | + Some(current_size), |
| 688 | + Some(elem_size), |
| 689 | + Some(elem_align), |
| 690 | + Some(current_max_align), |
| 691 | + ) => { |
| 692 | + // Apply alignment padding |
| 693 | + let aligned_size = |
| 694 | + (current_size + elem_align - 1) / elem_align * elem_align; |
| 695 | + total_size = Some(aligned_size + elem_size); |
| 696 | + max_align = Some(current_max_align.max(elem_align)); |
| 697 | + } |
| 698 | + _ => { |
| 699 | + // If any size or alignment is None, the final result is None |
| 700 | + total_size = None; |
| 701 | + max_align = None; |
| 702 | + } |
| 703 | + } |
| 704 | + } |
| 705 | + |
| 706 | + if is_uninhabited { |
| 707 | + // If any element is uninhabited, the whole tuple is uninhabited |
| 708 | + return Ok(Layout { |
| 709 | + size: Some(0), |
| 710 | + align: max_align.or(Some(1)), // Ensure at least 1-byte alignment |
| 711 | + uninhabited: true, |
| 712 | + variant_layouts: Vector::new(), |
| 713 | + discriminant_layout: None, |
| 714 | + }); |
| 715 | + } |
| 716 | + |
| 717 | + // Final padding to struct alignment |
| 718 | + let final_size = match (total_size, max_align) { |
| 719 | + (Some(size), Some(align)) => Some((size + align - 1) / align * align), |
| 720 | + _ => None, |
| 721 | + }; |
| 722 | + |
| 723 | + Ok(Layout { |
| 724 | + size: final_size, |
| 725 | + align: max_align, |
| 726 | + uninhabited: is_uninhabited, |
| 727 | + variant_layouts: Vector::new(), |
| 728 | + discriminant_layout: None, |
| 729 | + }) |
| 730 | + } |
| 731 | + TypeId::Builtin(builtin_ty) => { |
| 732 | + match builtin_ty { |
| 733 | + BuiltinTy::Box => Err("TODO: handle Box with ptr-metadata".to_string()), |
| 734 | + BuiltinTy::Array => { |
| 735 | + // Array layout: element_type repeated const_generics[0] times |
| 736 | + let element_ty = &type_decl_ref.generics.types[0]; |
| 737 | + let element_layout = element_ty.layout(translated)?; |
| 738 | + |
| 739 | + if element_layout.uninhabited { |
| 740 | + return Ok(Layout { |
| 741 | + size: Some(0), |
| 742 | + align: element_layout.align, |
| 743 | + uninhabited: true, |
| 744 | + variant_layouts: Vector::new(), |
| 745 | + discriminant_layout: None, |
| 746 | + }); |
| 747 | + } |
| 748 | + |
| 749 | + let cg = type_decl_ref |
| 750 | + .generics |
| 751 | + .const_generics |
| 752 | + .get(ConstGenericVarId::ZERO) |
| 753 | + .unwrap(); |
| 754 | + let ConstGeneric::Value(Literal::Scalar(scalar)) = cg else { |
| 755 | + return Err(format!( |
| 756 | + "No instant available const generic value or wrong format value: {}", |
| 757 | + cg.with_ctx(&translated.into_fmt()) |
| 758 | + )); |
| 759 | + }; |
| 760 | + let len = scalar.as_uint().or_else(|e| { |
| 761 | + Err(format!("Failed to get array length: {:?}", e)) |
| 762 | + })?; |
| 763 | + |
| 764 | + let element_size = element_layout.size; |
| 765 | + let align = element_layout.align; |
| 766 | + |
| 767 | + let size = element_size.map(|s| s * (len as u64)); |
| 768 | + |
| 769 | + Ok(Layout { |
| 770 | + size, |
| 771 | + align, |
| 772 | + uninhabited: false, |
| 773 | + variant_layouts: Vector::new(), |
| 774 | + discriminant_layout: None, |
| 775 | + }) |
| 776 | + } |
| 777 | + BuiltinTy::Slice | BuiltinTy::Str => { |
| 778 | + Err("DST does not have layout".to_string()) |
| 779 | + } |
| 780 | + } |
| 781 | + } |
| 782 | + } |
| 783 | + } |
| 784 | + TyKind::Literal(lit_ty) => { |
| 785 | + // For literal types, create a simple scalar layout |
| 786 | + let size = |
| 787 | + lit_ty.target_size(translated.target_information.target_pointer_size) as u64; |
| 788 | + Ok(Layout { |
| 789 | + size: Some(size), |
| 790 | + align: Some(size), // Scalar types are self-aligned |
| 791 | + uninhabited: false, |
| 792 | + variant_layouts: Vector::new(), |
| 793 | + discriminant_layout: None, |
| 794 | + }) |
| 795 | + } |
| 796 | + TyKind::RawPtr(_, _) | TyKind::Ref(_, _, _) => { |
| 797 | + Err("TODO: handle pointer/reference with ptr-metadata".to_string()) |
| 798 | + } |
| 799 | + TyKind::TypeVar(_) => Err("No layout due to generic".to_string()), |
| 800 | + _ => Err(format!( |
| 801 | + "Don't know how to compute layout for type {}", |
| 802 | + self.with_ctx(&translated.into_fmt()) |
| 803 | + )), |
| 804 | + } |
| 805 | + } |
| 806 | + |
600 | 807 | /// Substitue the given `target_ty` with the `replacement` type recursively in this type. |
601 | 808 | /// E.g., if `self` is `Vec<i32>`, `target_ty` is `i32` and `replacement` is `Vec<i32>`, then |
602 | 809 | /// `self` will become `Vec<Vec<i32>>`. |
@@ -711,6 +918,12 @@ impl TypeDeclRef { |
711 | 918 | } |
712 | 919 | } |
713 | 920 |
|
| 921 | +impl From<LiteralTy> for Ty { |
| 922 | + fn from(lit: LiteralTy) -> Ty { |
| 923 | + TyKind::Literal(lit).into_ty() |
| 924 | + } |
| 925 | +} |
| 926 | + |
714 | 927 | impl TraitDeclRef { |
715 | 928 | pub fn self_ty<'a>(&'a self, krate: &'a TranslatedCrate) -> Option<&'a Ty> { |
716 | 929 | match self.generics.types.iter().next() { |
|
0 commit comments