Skip to main content

ezno_checker/features/
variables.rs

1//! More code at [`crate::context`] and [`Environment`]
2
3use 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/// A variable, that can be referenced. Can be a including class (prototypes) and functions
22///
23/// TODO constant variables with a fixed value
24#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
25pub enum VariableOrImport {
26	Variable {
27		/// Whether can be reassigned and what to
28		mutability: VariableMutability,
29		/// Location where variable is defined **ALSO UNIQUELY IDENTIFIES THE VARIABLE** as can
30		/// be turned into a [`VariableId`]
31		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	/// Whether can be reassigned
60	pub(crate) fn get_mutability(&self) -> VariableMutability {
61		match self {
62			VariableOrImport::Variable { mutability, .. } => *mutability,
63			// TODO I think ?
64			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/// Shallow mutability
83#[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
92/// Returns whether valid
93pub 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}