swamp_analyzer/
context.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use swamp_types::{TypeKind, TypeRef};
7
8/// `TypeRef` checking context
9#[derive(Debug, Clone)]
10pub struct TypeContext<'a> {
11    /// Expected type for the current expression
12    pub expected_type: Option<&'a TypeRef>,
13    pub has_lvalue_target: bool,
14    pub ephemeral_is_allowed: bool,
15}
16
17impl<'a> TypeContext<'a> {
18    #[must_use]
19    pub const fn new(expected_type: Option<&'a TypeRef>, has_lvalue_target: bool) -> Self {
20        Self {
21            expected_type,
22            has_lvalue_target,
23            ephemeral_is_allowed: false,
24        }
25    }
26
27    pub(crate) const fn with_lvalue(&self) -> Self {
28        Self {
29            expected_type: self.expected_type,
30            has_lvalue_target: true,
31            ephemeral_is_allowed: false,
32        }
33    }
34
35    pub(crate) const fn with_ephemeral(&self) -> TypeContext {
36        Self {
37            expected_type: self.expected_type,
38            has_lvalue_target: self.has_lvalue_target,
39            ephemeral_is_allowed: true,
40        }
41    }
42
43    pub(crate) const fn argument(&self, expected_type: &'a TypeRef) -> Self {
44        Self {
45            expected_type: Some(expected_type),
46            has_lvalue_target: self.has_lvalue_target,
47            ephemeral_is_allowed: false,
48        }
49    }
50
51    pub(crate) const fn with_argument_anything(&self) -> Self {
52        Self {
53            expected_type: None,
54            has_lvalue_target: self.has_lvalue_target,
55            ephemeral_is_allowed: false,
56        }
57    }
58
59    #[must_use]
60    pub const fn new_argument(required_type: &'a TypeRef, has_lvalue_target: bool) -> Self {
61        Self {
62            expected_type: Some(required_type),
63            has_lvalue_target,
64            ephemeral_is_allowed: false,
65        }
66    }
67
68    pub(crate) const fn new_argument_ephemeral(
69        required_type: &'a TypeRef,
70        has_lvalue_target: bool,
71    ) -> Self {
72        Self {
73            expected_type: Some(required_type),
74            has_lvalue_target,
75            ephemeral_is_allowed: true,
76        }
77    }
78
79    #[must_use]
80    pub const fn new_unsure_argument(
81        expected_type: Option<&'a TypeRef>,
82        has_lvalue_target: bool,
83    ) -> Self {
84        Self {
85            expected_type,
86            has_lvalue_target,
87            ephemeral_is_allowed: false,
88        }
89    }
90
91    #[must_use]
92    pub const fn new_anything_argument(has_lvalue_target: bool) -> Self {
93        Self {
94            expected_type: None,
95            has_lvalue_target,
96            ephemeral_is_allowed: false,
97        }
98    }
99
100    #[must_use]
101    pub fn new_function(required_type: &'a TypeRef) -> Self {
102        Self {
103            expected_type: Some(required_type),
104            has_lvalue_target: required_type.collection_view_that_needs_explicit_storage(),
105            ephemeral_is_allowed: false,
106        }
107    }
108
109    #[must_use]
110    pub const fn with_expected_type(
111        &self,
112        expected_type: Option<&'a TypeRef>,
113        has_lvalue_target: bool,
114    ) -> Self {
115        Self {
116            expected_type,
117            has_lvalue_target,
118            ephemeral_is_allowed: false,
119        }
120    }
121
122    pub(crate) const fn we_know_expected_type(
123        &self,
124        found_type: &'a TypeRef,
125        has_lvalue_target: bool,
126    ) -> Self {
127        self.with_expected_type(Some(found_type), has_lvalue_target)
128    }
129
130    /// If the expected type is `Optional<T>`, returns `T`; otherwise returns the
131    /// original expected type.
132    #[must_use]
133    pub fn expected_type_or_optional_inner(&self) -> Self {
134        #[allow(clippy::bind_instead_of_map)]
135        let new_expected = self
136            .expected_type
137            .and_then(|expected| match expected.kind.as_ref() {
138                TypeKind::Optional(inner) => Some(inner),
139                _ => Some(expected),
140            });
141
142        Self {
143            expected_type: new_expected,
144            has_lvalue_target: self.has_lvalue_target,
145            ephemeral_is_allowed: false,
146        }
147    }
148}