1use super::prelude::*;
2
3pub(super) fn resolve_local(locals: &[(String, Ty)], name: &str) -> Result<Ty, ElabError> {
4 locals
5 .iter()
6 .rev()
7 .find_map(|(local, ty)| {
8 if local == name {
9 Some(ty.clone())
10 } else {
11 None
12 }
13 })
14 .ok_or_else(|| ElabError::UnknownIdentifier {
15 name: name.to_owned(),
16 })
17}
18
19pub(super) fn split_variant_path(path: &str) -> Option<(&str, &str)> {
20 let (head, tail) = path.split_once("::")?;
21 if tail.contains("::") {
22 return None;
23 }
24 Some((head, tail))
25}
26
27pub(super) fn is_type_param(param: &Param) -> bool {
28 param.ty.mode == OwnershipMode::View && matches!(param.ty.ty, TypeExpr::TypeKind)
29}
30
31pub(super) fn is_runtime_template(params: &[Param]) -> bool {
32 params
33 .iter()
34 .any(|param| is_type_param(param) || param.is_meta || param.is_variadic)
35}
36
37pub(super) fn type_param_names(params: &[Param]) -> Vec<String> {
38 params
39 .iter()
40 .filter(|param| is_type_param(param))
41 .map(|param| param.name.clone())
42 .collect()
43}
44
45pub(super) fn has_meta_params(params: &[Param]) -> bool {
46 params.iter().any(|param| param.is_meta)
47}
48
49pub(super) fn variadic_param_name(
50 name: &str,
51 params: &[Param],
52) -> Result<Option<String>, ElabError> {
53 let mut variadic = None;
54 for (index, param) in params.iter().enumerate() {
55 if !param.is_variadic {
56 continue;
57 }
58 if variadic.is_some() {
59 return Err(ElabError::MultipleVariadicParams {
60 name: name.to_owned(),
61 });
62 }
63 if index + 1 != params.len() {
64 return Err(ElabError::InvalidVariadicParam {
65 name: name.to_owned(),
66 });
67 }
68 if !matches!(¶m.ty.ty, TypeExpr::Named(any_name) if any_name == "any") {
69 return Err(ElabError::InvalidVariadicParam {
70 name: name.to_owned(),
71 });
72 }
73 variadic = Some(param.name.clone());
74 }
75 Ok(variadic)
76}
77
78pub(super) fn runtime_params(params: &[Param]) -> Vec<Param> {
79 params
80 .iter()
81 .filter(|param| !is_type_param(param) && !param.is_meta)
82 .cloned()
83 .collect()
84}
85
86pub(super) fn canonical_nominal_name(ty: &Ty) -> String {
87 let (name, args) = match ty {
88 Ty::Struct { name, args } | Ty::Enum { name, args } => (name, args),
89 _ => {
90 return ty.to_string();
91 }
92 };
93 if args.is_empty() {
94 name.clone()
95 } else {
96 let rendered = args
97 .iter()
98 .map(render_type_name)
99 .collect::<Vec<_>>()
100 .join(", ");
101 format!("{name}[{rendered}]")
102 }
103}
104
105pub(super) fn render_type_name(ty: &Ty) -> String {
106 match ty {
107 Ty::Unit => "Unit".to_owned(),
108 Ty::U8 => "u8".to_owned(),
109 Ty::U16 => "u16".to_owned(),
110 Ty::U32 => "u32".to_owned(),
111 Ty::U64 => "u64".to_owned(),
112 Ty::I8 => "i8".to_owned(),
113 Ty::I16 => "i16".to_owned(),
114 Ty::I32 => "i32".to_owned(),
115 Ty::I64 => "i64".to_owned(),
116 Ty::F32 => "f32".to_owned(),
117 Ty::F64 => "f64".to_owned(),
118 Ty::String => "String".to_owned(),
119 Ty::Bool => "Bool".to_owned(),
120 Ty::Pointer(item) => format!("*{}", render_type_name(item)),
121 Ty::Option(item) => format!("Option[{}]", render_type_name(item)),
122 Ty::Array { item, len } => format!("[{}; {}]", render_type_name(item), len),
123 Ty::Slice(item) => format!("[{}]", render_type_name(item)),
124 Ty::Tuple(items) => {
125 let mut rendered = items
126 .iter()
127 .map(render_type_name)
128 .collect::<Vec<_>>()
129 .join(", ");
130 if items.len() == 1 {
131 rendered.push(',');
132 }
133 format!("({rendered})")
134 }
135 Ty::Struct { .. } | Ty::Enum { .. } => canonical_nominal_name(ty),
136 Ty::RefRo(_) | Ty::RefMut(_) => {
137 panic!("reference types are not valid in canonical runtime type names")
138 }
139 }
140}
141
142pub(super) fn ty_to_type_expr(ty: &Ty) -> TypeExpr {
144 match ty {
145 Ty::Unit => TypeExpr::Named("Unit".to_owned()),
146 Ty::U8 => TypeExpr::Named("u8".to_owned()),
147 Ty::U16 => TypeExpr::Named("u16".to_owned()),
148 Ty::U32 => TypeExpr::Named("u32".to_owned()),
149 Ty::U64 => TypeExpr::Named("u64".to_owned()),
150 Ty::I8 => TypeExpr::Named("i8".to_owned()),
151 Ty::I16 => TypeExpr::Named("i16".to_owned()),
152 Ty::I32 => TypeExpr::Named("i32".to_owned()),
153 Ty::I64 => TypeExpr::Named("i64".to_owned()),
154 Ty::F32 => TypeExpr::Named("f32".to_owned()),
155 Ty::F64 => TypeExpr::Named("f64".to_owned()),
156 Ty::String => TypeExpr::Named("String".to_owned()),
157 Ty::Bool => TypeExpr::Named("Bool".to_owned()),
158 Ty::Pointer(item) => TypeExpr::Pointer {
159 item: Box::new(ty_to_type_expr(item)),
160 },
161 Ty::Option(item) => TypeExpr::Apply {
162 callee: "Option".to_owned(),
163 args: vec![ty_to_type_expr(item)],
164 },
165 Ty::Array { item, len } => TypeExpr::Array {
166 item: Box::new(ty_to_type_expr(item)),
167 len: *len,
168 },
169 Ty::Slice(item) => TypeExpr::Slice {
170 item: Box::new(ty_to_type_expr(item)),
171 },
172 Ty::Tuple(items) => TypeExpr::Tuple(items.iter().map(ty_to_type_expr).collect()),
173 Ty::Struct { .. } | Ty::Enum { .. } => TypeExpr::Named(canonical_nominal_name(ty)),
174 Ty::RefRo(_) | Ty::RefMut(_) => {
175 panic!("reference types are not valid in runtime type expression rewriting")
176 }
177 }
178}