microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
compiler/qsc_hir/src/ty.rs
782lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use indenter::{indented, Indented}; |
| 5 | use qsc_data_structures::span::Span; |
| 6 | use rustc_hash::FxHashMap; |
| 7 | |
| 8 | use crate::hir::{CallableKind, FieldPath, Functor, ItemId, PackageId, Res}; |
| 9 | use std::{ |
| 10 | fmt::{self, Debug, Display, Formatter, Write}, |
| 11 | rc::Rc, |
| 12 | }; |
| 13 | |
| 14 | fn set_indentation<'a, 'b>( |
| 15 | indent: Indented<'a, Formatter<'b>>, |
| 16 | level: usize, |
| 17 | ) -> Indented<'a, Formatter<'b>> { |
| 18 | match level { |
| 19 | 0 => indent.with_str(""), |
| 20 | 1 => indent.with_str(" "), |
| 21 | 2 => indent.with_str(" "), |
| 22 | _ => unimplemented!("intentation level not supported"), |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | /// A type. |
| 27 | #[derive(Clone, Debug, Default, Eq, PartialEq)] |
| 28 | pub enum Ty { |
| 29 | /// An array type. |
| 30 | Array(Box<Ty>), |
| 31 | /// An arrow type: `->` for a function or `=>` for an operation. |
| 32 | Arrow(Box<Arrow>), |
| 33 | /// A placeholder type variable used during type inference. |
| 34 | Infer(InferTyId), |
| 35 | /// A type parameter. |
| 36 | Param(Rc<str>, ParamId), |
| 37 | /// A primitive type. |
| 38 | Prim(Prim), |
| 39 | /// A tuple type. |
| 40 | Tuple(Vec<Ty>), |
| 41 | /// A user-defined type. |
| 42 | Udt(Rc<str>, Res), |
| 43 | /// An invalid type. |
| 44 | #[default] |
| 45 | Err, |
| 46 | } |
| 47 | |
| 48 | impl Ty { |
| 49 | /// The unit type. |
| 50 | pub const UNIT: Self = Self::Tuple(Vec::new()); |
| 51 | |
| 52 | #[must_use] |
| 53 | pub fn with_package(&self, package: PackageId) -> Self { |
| 54 | match self { |
| 55 | Ty::Infer(_) | Ty::Param(_, _) | Ty::Prim(_) | Ty::Err => self.clone(), |
| 56 | Ty::Array(item) => Ty::Array(Box::new(item.with_package(package))), |
| 57 | Ty::Arrow(arrow) => Ty::Arrow(Box::new(arrow.with_package(package))), |
| 58 | Ty::Tuple(items) => Ty::Tuple( |
| 59 | items |
| 60 | .iter() |
| 61 | .map(|item| item.with_package(package)) |
| 62 | .collect(), |
| 63 | ), |
| 64 | Ty::Udt(name, res) => Ty::Udt(name.clone(), res.with_package(package)), |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | pub fn display(&self) -> String { |
| 69 | match self { |
| 70 | Ty::Array(item) => { |
| 71 | format!("{}[]", item.display()) |
| 72 | } |
| 73 | Ty::Arrow(arrow) => { |
| 74 | let arrow_symbol = match arrow.kind { |
| 75 | CallableKind::Function => "->", |
| 76 | CallableKind::Operation => "=>", |
| 77 | }; |
| 78 | |
| 79 | let functors = match arrow.functors { |
| 80 | FunctorSet::Value(FunctorSetValue::Empty) |
| 81 | | FunctorSet::Param(_, FunctorSetValue::Empty) => String::new(), |
| 82 | FunctorSet::Value(_) | FunctorSet::Infer(_) => { |
| 83 | format!(" is {}", arrow.functors) |
| 84 | } |
| 85 | FunctorSet::Param(_, functors) => { |
| 86 | format!(" is {functors}") |
| 87 | } |
| 88 | }; |
| 89 | format!( |
| 90 | "({} {arrow_symbol} {}{functors})", |
| 91 | arrow.input.display(), |
| 92 | arrow.output.display() |
| 93 | ) |
| 94 | } |
| 95 | Ty::Infer(_) | Ty::Err => "?".to_string(), |
| 96 | Ty::Param(name, _) | Ty::Udt(name, _) => name.to_string(), |
| 97 | Ty::Prim(prim) => format!("{prim:?}"), |
| 98 | Ty::Tuple(items) => { |
| 99 | if items.is_empty() { |
| 100 | "Unit".to_string() |
| 101 | } else if items.len() == 1 { |
| 102 | let item = items.first().expect("expected single item"); |
| 103 | format!("({},)", item.display()) |
| 104 | } else { |
| 105 | let items = items.iter().map(Ty::display).collect::<Vec<_>>().join(", "); |
| 106 | format!("({items})") |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | impl Display for Ty { |
| 114 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 115 | match self { |
| 116 | Ty::Array(item) => write!(f, "{item}[]"), |
| 117 | Ty::Arrow(arrow) => Display::fmt(arrow, f), |
| 118 | Ty::Infer(infer) => Display::fmt(infer, f), |
| 119 | Ty::Param(name, param_id) => { |
| 120 | write!(f, "Param<\"{name}\": {param_id}>") |
| 121 | } |
| 122 | Ty::Prim(prim) => Debug::fmt(prim, f), |
| 123 | Ty::Tuple(items) => { |
| 124 | if items.is_empty() { |
| 125 | f.write_str("Unit") |
| 126 | } else { |
| 127 | f.write_char('(')?; |
| 128 | if let Some((first, rest)) = items.split_first() { |
| 129 | Display::fmt(first, f)?; |
| 130 | if rest.is_empty() { |
| 131 | f.write_char(',')?; |
| 132 | } else { |
| 133 | for item in rest { |
| 134 | f.write_str(", ")?; |
| 135 | Display::fmt(item, f)?; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | f.write_str(")") |
| 140 | } |
| 141 | } |
| 142 | Ty::Udt(name, res) => { |
| 143 | write!(f, "UDT<\"{name}\": {res}>") |
| 144 | } |
| 145 | Ty::Err => f.write_char('?'), |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | /// A type scheme. |
| 151 | pub struct Scheme { |
| 152 | params: Vec<GenericParam>, |
| 153 | ty: Box<Arrow>, |
| 154 | } |
| 155 | |
| 156 | impl Scheme { |
| 157 | /// Creates a new type scheme. |
| 158 | #[must_use] |
| 159 | pub fn new(params: Vec<GenericParam>, ty: Box<Arrow>) -> Self { |
| 160 | Self { params, ty } |
| 161 | } |
| 162 | |
| 163 | #[must_use] |
| 164 | pub fn with_package(&self, package: PackageId) -> Self { |
| 165 | Self { |
| 166 | params: self.params.clone(), |
| 167 | ty: Box::new(Arrow { |
| 168 | kind: self.ty.kind, |
| 169 | input: Box::new(self.ty.input.with_package(package)), |
| 170 | output: Box::new(self.ty.output.with_package(package)), |
| 171 | functors: self.ty.functors, |
| 172 | }), |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | /// The generic parameters to the type. |
| 177 | #[must_use] |
| 178 | pub fn params(&self) -> &[GenericParam] { |
| 179 | &self.params |
| 180 | } |
| 181 | |
| 182 | /// Instantiates this type scheme with the given arguments. |
| 183 | /// |
| 184 | /// # Errors |
| 185 | /// |
| 186 | /// Returns an error if the given arguments do not match the scheme parameters. |
| 187 | pub fn instantiate(&self, args: &[GenericArg]) -> Result<Arrow, InstantiationError> { |
| 188 | if args.len() == self.params.len() { |
| 189 | let args: FxHashMap<_, _> = self |
| 190 | .params |
| 191 | .iter() |
| 192 | .enumerate() |
| 193 | .map(|(ix, _)| ParamId::from(ix)) |
| 194 | .zip(args) |
| 195 | .collect(); |
| 196 | instantiate_arrow_ty(|name| args.get(name).copied(), &self.ty) |
| 197 | } else { |
| 198 | Err(InstantiationError::Arity) |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | /// A type scheme instantiation error. |
| 204 | #[derive(Debug)] |
| 205 | pub enum InstantiationError { |
| 206 | /// The number of generic arguments does not match the number of generic parameters. |
| 207 | Arity, |
| 208 | /// A generic argument does not match the kind of its corresponding generic parameter. |
| 209 | Kind(ParamId), |
| 210 | } |
| 211 | |
| 212 | fn instantiate_ty<'a>( |
| 213 | arg: impl Fn(&ParamId) -> Option<&'a GenericArg> + Copy, |
| 214 | ty: &Ty, |
| 215 | ) -> Result<Ty, InstantiationError> { |
| 216 | match ty { |
| 217 | Ty::Err | Ty::Infer(_) | Ty::Prim(_) | Ty::Udt(_, _) => Ok(ty.clone()), |
| 218 | Ty::Array(item) => Ok(Ty::Array(Box::new(instantiate_ty(arg, item)?))), |
| 219 | Ty::Arrow(arrow) => Ok(Ty::Arrow(Box::new(instantiate_arrow_ty(arg, arrow)?))), |
| 220 | Ty::Param(_, param) => match arg(param) { |
| 221 | Some(GenericArg::Ty(ty_arg)) => Ok(ty_arg.clone()), |
| 222 | Some(_) => Err(InstantiationError::Kind(*param)), |
| 223 | None => Ok(ty.clone()), |
| 224 | }, |
| 225 | Ty::Tuple(items) => Ok(Ty::Tuple( |
| 226 | items |
| 227 | .iter() |
| 228 | .map(|item| instantiate_ty(arg, item)) |
| 229 | .collect::<Result<_, _>>()?, |
| 230 | )), |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | fn instantiate_arrow_ty<'a>( |
| 235 | arg: impl Fn(&ParamId) -> Option<&'a GenericArg> + Copy, |
| 236 | arrow: &Arrow, |
| 237 | ) -> Result<Arrow, InstantiationError> { |
| 238 | let input = instantiate_ty(arg, &arrow.input)?; |
| 239 | let output = instantiate_ty(arg, &arrow.output)?; |
| 240 | let functors = if let FunctorSet::Param(param, _) = arrow.functors { |
| 241 | match arg(¶m) { |
| 242 | Some(GenericArg::Functor(functor_arg)) => *functor_arg, |
| 243 | Some(_) => return Err(InstantiationError::Kind(param)), |
| 244 | None => arrow.functors, |
| 245 | } |
| 246 | } else { |
| 247 | arrow.functors |
| 248 | }; |
| 249 | |
| 250 | Ok(Arrow { |
| 251 | kind: arrow.kind, |
| 252 | input: Box::new(input), |
| 253 | output: Box::new(output), |
| 254 | functors, |
| 255 | }) |
| 256 | } |
| 257 | |
| 258 | impl Display for GenericParam { |
| 259 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 260 | match self { |
| 261 | GenericParam::Ty(name) => write!(f, "type {name}"), |
| 262 | GenericParam::Functor(min) => write!(f, "functor ({min})"), |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /// The kind of a generic parameter. |
| 268 | #[derive(Clone, Debug, PartialEq)] |
| 269 | pub enum GenericParam { |
| 270 | /// A type parameter. |
| 271 | Ty(TypeParamName), |
| 272 | /// A functor parameter with a lower bound. |
| 273 | Functor(FunctorSetValue), |
| 274 | } |
| 275 | |
| 276 | /// The name of a generic type parameter. |
| 277 | #[derive(Clone, Debug, PartialEq)] |
| 278 | pub struct TypeParamName { |
| 279 | /// The span. |
| 280 | pub span: Span, |
| 281 | /// The name. |
| 282 | pub name: Rc<str>, |
| 283 | } |
| 284 | |
| 285 | impl Display for TypeParamName { |
| 286 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 287 | write!(f, "{} \"{}\"", self.span, self.name) |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | /// A generic parameter ID. |
| 292 | #[derive(Clone, Copy, Default, Debug, Eq, Hash, PartialEq)] |
| 293 | pub struct ParamId(u32); |
| 294 | |
| 295 | impl ParamId { |
| 296 | /// The successor of this ID. |
| 297 | #[must_use] |
| 298 | pub fn successor(self) -> Self { |
| 299 | Self(self.0 + 1) |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | impl From<usize> for ParamId { |
| 304 | fn from(value: usize) -> Self { |
| 305 | ParamId( |
| 306 | value |
| 307 | .try_into() |
| 308 | .expect("Type Parameter ID does not fit into u32"), |
| 309 | ) |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | impl From<ParamId> for usize { |
| 314 | fn from(value: ParamId) -> Self { |
| 315 | value.0 as usize |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | impl Display for ParamId { |
| 320 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 321 | Display::fmt(&self.0, f) |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | /// An argument to a generic parameter. |
| 326 | #[derive(Clone, Debug, Eq, PartialEq)] |
| 327 | pub enum GenericArg { |
| 328 | /// A type argument. |
| 329 | Ty(Ty), |
| 330 | /// A functor argument. |
| 331 | Functor(FunctorSet), |
| 332 | } |
| 333 | |
| 334 | impl Display for GenericArg { |
| 335 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 336 | match self { |
| 337 | GenericArg::Ty(ty) => Display::fmt(ty, f), |
| 338 | GenericArg::Functor(functors) => Display::fmt(functors, f), |
| 339 | } |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | /// An arrow type: `->` for a function or `=>` for an operation. |
| 344 | #[derive(Clone, Debug, Eq, PartialEq)] |
| 345 | pub struct Arrow { |
| 346 | /// Whether the callable is a function or an operation. |
| 347 | pub kind: CallableKind, |
| 348 | /// The input type to the callable. |
| 349 | pub input: Box<Ty>, |
| 350 | /// The output type from the callable. |
| 351 | pub output: Box<Ty>, |
| 352 | /// The functors supported by the callable. |
| 353 | pub functors: FunctorSet, |
| 354 | } |
| 355 | |
| 356 | impl Arrow { |
| 357 | #[must_use] |
| 358 | pub fn with_package(&self, package: PackageId) -> Self { |
| 359 | Self { |
| 360 | kind: self.kind, |
| 361 | input: Box::new(self.input.with_package(package)), |
| 362 | output: Box::new(self.output.with_package(package)), |
| 363 | functors: self.functors, |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | impl Display for Arrow { |
| 369 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 370 | let arrow = match self.kind { |
| 371 | CallableKind::Function => "->", |
| 372 | CallableKind::Operation => "=>", |
| 373 | }; |
| 374 | write!(f, "({} {arrow} {}", self.input, self.output)?; |
| 375 | if self.functors != FunctorSet::Value(FunctorSetValue::Empty) { |
| 376 | f.write_str(" is ")?; |
| 377 | Display::fmt(&self.functors, f)?; |
| 378 | } |
| 379 | f.write_char(')') |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | /// A primitive type. |
| 384 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
| 385 | pub enum Prim { |
| 386 | /// The big integer type. |
| 387 | BigInt, |
| 388 | /// The boolean type. |
| 389 | Bool, |
| 390 | /// The floating-point type. |
| 391 | Double, |
| 392 | /// The integer type. |
| 393 | Int, |
| 394 | /// The Pauli operator type. |
| 395 | Pauli, |
| 396 | /// The qubit type. |
| 397 | Qubit, |
| 398 | /// The range type. |
| 399 | Range, |
| 400 | /// The range type without a lower bound. |
| 401 | RangeTo, |
| 402 | /// The range type without an upper bound. |
| 403 | RangeFrom, |
| 404 | /// The range type without lower and upper bounds. |
| 405 | RangeFull, |
| 406 | /// The measurement result type. |
| 407 | Result, |
| 408 | /// The string type. |
| 409 | String, |
| 410 | } |
| 411 | |
| 412 | /// A set of functors. |
| 413 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 414 | pub enum FunctorSet { |
| 415 | /// An evaluated set. |
| 416 | Value(FunctorSetValue), |
| 417 | /// A functor parameter. |
| 418 | Param(ParamId, FunctorSetValue), |
| 419 | /// A placeholder functor variable used during type inference. |
| 420 | Infer(InferFunctorId), |
| 421 | } |
| 422 | |
| 423 | impl FunctorSet { |
| 424 | /// Returns the contained value. |
| 425 | /// |
| 426 | /// # Panics |
| 427 | /// |
| 428 | /// Panics if this set is not a value. |
| 429 | #[must_use] |
| 430 | pub fn expect_value(self, msg: &str) -> FunctorSetValue { |
| 431 | match self { |
| 432 | Self::Value(value) => value, |
| 433 | Self::Param(_, _) | Self::Infer(_) => panic!("{msg}"), |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | impl Display for FunctorSet { |
| 439 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 440 | match self { |
| 441 | Self::Value(value) => Display::fmt(value, f), |
| 442 | Self::Param(param, _) => write!(f, "Param<{param}>"), |
| 443 | Self::Infer(infer) => Display::fmt(infer, f), |
| 444 | } |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | /// The value of a functor set. |
| 449 | #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] |
| 450 | pub enum FunctorSetValue { |
| 451 | /// The empty set. |
| 452 | #[default] |
| 453 | Empty, |
| 454 | /// The singleton adjoint set. |
| 455 | Adj, |
| 456 | /// The singleton controlled set. |
| 457 | Ctl, |
| 458 | /// The set of controlled and adjoint. |
| 459 | CtlAdj, |
| 460 | } |
| 461 | |
| 462 | impl FunctorSetValue { |
| 463 | /// True if this set contains the functor. |
| 464 | #[must_use] |
| 465 | pub fn contains(&self, functor: &Functor) -> bool { |
| 466 | match self { |
| 467 | Self::Empty => false, |
| 468 | Self::Adj => matches!(functor, Functor::Adj), |
| 469 | Self::Ctl => matches!(functor, Functor::Ctl), |
| 470 | Self::CtlAdj => matches!(functor, Functor::Adj | Functor::Ctl), |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | /// The intersection of this set and another set. |
| 475 | #[must_use] |
| 476 | pub fn intersect(&self, other: &Self) -> Self { |
| 477 | match (self, other) { |
| 478 | (Self::Empty, _) |
| 479 | | (_, Self::Empty) |
| 480 | | (Self::Adj, Self::Ctl) |
| 481 | | (Self::Ctl, Self::Adj) => Self::Empty, |
| 482 | (Self::Adj, Self::Adj) => Self::Adj, |
| 483 | (Self::Ctl, Self::Ctl) => Self::Ctl, |
| 484 | (Self::CtlAdj, &set) | (&set, Self::CtlAdj) => set, |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | /// The union of this set and another set. |
| 489 | #[must_use] |
| 490 | pub fn union(&self, other: &Self) -> Self { |
| 491 | match (self, other) { |
| 492 | (Self::Empty, &set) | (&set, Self::Empty) => set, |
| 493 | (Self::Adj, Self::Adj) => Self::Adj, |
| 494 | (Self::Ctl, Self::Ctl) => Self::Ctl, |
| 495 | (Self::CtlAdj, _) |
| 496 | | (_, Self::CtlAdj) |
| 497 | | (Self::Adj, Self::Ctl) |
| 498 | | (Self::Ctl, Self::Adj) => Self::CtlAdj, |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | #[must_use] |
| 503 | pub fn satisfies(&self, other: &Self) -> bool { |
| 504 | matches!( |
| 505 | (self, other), |
| 506 | (_, Self::Empty) |
| 507 | | (Self::Adj | Self::CtlAdj, Self::Adj) |
| 508 | | (Self::Ctl | Self::CtlAdj, Self::Ctl) |
| 509 | | (Self::CtlAdj, Self::CtlAdj) |
| 510 | ) |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | impl Display for FunctorSetValue { |
| 515 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 516 | match self { |
| 517 | Self::Empty => f.write_str("empty set"), |
| 518 | Self::Adj => f.write_str("Adj"), |
| 519 | Self::Ctl => f.write_str("Ctl"), |
| 520 | Self::CtlAdj => f.write_str("Adj + Ctl"), |
| 521 | } |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | /// A user-defined type. |
| 526 | #[derive(Clone, Debug, PartialEq)] |
| 527 | pub struct Udt { |
| 528 | /// The span. |
| 529 | pub span: Span, |
| 530 | /// The name. |
| 531 | pub name: Rc<str>, |
| 532 | // The definition. |
| 533 | pub definition: UdtDef, |
| 534 | } |
| 535 | |
| 536 | impl Udt { |
| 537 | #[must_use] |
| 538 | pub fn get_pure_ty(&self) -> Ty { |
| 539 | fn get_pure_ty(def: &UdtDef) -> Ty { |
| 540 | match &def.kind { |
| 541 | UdtDefKind::Field(field) => field.ty.clone(), |
| 542 | UdtDefKind::Tuple(tup) => Ty::Tuple(tup.iter().map(get_pure_ty).collect()), |
| 543 | } |
| 544 | } |
| 545 | get_pure_ty(&self.definition) |
| 546 | } |
| 547 | |
| 548 | /// The type scheme of the constructor for this type definition. |
| 549 | /// |
| 550 | /// # Arguments |
| 551 | /// |
| 552 | /// * `id` - The ID of the constructed type. |
| 553 | #[must_use] |
| 554 | pub fn cons_scheme(&self, id: ItemId) -> Scheme { |
| 555 | Scheme { |
| 556 | params: Vec::new(), |
| 557 | ty: Box::new(Arrow { |
| 558 | kind: CallableKind::Function, |
| 559 | input: Box::new(self.get_pure_ty()), |
| 560 | output: Box::new(Ty::Udt(self.name.clone(), Res::Item(id))), |
| 561 | functors: FunctorSet::Value(FunctorSetValue::Empty), |
| 562 | }), |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | /// The path to the field with the given name. Returns [None] if this user-defined type does not |
| 567 | /// have a field with the given name. |
| 568 | #[must_use] |
| 569 | pub fn field_path(&self, name: &str) -> Option<FieldPath> { |
| 570 | Self::find_field_path(&self.definition, name) |
| 571 | } |
| 572 | |
| 573 | fn find_field_path(def: &UdtDef, name: &str) -> Option<FieldPath> { |
| 574 | match &def.kind { |
| 575 | UdtDefKind::Field(field) => field.name.as_ref().and_then(|field_name| { |
| 576 | if field_name.as_ref() == name { |
| 577 | Some(FieldPath::default()) |
| 578 | } else { |
| 579 | None |
| 580 | } |
| 581 | }), |
| 582 | UdtDefKind::Tuple(defs) => defs.iter().enumerate().find_map(|(i, def)| { |
| 583 | Self::find_field_path(def, name).map(|mut path| { |
| 584 | path.indices.insert(0, i); |
| 585 | path |
| 586 | }) |
| 587 | }), |
| 588 | } |
| 589 | } |
| 590 | |
| 591 | fn find_field(&self, path: &FieldPath) -> Option<&UdtField> { |
| 592 | let mut udt_def = &self.definition; |
| 593 | for &index in &path.indices { |
| 594 | let UdtDefKind::Tuple(items) = &udt_def.kind else { |
| 595 | return None; |
| 596 | }; |
| 597 | udt_def = &items[index]; |
| 598 | } |
| 599 | let UdtDefKind::Field(field) = &udt_def.kind else { |
| 600 | return None; |
| 601 | }; |
| 602 | Some(field) |
| 603 | } |
| 604 | |
| 605 | /// The field with the given name. Returns [None] if this user-defined type does not |
| 606 | /// have a field with the given name. |
| 607 | #[must_use] |
| 608 | pub fn find_field_by_name(&self, name: &str) -> Option<&UdtField> { |
| 609 | Self::find_field_by_name_rec(&self.definition, name) |
| 610 | } |
| 611 | |
| 612 | fn find_field_by_name_rec<'a>(def: &'a UdtDef, name: &str) -> Option<&'a UdtField> { |
| 613 | match &def.kind { |
| 614 | UdtDefKind::Field(field) => field.name.as_ref().and_then(|field_name| { |
| 615 | if field_name.as_ref() == name { |
| 616 | Some(field) |
| 617 | } else { |
| 618 | None |
| 619 | } |
| 620 | }), |
| 621 | UdtDefKind::Tuple(defs) => defs |
| 622 | .iter() |
| 623 | .find_map(|def| Self::find_field_by_name_rec(def, name)), |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | /// The type of the field at the given path. Returns [None] if the path is not valid for this |
| 628 | /// user-defined type. |
| 629 | #[must_use] |
| 630 | pub fn field_ty(&self, path: &FieldPath) -> Option<&Ty> { |
| 631 | self.find_field(path).map(|field| &field.ty) |
| 632 | } |
| 633 | |
| 634 | /// The type of the field with the given name. Returns [None] if this user-defined type does not |
| 635 | /// have a field with the given name. |
| 636 | #[must_use] |
| 637 | pub fn field_ty_by_name(&self, name: &str) -> Option<&Ty> { |
| 638 | self.find_field_by_name(name).map(|field| &field.ty) |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | impl Display for Udt { |
| 643 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 644 | let mut indent = set_indentation(indented(f), 0); |
| 645 | write!(indent, "UDT {}:", self.span)?; |
| 646 | indent = set_indentation(indent, 1); |
| 647 | write!(indent, "\n{}", self.definition)?; |
| 648 | Ok(()) |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | /// A UDT type definition. |
| 653 | #[derive(Clone, Debug, PartialEq)] |
| 654 | pub struct UdtDef { |
| 655 | /// The span. |
| 656 | pub span: Span, |
| 657 | /// The type definition kind. |
| 658 | pub kind: UdtDefKind, |
| 659 | } |
| 660 | |
| 661 | impl Display for UdtDef { |
| 662 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 663 | write!(f, "TyDef {}: {}", self.span, self.kind) |
| 664 | } |
| 665 | } |
| 666 | |
| 667 | /// A UDT type definition kind. |
| 668 | #[derive(Clone, Debug, PartialEq)] |
| 669 | pub enum UdtDefKind { |
| 670 | /// A field definition with an optional name but required type. |
| 671 | Field(UdtField), |
| 672 | /// A tuple. |
| 673 | Tuple(Vec<UdtDef>), |
| 674 | } |
| 675 | |
| 676 | impl Display for UdtDefKind { |
| 677 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 678 | let mut indent = set_indentation(indented(f), 0); |
| 679 | match &self { |
| 680 | UdtDefKind::Field(field) => { |
| 681 | write!(indent, "Field:")?; |
| 682 | indent = set_indentation(indent, 1); |
| 683 | write!(indent, "{field}")?; |
| 684 | } |
| 685 | UdtDefKind::Tuple(ts) => { |
| 686 | if ts.is_empty() { |
| 687 | write!(indent, "Unit")?; |
| 688 | } else { |
| 689 | write!(indent, "Tuple:")?; |
| 690 | indent = set_indentation(indent, 1); |
| 691 | for t in ts { |
| 692 | write!(indent, "\n{t}")?; |
| 693 | } |
| 694 | } |
| 695 | } |
| 696 | } |
| 697 | Ok(()) |
| 698 | } |
| 699 | } |
| 700 | |
| 701 | /// A user-defined type. |
| 702 | #[derive(Clone, Debug, PartialEq)] |
| 703 | pub struct UdtField { |
| 704 | /// The span of the field name. |
| 705 | pub name_span: Option<Span>, |
| 706 | /// The field name. |
| 707 | pub name: Option<Rc<str>>, |
| 708 | // The field type. |
| 709 | pub ty: Ty, |
| 710 | } |
| 711 | |
| 712 | impl Display for UdtField { |
| 713 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 714 | if let Some(n) = &self.name { |
| 715 | if let Some(s) = &self.name_span { |
| 716 | write!(f, "\nname: {n} {s}")?; |
| 717 | } |
| 718 | } |
| 719 | write!(f, "\ntype: {}", self.ty)?; |
| 720 | Ok(()) |
| 721 | } |
| 722 | } |
| 723 | |
| 724 | /// A placeholder type variable used during type inference. |
| 725 | #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] |
| 726 | pub struct InferTyId(usize); |
| 727 | |
| 728 | impl InferTyId { |
| 729 | /// The successor of this ID. |
| 730 | #[must_use] |
| 731 | pub fn successor(self) -> Self { |
| 732 | Self(self.0 + 1) |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | impl Display for InferTyId { |
| 737 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 738 | write!(f, "?{}", self.0) |
| 739 | } |
| 740 | } |
| 741 | |
| 742 | impl From<usize> for InferTyId { |
| 743 | fn from(value: usize) -> Self { |
| 744 | Self(value) |
| 745 | } |
| 746 | } |
| 747 | |
| 748 | impl From<InferTyId> for usize { |
| 749 | fn from(value: InferTyId) -> Self { |
| 750 | value.0 |
| 751 | } |
| 752 | } |
| 753 | |
| 754 | /// A placeholder functor variable used during type inference. |
| 755 | #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] |
| 756 | pub struct InferFunctorId(usize); |
| 757 | |
| 758 | impl InferFunctorId { |
| 759 | /// The successor of this ID. |
| 760 | #[must_use] |
| 761 | pub fn successor(self) -> Self { |
| 762 | Self(self.0 + 1) |
| 763 | } |
| 764 | } |
| 765 | |
| 766 | impl Display for InferFunctorId { |
| 767 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| 768 | write!(f, "f?{}", self.0) |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | impl From<usize> for InferFunctorId { |
| 773 | fn from(value: usize) -> Self { |
| 774 | InferFunctorId(value) |
| 775 | } |
| 776 | } |
| 777 | |
| 778 | impl From<InferFunctorId> for usize { |
| 779 | fn from(value: InferFunctorId) -> Self { |
| 780 | value.0 |
| 781 | } |
| 782 | } |
| 783 | |