1use source_map::{Span, SpanWithSource};
4
5use crate::context::{environment::ContextLocation, AssignmentError, VariableRegisterArguments};
6use crate::diagnostics::{PropertyKeyRepresentation, TypeCheckError, TypeStringRepresentation};
7use crate::subtyping::{type_is_subtype_object, SubTypeResult};
8use crate::{
9 types::{
10 logical::{Logical, LogicalOrValid},
11 properties::{
12 get_property_key_names_on_a_single_type, get_property_unbound, PropertyKey, Publicity,
13 },
14 TypeId,
15 },
16 CheckingData, VariableId,
17};
18use crate::{Environment, Instance};
19use std::fmt::Debug;
20
21#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
25pub enum VariableOrImport {
26 Variable {
27 mutability: VariableMutability,
29 declared_at: SpanWithSource,
32 context: ContextLocation,
33 allow_reregistration: bool,
34 },
35 MutableImport {
36 of: VariableId,
37 constant: bool,
38 import_specified_at: SpanWithSource,
39 },
40 ConstantImport {
41 to: Option<VariableId>,
42 import_specified_at: SpanWithSource,
43 },
44}
45
46impl VariableOrImport {
47 pub(crate) fn get_id(&self) -> VariableId {
48 match self {
49 VariableOrImport::Variable { mutability: _, declared_at, .. } => {
50 VariableId(declared_at.source, declared_at.start)
51 }
52 VariableOrImport::MutableImport { import_specified_at, .. }
53 | VariableOrImport::ConstantImport { import_specified_at, .. } => {
54 VariableId(import_specified_at.source, import_specified_at.start)
55 }
56 }
57 }
58
59 pub(crate) fn get_mutability(&self) -> VariableMutability {
61 match self {
62 VariableOrImport::Variable { mutability, .. } => *mutability,
63 VariableOrImport::MutableImport { of: _, constant: _, import_specified_at: _ }
65 | VariableOrImport::ConstantImport { to: _, import_specified_at: _ } => {
66 VariableMutability::Constant
67 }
68 }
69 }
70
71 pub(crate) fn get_origin_variable_id(&self) -> VariableId {
72 match self {
73 VariableOrImport::Variable { declared_at: pos, .. }
74 | VariableOrImport::ConstantImport { import_specified_at: pos, .. } => {
75 VariableId(pos.source, pos.start)
76 }
77 VariableOrImport::MutableImport { of, .. } => *of,
78 }
79 }
80}
81
82#[derive(Copy, Clone, Debug, binary_serialize_derive::BinarySerializable)]
84pub enum VariableMutability {
85 Constant,
86 Mutable { reassignment_constraint: Option<TypeId> },
87}
88
89#[derive(Clone, Debug)]
90pub struct VariableWithValue(pub VariableOrImport, pub TypeId);
91
92pub fn check_variable_initialization<T: crate::ReadFromFS, A: crate::ASTImplementation>(
94 (variable_declared_type, variable_declared_pos): (TypeId, SpanWithSource),
95 (expression_type, expression_declared_pos): (TypeId, SpanWithSource),
96 environment: &mut crate::context::Environment,
97 checking_data: &mut CheckingData<T, A>,
98) -> bool {
99 let type_is_subtype = type_is_subtype_object(
100 variable_declared_type,
101 expression_type,
102 environment,
103 &mut checking_data.types,
104 );
105
106 if let SubTypeResult::IsNotSubType(_matches) = type_is_subtype {
107 let error = crate::diagnostics::TypeCheckError::AssignmentError(
108 AssignmentError::DoesNotMeetConstraint {
109 variable_type: crate::diagnostics::TypeStringRepresentation::from_type_id(
110 variable_declared_type,
111 environment,
112 &checking_data.types,
113 checking_data.options.debug_types,
114 ),
115 variable_position: variable_declared_pos,
116 value_type: crate::diagnostics::TypeStringRepresentation::from_type_id(
117 expression_type,
118 environment,
119 &checking_data.types,
120 checking_data.options.debug_types,
121 ),
122 value_position: expression_declared_pos,
123 },
124 );
125
126 checking_data.diagnostics_container.add_error(error);
127 false
128 } else {
129 true
130 }
131}
132
133pub fn get_new_register_argument_under<T: crate::ReadFromFS, A: crate::ASTImplementation>(
134 on: &VariableRegisterArguments,
135 under: &PropertyKey,
136 environment: &mut Environment,
137 checking_data: &mut CheckingData<T, A>,
138 at: Span,
139) -> VariableRegisterArguments {
140 let position = at.with_source(environment.get_source());
141
142 let space = on.space.map(|space| {
143 let property_constraint = get_property_unbound(
144 (space, None),
145 (Publicity::Public, under, None),
146 false,
147 environment,
148 &checking_data.types,
149 );
150 if let Ok(value) = property_constraint {
151 if let LogicalOrValid::Logical(value) = value {
152 match value {
153 Logical::Pure(crate::PropertyValue::Value(value)) => value,
154 Logical::Pure(_) => todo!(),
155 Logical::Or { .. } => todo!(),
156 Logical::Implies { .. } => todo!(),
157 Logical::BasedOnKey { .. } => todo!(),
158 }
159 } else {
160 TypeId::UNIMPLEMENTED_ERROR_TYPE
161 }
162 } else {
163 let keys;
164 let possibles = if let PropertyKey::String(s) = under {
165 keys = get_property_key_names_on_a_single_type(
166 space,
167 &checking_data.types,
168 environment,
169 );
170 let mut possibles =
171 crate::get_closest(keys.iter().map(AsRef::as_ref), s).unwrap_or(vec![]);
172 possibles.sort_unstable();
173 possibles
174 } else {
175 Vec::new()
176 };
177 checking_data.diagnostics_container.add_error(TypeCheckError::PropertyDoesNotExist {
178 property: PropertyKeyRepresentation::new(under, environment, &checking_data.types),
179 on: TypeStringRepresentation::from_type_id(
180 space,
181 environment,
182 &checking_data.types,
183 false,
184 ),
185 position,
186 possibles,
187 });
188 TypeId::ERROR_TYPE
189 }
190 });
191
192 let initial_value = on.initial_value.map(|initial_value| {
193 environment
194 .get_property_handle_errors(
195 initial_value,
196 Publicity::Public,
197 under,
198 checking_data,
199 position,
200 crate::types::properties::AccessMode::Regular,
201 )
202 .map_or(TypeId::ERROR_TYPE, Instance::get_value)
203 });
204
205 VariableRegisterArguments {
206 constant: on.constant,
207 space,
208 initial_value,
209 allow_reregistration: on.allow_reregistration,
210 }
211}