Skip to main content

ezno_checker/context/
environment.rs

1use source_map::{SourceId, Span, SpanWithSource};
2use std::collections::{HashMap, HashSet};
3
4use crate::{
5	context::{get_on_ctx, information::ReturnState},
6	diagnostics::{
7		NotInLoopOrCouldNotFindLabel, PropertyKeyRepresentation, TypeCheckError,
8		TypeStringRepresentation, VariableUsedInTDZ,
9	},
10	events::{Event, FinalEvent, RootReference},
11	features::{
12		assignments::{
13			Assignable, AssignableArrayDestructuringField, AssignableObjectDestructuringField,
14			AssignmentKind, AssignmentReturnStatus, IncrementOrDecrement, Reference,
15		},
16		modules::Exported,
17		operations::{evaluate_logical_operation_with_expression, MathematicalOrBitwiseOperation},
18		variables::{VariableMutability, VariableOrImport, VariableWithValue},
19	},
20	subtyping::{type_is_subtype, type_is_subtype_object, State, SubTypeResult, SubTypingOptions},
21	types::{
22		properties::{
23			get_property_key_names_on_a_single_type, AccessMode, PropertyKey, PropertyKind,
24			Publicity,
25		},
26		PolyNature, Type, TypeStore,
27	},
28	CheckingData, Instance, RootContext, TypeId,
29};
30
31use super::{
32	get_value_of_variable, invocation::CheckThings, AssignmentError, ClosedOverReferencesInScope,
33	Context, ContextType, Environment, GeneralContext, InformationChain,
34};
35
36/// For WIP contextual access of certain APIs
37pub type ContextLocation = Option<String>;
38
39/// Error type for something already being defined
40pub struct AlreadyExists;
41
42pub enum DeclareInterfaceResult {
43	Merging { ty: TypeId, in_same_context: bool },
44	New(TypeId),
45}
46
47#[derive(Debug)]
48pub struct Syntax<'a> {
49	pub scope: Scope,
50	pub(crate) parent: GeneralContext<'a>,
51
52	/// Variables that this context pulls in from above (across a dynamic context). aka not from parameters of bound this
53	/// Not to be confused with `closed_over_references`
54	pub free_variables: HashSet<RootReference>,
55
56	/// Variables used in this scope which are closed over by functions. These need to be stored
57	/// Not to be confused with `used_parent_references`
58	pub closed_over_references: ClosedOverReferencesInScope,
59
60	/// TODO WIP! server, client, worker etc
61	pub location: ContextLocation,
62
63	/// Parameter inference requests
64	/// TODO RHS = Has Property
65	pub requests: Vec<(TypeId, TypeId)>,
66}
67
68/// Code under a dynamic boundary can run more than once
69#[derive(Debug, Clone, Copy)]
70pub enum DynamicBoundaryKind {
71	Loop,
72	Function,
73}
74
75impl DynamicBoundaryKind {
76	#[must_use]
77	pub fn can_use_variable_before_definition(self) -> bool {
78		matches!(self, Self::Function)
79	}
80}
81
82impl<'a> ContextType for Syntax<'a> {
83	fn as_general_context(et: &Context<Self>) -> GeneralContext<'_> {
84		GeneralContext::Syntax(et)
85	}
86
87	fn get_parent(&self) -> Option<&GeneralContext<'_>> {
88		Some(&self.parent)
89	}
90
91	fn as_syntax(&self) -> Option<&Syntax> {
92		Some(self)
93	}
94
95	fn get_closed_over_references_mut(&mut self) -> Option<&mut ClosedOverReferencesInScope> {
96		Some(&mut self.closed_over_references)
97	}
98}
99
100#[derive(Debug, Clone, Copy)]
101pub enum ExpectedReturnType {
102	/// This may have a position in the future
103	Inferred(TypeId),
104	FromReturnAnnotation(TypeId, Span),
105}
106
107impl ExpectedReturnType {
108	pub(crate) fn get_type_and_position(self) -> (TypeId, Option<Span>) {
109		match self {
110			ExpectedReturnType::Inferred(ty) => (ty, None),
111			ExpectedReturnType::FromReturnAnnotation(ty, pos) => (ty, Some(pos)),
112		}
113	}
114}
115
116/// TODO better names
117/// Decides whether `await` and `yield` are available and many others
118///
119/// `this` is the dependent type
120#[derive(Debug, Clone)]
121pub enum FunctionScope {
122	ArrowFunction {
123		// This always points to a poly free variable type
124		free_this_type: TypeId,
125		is_async: bool,
126		expected_return: Option<ExpectedReturnType>,
127	},
128	/// TODO does this need to gdistinguish class
129	MethodFunction {
130		// This always points to a poly free variable type
131		free_this_type: TypeId,
132		is_async: bool,
133		is_generator: bool,
134
135		expected_return: Option<ExpectedReturnType>,
136	},
137	// is new-able
138	Function {
139		is_generator: bool,
140		is_async: bool,
141		expected_return: Option<ExpectedReturnType>,
142		// This always points to a conditional type based on `new.target === undefined`
143		this_type: TypeId,
144		type_of_super: TypeId,
145		location: ContextLocation,
146	},
147	Constructor {
148		/// Can call `super`
149		extends: bool,
150		type_of_super: Option<TypeId>,
151		// This is always created, but may not be used (or have the relevant properties & prototype)
152		this_object_type: TypeId,
153	},
154}
155
156impl FunctionScope {
157	// TODO temp
158	pub(crate) fn get_expected_return_type_mut(&mut self) -> &mut Option<ExpectedReturnType> {
159		match self {
160			FunctionScope::ArrowFunction { expected_return, .. }
161			| FunctionScope::MethodFunction { expected_return, .. }
162			| FunctionScope::Function { expected_return, .. } => expected_return,
163			FunctionScope::Constructor { .. } => unreachable!(),
164		}
165	}
166}
167
168/// For labeled statements
169pub type Label = Option<String>;
170
171#[derive(Clone, Copy)]
172pub enum Returnable<'a, A: crate::ASTImplementation> {
173	Statement(Option<&'a A::MultipleExpression<'a>>, Span),
174	ArrowFunctionBody(&'a A::Expression<'a>),
175}
176
177/// TODO name of structure
178/// TODO conditionals should have conditional proofs (separate from the ones on context)
179#[derive(Debug, Clone)]
180pub enum Scope {
181	Function(FunctionScope),
182	InterfaceEnvironment {
183		this_constraint: TypeId,
184	},
185	DefaultFunctionParameter {},
186	FunctionAnnotation {},
187	/// For ifs, elses, or lazy operators
188	Conditional {
189		/// Something that is truthy for this to run
190		antecedent: TypeId,
191
192		is_switch: Option<Label>,
193	},
194	/// Variables here are dependent on the iteration,
195	Iteration {
196		label: Label, // TODO on: Proofs,
197	},
198	TryBlock {},
199	CatchBlock {},
200	FinallyBlock {},
201	// Just blocks and modules
202	Block {},
203	Module {
204		source: SourceId,
205		exported: Exported,
206	},
207	DefinitionModule {
208		source: SourceId,
209	},
210	/// For generic parameters
211	TypeAlias,
212	StaticBlock {
213		this_type: TypeId,
214	},
215	/// For repl only
216	PassThrough {
217		source: SourceId,
218	},
219	TypeAnnotationCondition {
220		infer_parameters: HashMap<String, TypeId>,
221	},
222	TypeAnnotationConditionResult,
223}
224
225impl Scope {
226	#[must_use]
227	pub fn is_dynamic_boundary(&self) -> Option<DynamicBoundaryKind> {
228		match self {
229			Scope::Function { .. } => Some(DynamicBoundaryKind::Function),
230			Scope::Iteration { .. } => Some(DynamicBoundaryKind::Loop),
231			_ => None,
232		}
233	}
234
235	#[must_use]
236	pub fn is_conditional(&self) -> bool {
237		matches!(self, Scope::Conditional { .. })
238	}
239}
240
241impl<'a> Environment<'a> {
242	/// Handles all assignments, including updates and destructuring
243	///
244	/// Will evaluate the expression with the right timing and conditions, including never if short circuit
245	pub fn assign_handle_errors<'b, T: crate::ReadFromFS, A: crate::ASTImplementation>(
246		&mut self,
247		lhs: Assignable<A>,
248		operator: AssignmentKind,
249		// Can be `None` for increment and decrement
250		expression: Option<&'b A::Expression<'b>>,
251		assignment_position: Span,
252		checking_data: &mut CheckingData<T, A>,
253	) -> TypeId {
254		match lhs {
255			Assignable::Reference(reference) => {
256				match operator {
257					AssignmentKind::Assign => {
258						let rhs = A::synthesise_expression(
259							expression.unwrap(),
260							TypeId::ANY_TYPE,
261							self,
262							checking_data,
263						);
264
265						let assignment_position =
266							assignment_position.with_source(self.get_source());
267						self.set_reference_handle_errors(
268							reference,
269							rhs,
270							assignment_position,
271							checking_data,
272						);
273						rhs
274					}
275					AssignmentKind::PureUpdate(operator) => {
276						// Order matters here
277						// let reference_position = reference.get_position();
278						let existing = self.get_reference(
279							reference.clone(),
280							checking_data,
281							AccessMode::Regular,
282						);
283
284						let expression = expression.unwrap();
285						// let expression_pos =
286						// 	A::expression_position(expression).with_source(self.get_source());
287
288						let rhs = A::synthesise_expression(
289							expression,
290							TypeId::ANY_TYPE,
291							self,
292							checking_data,
293						);
294
295						let result = crate::features::operations::evaluate_mathematical_operation(
296							existing,
297							operator,
298							rhs,
299							self,
300							&mut checking_data.types,
301							checking_data.options.strict_casts,
302							checking_data.options.advanced_numbers,
303						);
304						if let Ok(new) = result {
305							let assignment_position =
306								assignment_position.with_source(self.get_source());
307
308							self.set_reference_handle_errors(
309								reference,
310								new,
311								assignment_position,
312								checking_data,
313							);
314
315							new
316						} else {
317							checking_data.diagnostics_container.add_error(
318								crate::TypeCheckError::InvalidMathematicalOrBitwiseOperation {
319									operator,
320									lhs: crate::diagnostics::TypeStringRepresentation::from_type_id(
321										existing,
322										self,
323										&checking_data.types,
324										false,
325									),
326									rhs: crate::diagnostics::TypeStringRepresentation::from_type_id(
327										rhs,
328										self,
329										&checking_data.types,
330										false,
331									),
332									position: assignment_position.with_source(self.get_source()),
333								},
334							);
335							TypeId::ERROR_TYPE
336						}
337					}
338					AssignmentKind::IncrementOrDecrement(direction, return_kind) => {
339						// let value =
340						// 	self.get_variable_or_error(&name, &assignment_position, checking_data);
341						let position = reference.get_position();
342						let existing = self.get_reference(
343							reference.clone(),
344							checking_data,
345							AccessMode::Regular,
346						);
347
348						// TODO existing needs to be cast to number!!
349						let operator = match direction {
350							IncrementOrDecrement::Increment => MathematicalOrBitwiseOperation::Add,
351							IncrementOrDecrement::Decrement => {
352								MathematicalOrBitwiseOperation::Subtract
353							}
354						};
355
356						let result = crate::features::operations::evaluate_mathematical_operation(
357							existing,
358							operator,
359							TypeId::ONE,
360							self,
361							&mut checking_data.types,
362							checking_data.options.strict_casts,
363							checking_data.options.advanced_numbers,
364						);
365						if let Ok(new) = result {
366							let assignment_position =
367								assignment_position.with_source(self.get_source());
368
369							self.set_reference_handle_errors(
370								reference,
371								new,
372								assignment_position,
373								checking_data,
374							);
375
376							match return_kind {
377								AssignmentReturnStatus::Previous => existing,
378								AssignmentReturnStatus::New => new,
379							}
380						} else {
381							checking_data.diagnostics_container.add_error(
382								crate::TypeCheckError::InvalidMathematicalOrBitwiseOperation {
383									operator,
384									lhs: crate::diagnostics::TypeStringRepresentation::from_type_id(
385										existing,
386										self,
387										&checking_data.types,
388										false,
389									),
390									rhs: crate::diagnostics::TypeStringRepresentation::from_type_id(
391										TypeId::ONE,
392										self,
393										&checking_data.types,
394										false,
395									),
396									position,
397								},
398							);
399							TypeId::ERROR_TYPE
400						}
401					}
402					AssignmentKind::ConditionalUpdate(operator) => {
403						let existing = self.get_reference(
404							reference.clone(),
405							checking_data,
406							AccessMode::Regular,
407						);
408						let expression = expression.unwrap();
409						let new = evaluate_logical_operation_with_expression(
410							(existing, reference.get_position().without_source()),
411							operator,
412							expression,
413							checking_data,
414							self,
415							TypeId::ANY_TYPE,
416						)
417						.unwrap();
418
419						let assignment_position =
420							assignment_position.with_source(self.get_source());
421						self.set_reference_handle_errors(
422							reference,
423							new,
424							assignment_position,
425							checking_data,
426						);
427						new
428					}
429				}
430			}
431			Assignable::ObjectDestructuring(members, _spread) => {
432				debug_assert!(matches!(operator, AssignmentKind::Assign));
433
434				let rhs = A::synthesise_expression(
435					expression.unwrap(),
436					TypeId::ANY_TYPE,
437					self,
438					checking_data,
439				);
440
441				self.assign_to_object_destructure_handle_errors(
442					members,
443					rhs,
444					assignment_position.with_source(self.get_source()),
445					checking_data,
446				);
447
448				rhs
449			}
450			Assignable::ArrayDestructuring(members, _spread) => {
451				debug_assert!(matches!(operator, AssignmentKind::Assign));
452
453				let rhs = A::synthesise_expression(
454					expression.unwrap(),
455					TypeId::ANY_TYPE,
456					self,
457					checking_data,
458				);
459
460				self.assign_to_array_destructure_handle_errors(
461					members,
462					rhs,
463					assignment_position.with_source(self.get_source()),
464					checking_data,
465				);
466
467				rhs
468			}
469		}
470	}
471
472	fn assign_to_assignable_handle_errors<T: crate::ReadFromFS, A: crate::ASTImplementation>(
473		&mut self,
474		lhs: Assignable<A>,
475		rhs: TypeId,
476		assignment_position: SpanWithSource,
477		checking_data: &mut CheckingData<T, A>,
478	) {
479		match lhs {
480			Assignable::Reference(reference) => {
481				self.set_reference_handle_errors(
482					reference,
483					rhs,
484					assignment_position,
485					checking_data,
486				);
487			}
488			Assignable::ObjectDestructuring(assignments, _spread) => self
489				.assign_to_object_destructure_handle_errors(
490					assignments,
491					rhs,
492					assignment_position,
493					checking_data,
494				),
495			Assignable::ArrayDestructuring(assignments, _spread) => self
496				.assign_to_array_destructure_handle_errors(
497					assignments,
498					rhs,
499					assignment_position,
500					checking_data,
501				),
502		}
503	}
504
505	fn assign_to_object_destructure_handle_errors<
506		T: crate::ReadFromFS,
507		A: crate::ASTImplementation,
508	>(
509		&mut self,
510		assignments: Vec<AssignableObjectDestructuringField<A>>,
511		rhs: TypeId,
512		assignment_position: SpanWithSource,
513		checking_data: &mut CheckingData<T, A>,
514	) {
515		for assignment in assignments {
516			match assignment {
517				AssignableObjectDestructuringField::Mapped {
518					key,
519					name,
520					default_value,
521					position,
522				} => {
523					// TODO conditionaly
524					let mut diagnostics = Default::default();
525					let result = crate::types::properties::get_property(
526						rhs,
527						Publicity::Public,
528						&key,
529						self,
530						(
531							&mut CheckThings { debug_types: checking_data.options.debug_types },
532							&mut diagnostics,
533						),
534						&mut checking_data.types,
535						position,
536						AccessMode::DoNotBindThis,
537					);
538					diagnostics.append_to(
539						crate::types::calling::CallingContext::Getter,
540						&mut checking_data.diagnostics_container,
541					);
542
543					let rhs_value = if let Some((_, value)) = result {
544						value
545					} else if let Some(default_value) = default_value {
546						A::synthesise_expression(
547							default_value.as_ref(),
548							TypeId::ANY_TYPE,
549							self,
550							checking_data,
551						)
552					} else {
553						let keys;
554						let possibles = if let PropertyKey::String(s) = &key {
555							keys = get_property_key_names_on_a_single_type(
556								rhs,
557								&checking_data.types,
558								self,
559							);
560							let mut possibles =
561								crate::get_closest(keys.iter().map(AsRef::as_ref), s)
562									.unwrap_or(vec![]);
563							possibles.sort_unstable();
564							possibles
565						} else {
566							Vec::new()
567						};
568						checking_data.diagnostics_container.add_error(
569							TypeCheckError::PropertyDoesNotExist {
570								property: PropertyKeyRepresentation::new(
571									&key,
572									self,
573									&checking_data.types,
574								),
575								on: TypeStringRepresentation::from_type_id(
576									rhs,
577									self,
578									&checking_data.types,
579									false,
580								),
581								position,
582								possibles,
583							},
584						);
585
586						TypeId::ERROR_TYPE
587					};
588
589					self.assign_to_assignable_handle_errors(
590						name,
591						rhs_value,
592						assignment_position,
593						checking_data,
594					);
595				}
596			}
597		}
598	}
599
600	#[allow(clippy::needless_pass_by_value)]
601	#[allow(clippy::unused_self)]
602	fn assign_to_array_destructure_handle_errors<
603		T: crate::ReadFromFS,
604		A: crate::ASTImplementation,
605	>(
606		&mut self,
607		_assignments: Vec<AssignableArrayDestructuringField<A>>,
608		_rhs: TypeId,
609		assignment_position: SpanWithSource,
610		checking_data: &mut CheckingData<T, A>,
611	) {
612		checking_data
613			.raise_unimplemented_error("destructuring array (needs iterator)", assignment_position);
614	}
615
616	fn get_reference<U: crate::ReadFromFS, A: crate::ASTImplementation>(
617		&mut self,
618		reference: Reference,
619		checking_data: &mut CheckingData<U, A>,
620		mode: AccessMode,
621	) -> TypeId {
622		match reference {
623			Reference::Variable(name, position) => self
624				.get_variable_handle_error(&name, position, checking_data)
625				.map_or(TypeId::ERROR_TYPE, |VariableWithValue(_, ty)| ty),
626			Reference::Property { on, with, publicity, position } => {
627				let get_property_handle_errors = self.get_property_handle_errors(
628					on,
629					publicity,
630					&with,
631					checking_data,
632					position,
633					mode,
634				);
635				match get_property_handle_errors {
636					Ok(i) => i.get_value(),
637					Err(()) => TypeId::ERROR_TYPE,
638				}
639			}
640		}
641	}
642
643	fn set_reference_handle_errors<U: crate::ReadFromFS, A: crate::ASTImplementation>(
644		&mut self,
645		reference: Reference,
646		rhs: TypeId,
647		_position: SpanWithSource,
648		checking_data: &mut CheckingData<U, A>,
649	) {
650		match reference {
651			Reference::Variable(name, position) => {
652				self.assign_to_variable_handle_errors(name.as_str(), position, rhs, checking_data);
653			}
654			Reference::Property { on, with, publicity, position } => {
655				self.set_property_handle_errors(on, publicity, &with, rhs, position, checking_data);
656			}
657		}
658	}
659
660	pub fn assign_to_variable_handle_errors<T: crate::ReadFromFS, A: crate::ASTImplementation>(
661		&mut self,
662		variable_name: &str,
663		assignment_position: SpanWithSource,
664		new_type: TypeId,
665		checking_data: &mut CheckingData<T, A>,
666	) {
667		let result = self.assign_to_variable(
668			variable_name,
669			assignment_position,
670			new_type,
671			&mut checking_data.types,
672		);
673		match result {
674			Ok(()) => {}
675			Err(error) => {
676				checking_data
677					.diagnostics_container
678					.add_error(TypeCheckError::AssignmentError(error));
679			}
680		}
681	}
682
683	/// This is top level variables, not properties.
684	pub fn assign_to_variable(
685		&mut self,
686		variable_name: &str,
687		assignment_position: SpanWithSource,
688		new_type: TypeId,
689		types: &mut TypeStore,
690	) -> Result<(), AssignmentError> {
691		// Get without the effects
692		let variable_in_map = self.get_variable_unbound(variable_name);
693
694		if let Some((_, boundary, variable)) = variable_in_map {
695			match variable {
696				VariableOrImport::Variable {
697					mutability,
698					declared_at,
699					context: _,
700					allow_reregistration: _,
701				} => match mutability {
702					VariableMutability::Constant => Err(AssignmentError::Constant(*declared_at)),
703					VariableMutability::Mutable { reassignment_constraint } => {
704						let variable = variable.clone();
705						let variable_position = *declared_at;
706						let variable_id = variable.get_id();
707
708						if boundary.is_none()
709							&& !self
710								.get_chain_of_info()
711								.any(|info| info.variable_current_value.contains_key(&variable_id))
712						{
713							return Err(AssignmentError::VariableUsedInTDZ(VariableUsedInTDZ {
714								position: assignment_position,
715								variable_name: variable_name.to_owned(),
716							}));
717						}
718
719						if let Some(reassignment_constraint) = *reassignment_constraint {
720							let result = type_is_subtype_object(
721								reassignment_constraint,
722								new_type,
723								self,
724								types,
725							);
726
727							if let SubTypeResult::IsNotSubType(_mismatches) = result {
728								return Err(AssignmentError::DoesNotMeetConstraint {
729									variable_type: TypeStringRepresentation::from_type_id(
730										reassignment_constraint,
731										self,
732										types,
733										false,
734									),
735									value_type: TypeStringRepresentation::from_type_id(
736										new_type, self, types, false,
737									),
738									variable_position,
739									value_position: assignment_position,
740								});
741							}
742						}
743
744						self.info.events.push(Event::SetsVariable(
745							variable_id,
746							new_type,
747							assignment_position,
748						));
749						self.info.variable_current_value.insert(variable_id, new_type);
750
751						Ok(())
752					}
753				},
754				VariableOrImport::MutableImport { .. }
755				| VariableOrImport::ConstantImport { .. } => {
756					Err(AssignmentError::Constant(assignment_position))
757				}
758			}
759		} else {
760			crate::utilities::notify!("Could say it is on the window here");
761			Err(AssignmentError::VariableNotFound {
762				variable: variable_name.to_owned(),
763				assignment_position,
764			})
765		}
766	}
767
768	pub(crate) fn get_root(&self) -> &RootContext {
769		match self.context_type.parent {
770			GeneralContext::Syntax(syntax) => syntax.get_root(),
771			GeneralContext::Root(root) => root,
772		}
773	}
774
775	#[must_use]
776	pub fn get_environment_type(&self) -> &Scope {
777		&self.context_type.scope
778	}
779
780	pub fn get_environment_type_mut(&mut self) -> &mut Scope {
781		&mut self.context_type.scope
782	}
783
784	/// `object_constraints` is LHS is constrained to RHS
785	pub fn add_parameter_constraint_request(
786		&mut self,
787		requests: impl Iterator<Item = (TypeId, TypeId)>,
788	) {
789		self.context_type.requests.extend(requests);
790	}
791
792	pub(crate) fn get_parent(&self) -> GeneralContext {
793		match self.context_type.parent {
794			GeneralContext::Syntax(syn) => GeneralContext::Syntax(syn),
795			GeneralContext::Root(rt) => GeneralContext::Root(rt),
796		}
797	}
798
799	pub fn get_property_handle_errors<U: crate::ReadFromFS, A: crate::ASTImplementation>(
800		&mut self,
801		on: TypeId,
802		publicity: Publicity,
803		under: &PropertyKey,
804		checking_data: &mut CheckingData<U, A>,
805		position: SpanWithSource,
806		mode: AccessMode,
807	) -> Result<Instance, ()> {
808		// let get_property = if let AccessMode::Optional = mode {
809		// 	let is_lhs_null = evaluate_equality_inequality_operation(
810		// 		lhs.0,
811		// 		&EqualityAndInequality::StrictEqual,
812		// 		TypeId::NULL_TYPE,
813		// 		&mut checking_data.types,
814		// 		checking_data.options.strict_casts,
815		// 	)?;
816		// 	Ok(new_conditional_context(
817		// 		environment,
818		// 		(is_lhs_null, lhs.1),
819		// 		|env: &mut Environment, data: &mut CheckingData<T, A>| {
820		// 			A::synthesise_expression(rhs, TypeId::ANY_TYPE, env, data)
821		// 		},
822		// 		Some(|_env: &mut Environment, _data: &mut CheckingData<T, A>| lhs.0),
823		// 		checking_data,
824		// 	))
825		// } else {
826		let mut diagnostics = Default::default();
827		let get_property = crate::types::properties::get_property(
828			on,
829			publicity,
830			under,
831			self,
832			(&mut CheckThings { debug_types: checking_data.options.debug_types }, &mut diagnostics),
833			&mut checking_data.types,
834			position,
835			mode,
836		);
837		diagnostics.append_to(
838			crate::types::calling::CallingContext::Getter,
839			&mut checking_data.diagnostics_container,
840		);
841
842		// };
843
844		if let Some((kind, result)) = get_property {
845			Ok(match kind {
846				PropertyKind::Getter => Instance::GValue(result),
847				// TODO instance.property...?
848				PropertyKind::Generic | PropertyKind::Direct | PropertyKind::Setter => {
849					Instance::RValue(result)
850				}
851			})
852		} else {
853			let keys;
854			let possibles = if let PropertyKey::String(s) = under {
855				keys = get_property_key_names_on_a_single_type(on, &checking_data.types, self);
856				let mut possibles =
857					crate::get_closest(keys.iter().map(AsRef::as_ref), s).unwrap_or(vec![]);
858				possibles.sort_unstable();
859				possibles
860			} else {
861				Vec::new()
862			};
863			checking_data.diagnostics_container.add_error(TypeCheckError::PropertyDoesNotExist {
864				property: PropertyKeyRepresentation::new(under, self, &checking_data.types),
865				on: crate::diagnostics::TypeStringRepresentation::from_type_id(
866					on,
867					self,
868					&checking_data.types,
869					false,
870				),
871				position,
872				possibles,
873			});
874			Err(())
875		}
876	}
877
878	pub fn get_variable_handle_error<U: crate::ReadFromFS, A: crate::ASTImplementation>(
879		&mut self,
880		name: &str,
881		position: SpanWithSource,
882		checking_data: &mut CheckingData<U, A>,
883	) -> Result<VariableWithValue, TypeId> {
884		let (in_root, crossed_boundary, og_var) = {
885			let variable_information = self.get_variable_unbound(name);
886			// crate::utilities::notify!("{:?} returned {:?}", name, variable_information);
887			if let Some((in_root, crossed_boundary, og_var)) = variable_information {
888				(in_root, crossed_boundary, og_var.clone())
889			} else {
890				let possibles = {
891					let mut possibles =
892						crate::get_closest(self.get_all_variable_names(), name).unwrap_or(vec![]);
893					possibles.sort_unstable();
894					possibles
895				};
896				checking_data.diagnostics_container.add_error(
897					TypeCheckError::CouldNotFindVariable { variable: name, possibles, position },
898				);
899				return Err(TypeId::ERROR_TYPE);
900			}
901		};
902
903		let reference = RootReference::Variable(og_var.get_id());
904
905		// TODO context checking here
906		// {
907		// 	if let VariableOrImport::Variable { context: Some(ref context), .. } = og_var {
908		// 		if let Some(ref current_context) = self.parents_iter().find_map(|a| {
909		// 			if let GeneralContext::Syntax(syn) = a {
910		// 				syn.context_type.location.clone()
911		// 			} else {
912		// 				None
913		// 			}
914		// 		}) {
915		// 			if current_context != context {
916		// 				checking_data.diagnostics_container.add_error(
917		// 					TypeCheckError::VariableNotDefinedInContext {
918		// 						variable: name,
919		// 						expected_context: context,
920		// 						current_context: current_context.clone(),
921		// 						position,
922		// 					},
923		// 				);
924		// 				return Err(TypeId::ERROR_TYPE);
925		// 			}
926		// 		}
927		// 	}
928		// }
929
930		// let treat_as_in_same_scope = (og_var.is_constant && self.is_immutable(current_value));
931
932		// TODO in_root temp fix to treat those as constant (so Math works in functions)
933		if let (Some(_boundary), false) = (crossed_boundary, in_root) {
934			let based_on = match og_var.get_mutability() {
935				VariableMutability::Constant => {
936					let current_value = self
937						.get_chain_of_info()
938						.find_map(|info| {
939							info.variable_current_value.get(&og_var.get_origin_variable_id())
940						})
941						.copied();
942
943					// TODO WIP
944					let narrowed = current_value
945						.and_then(|cv| self.get_narrowed_or_object(cv, &checking_data.types));
946
947					if let Some(precise) = narrowed.or(current_value) {
948						// let ty = checking_data.types.get_type_by_id(precise);
949
950						// // TODO temp for function
951						// let value = if let Type::SpecialObject(SpecialObject::Function(..)) = ty {
952						// 	return Ok(VariableWithValue(og_var.clone(), precise));
953						// } else if let Type::RootPolyType(PolyNature::Open(_)) = ty {
954						// 	crate::utilities::notify!(
955						// 		"Open poly type '{}' treated as immutable free variable",
956						// 		name
957						// 	);
958						// 	return Ok(VariableWithValue(og_var.clone(), precise));
959						// } else if let Type::Constant(_) = ty {
960						// };
961
962						return Ok(VariableWithValue(og_var.clone(), precise));
963					}
964
965					crate::utilities::notify!("Free variable with no current value");
966					let constraint = checking_data
967						.local_type_mappings
968						.variables_to_constraints
969						.0
970						.get(&og_var.get_origin_variable_id());
971
972					if let Some(constraint) = constraint {
973						*constraint
974					} else {
975						crate::utilities::notify!("TODO record that free variable is `any` here");
976						TypeId::ANY_TYPE
977					}
978				}
979				VariableMutability::Mutable { reassignment_constraint } => {
980					// TODO is there a nicer way to do this
981					// Look for reassignments
982					let variable_id = og_var.get_id();
983
984					// `break`s here VERY IMPORTANT
985					for ctx in self.parents_iter() {
986						if let GeneralContext::Syntax(s) = ctx {
987							if s.possibly_mutated_variables.contains(&variable_id) {
988								crate::utilities::notify!("Possibly mutated variables");
989								break;
990							}
991
992							if let Some(current_value) =
993								get_on_ctx!(ctx.info.variable_current_value.get(&variable_id))
994									.copied()
995							{
996								return Ok(VariableWithValue(og_var.clone(), current_value));
997							}
998
999							if s.context_type.scope.is_dynamic_boundary().is_some() {
1000								break;
1001							}
1002						}
1003					}
1004
1005					if let Some(constraint) = reassignment_constraint {
1006						constraint
1007					} else {
1008						crate::utilities::notify!("TODO record that parent variable is `any` here");
1009						TypeId::ANY_TYPE
1010					}
1011				}
1012			};
1013
1014			let mut reused_reference = None;
1015			{
1016				let mut reversed_events = self.info.events.iter().rev();
1017				while let Some(event) = reversed_events.next() {
1018					if let Event::ReadsReference {
1019						reference: other_reference,
1020						reflects_dependency: Some(dependency),
1021						position: _,
1022					} = event
1023					{
1024						if reference == *other_reference {
1025							reused_reference = Some(*dependency);
1026							break;
1027						}
1028					} else if let Event::EndOfControlFlow(count) = event {
1029						// Important to skip control flow nodes
1030						for _ in 0..=(*count) {
1031							reversed_events.next();
1032						}
1033					}
1034				}
1035			}
1036
1037			let ty = if let Some(reused_reference) = reused_reference {
1038				// TODO temp. I believe this can break type contracts because of mutations
1039				// but needed here because of for loop narrowing
1040				let narrowed = self.get_narrowed_or_object(reused_reference, &checking_data.types);
1041				narrowed.unwrap_or(reused_reference)
1042			} else {
1043				// TODO dynamic ?
1044				let ty = Type::RootPolyType(crate::types::PolyNature::FreeVariable {
1045					reference: reference.clone(),
1046					based_on,
1047				});
1048				let ty = checking_data.types.register_type(ty);
1049
1050				// TODO would it be useful to record the type somewhere?
1051				self.context_type.free_variables.insert(reference);
1052
1053				// if inferred {
1054				// 	self.context_type.get_inferrable_constraints_mut().unwrap().insert(type_id);
1055				// }
1056
1057				self.info.events.push(Event::ReadsReference {
1058					reference: RootReference::Variable(og_var.get_id()),
1059					reflects_dependency: Some(ty),
1060					position,
1061				});
1062
1063				ty
1064			};
1065
1066			Ok(VariableWithValue(og_var.clone(), ty))
1067		} else {
1068			// TODO recursively in
1069			if let VariableOrImport::MutableImport { of, constant: false, import_specified_at: _ } =
1070				og_var.clone()
1071			{
1072				let current_value = get_value_of_variable(
1073					self,
1074					of,
1075					None::<&crate::types::generics::substitution::SubstitutionArguments<'static>>,
1076					&checking_data.types,
1077				)
1078				.expect("import not assigned yet");
1079				return Ok(VariableWithValue(og_var.clone(), current_value));
1080			}
1081
1082			let current_value = get_value_of_variable(
1083				self,
1084				og_var.get_id(),
1085				None::<&crate::types::generics::substitution::SubstitutionArguments<'static>>,
1086				&checking_data.types,
1087			);
1088
1089			if let Some(current_value) = current_value {
1090				Ok(VariableWithValue(og_var.clone(), current_value))
1091			} else {
1092				checking_data.diagnostics_container.add_error(TypeCheckError::VariableUsedInTDZ(
1093					VariableUsedInTDZ {
1094						variable_name: self.get_variable_name(og_var.get_id()).to_owned(),
1095						position,
1096					},
1097				));
1098				Ok(VariableWithValue(og_var.clone(), TypeId::ERROR_TYPE))
1099			}
1100		}
1101	}
1102
1103	pub fn throw_value(&mut self, thrown: TypeId, position: SpanWithSource, types: &mut TypeStore) {
1104		let final_event = FinalEvent::Throw { thrown, position };
1105
1106		// WIP
1107		let final_return =
1108			if let ReturnState::Rolling { under, returned: rolling_returning } = self.info.state {
1109				types.new_conditional_type(under, rolling_returning, TypeId::NEVER_TYPE)
1110			} else {
1111				TypeId::NEVER_TYPE
1112			};
1113		self.info.state = ReturnState::Finished(final_return);
1114
1115		self.info.events.push(final_event.into());
1116	}
1117
1118	/// Also appends invalid return type checks
1119	pub fn return_value<T: crate::ReadFromFS, A: crate::ASTImplementation>(
1120		&mut self,
1121		expression: &Returnable<A>,
1122		checking_data: &mut CheckingData<T, A>,
1123	) {
1124		let expected = self.get_expected_return_type();
1125		let expected_split = expected.map(ExpectedReturnType::get_type_and_position);
1126		let expected_type = expected_split.map_or(TypeId::ANY_TYPE, |(l, _)| l);
1127
1128		let (returned, returned_position) = match expression {
1129			Returnable::Statement(Some(expression), returned_position) => (
1130				A::synthesise_multiple_expression(expression, expected_type, self, checking_data),
1131				returned_position.with_source(self.get_source()),
1132			),
1133			Returnable::Statement(None, returned_position) => {
1134				(TypeId::UNDEFINED_TYPE, returned_position.with_source(self.get_source()))
1135			}
1136			Returnable::ArrowFunctionBody(expression) => (
1137				A::synthesise_expression(expression, expected_type, self, checking_data),
1138				A::expression_position(expression).with_source(self.get_source()),
1139			),
1140		};
1141
1142		// Check that it meets the return type (could do at the end, but fine here)
1143		{
1144			// Don't check inferred, only annotations
1145			if let Some(ExpectedReturnType::FromReturnAnnotation(expected, position)) = expected {
1146				// TODO what about conditional things
1147
1148				let mut state = State {
1149					already_checked: Default::default(),
1150					mode: Default::default(),
1151					contributions: Default::default(),
1152					others: SubTypingOptions::default(),
1153					// TODO don't think there is much case in constraining it here
1154					object_constraints: None,
1155				};
1156
1157				let result =
1158					type_is_subtype(expected, returned, &mut state, self, &checking_data.types);
1159
1160				if let SubTypeResult::IsNotSubType(_) = result {
1161					checking_data.diagnostics_container.add_error(
1162						TypeCheckError::ReturnedTypeDoesNotMatch {
1163							expected_return_type: TypeStringRepresentation::from_type_id(
1164								expected,
1165								self,
1166								&checking_data.types,
1167								checking_data.options.debug_types,
1168							),
1169							returned_type: TypeStringRepresentation::from_type_id(
1170								returned,
1171								self,
1172								&checking_data.types,
1173								checking_data.options.debug_types,
1174							),
1175							annotation_position: position.with_source(self.get_source()),
1176							returned_position,
1177						},
1178					);
1179
1180					// Add the expected return type instead here
1181					// if it fell through to another then it could be bad
1182					{
1183						let expected_return = checking_data.types.new_error_type(expected);
1184						let final_event = FinalEvent::Return {
1185							returned: expected_return,
1186							position: returned_position,
1187						};
1188						self.info.events.push(final_event.into());
1189						return;
1190					}
1191				}
1192			}
1193		}
1194
1195		{
1196			let final_event = FinalEvent::Return { returned, position: returned_position };
1197			self.info.events.push(final_event.into());
1198
1199			// WIP
1200			let final_return = if let ReturnState::Rolling { under, returned: rolling_returning } =
1201				self.info.state
1202			{
1203				checking_data.types.new_conditional_type(under, rolling_returning, returned)
1204			} else {
1205				returned
1206			};
1207			self.info.state = ReturnState::Finished(final_return);
1208		}
1209	}
1210
1211	pub fn add_continue(
1212		&mut self,
1213		label: Option<&str>,
1214		position: Span,
1215	) -> Result<(), NotInLoopOrCouldNotFindLabel> {
1216		if let Some(carry) = self.find_label_or_conditional_count(label, true) {
1217			self.info.events.push(
1218				FinalEvent::Continue { position: position.with_source(self.get_source()), carry }
1219					.into(),
1220			);
1221			Ok(())
1222		} else {
1223			Err(NotInLoopOrCouldNotFindLabel {
1224				label: label.map(ToOwned::to_owned),
1225				position: position.with_source(self.get_source()),
1226			})
1227		}
1228	}
1229
1230	pub fn add_break(
1231		&mut self,
1232		label: Option<&str>,
1233		position: Span,
1234	) -> Result<(), NotInLoopOrCouldNotFindLabel> {
1235		if let Some(carry) = self.find_label_or_conditional_count(label, false) {
1236			self.info.events.push(
1237				FinalEvent::Break { position: position.with_source(self.get_source()), carry }
1238					.into(),
1239			);
1240			Ok(())
1241		} else {
1242			Err(NotInLoopOrCouldNotFindLabel {
1243				label: label.map(ToOwned::to_owned),
1244				position: position.with_source(self.get_source()),
1245			})
1246		}
1247	}
1248
1249	/// Updates **a existing property**
1250	///
1251	/// Returns the result of the setter... TODO could return new else
1252	#[allow(clippy::too_many_arguments)]
1253	pub fn set_property_handle_errors<T: crate::ReadFromFS, A: crate::ASTImplementation>(
1254		&mut self,
1255		on: TypeId,
1256		publicity: Publicity,
1257		under: &PropertyKey,
1258		new: TypeId,
1259		setter_position: SpanWithSource,
1260		checking_data: &mut CheckingData<T, A>,
1261	) {
1262		// For setters
1263		let mut diagnostics = Default::default();
1264		let result = crate::types::properties::set_property(
1265			on,
1266			(publicity, under, new),
1267			setter_position,
1268			self,
1269			(&mut CheckThings { debug_types: checking_data.options.debug_types }, &mut diagnostics),
1270			&mut checking_data.types,
1271		);
1272		diagnostics.append_to(
1273			crate::types::calling::CallingContext::Setter,
1274			&mut checking_data.diagnostics_container,
1275		);
1276
1277		match result {
1278			Ok(()) => {}
1279			Err(error) => {
1280				checking_data
1281					.diagnostics_container
1282					.add_error(TypeCheckError::SetPropertyError(error));
1283			}
1284		}
1285	}
1286
1287	/// `continue` has different behavior to `break` right?
1288	fn find_label_or_conditional_count(
1289		&self,
1290		looking_for_label: Option<&str>,
1291		is_continue: bool,
1292	) -> Option<u8> {
1293		let mut falling_through_structures = 0;
1294		for ctx in self.parents_iter() {
1295			if let GeneralContext::Syntax(ctx) = ctx {
1296				let scope = &ctx.context_type.scope;
1297
1298				match scope {
1299					Scope::TypeAnnotationCondition { .. }
1300					| Scope::TypeAnnotationConditionResult => unreachable!(),
1301					Scope::Function(_)
1302					| Scope::InterfaceEnvironment { .. }
1303					| Scope::FunctionAnnotation {}
1304					| Scope::Module { .. }
1305					| Scope::DefinitionModule { .. }
1306					| Scope::TypeAlias
1307					| Scope::StaticBlock { .. } => {
1308						break;
1309					}
1310					Scope::Iteration { ref label } => {
1311						if looking_for_label.is_none() {
1312							return Some(falling_through_structures);
1313						} else if let Some(label) = label {
1314							if label == looking_for_label.unwrap() {
1315								return Some(falling_through_structures);
1316							}
1317						}
1318						falling_through_structures += 1;
1319					}
1320					Scope::Conditional { is_switch: Some(_label @ Some(_)), .. }
1321						if !is_continue && looking_for_label.is_some() =>
1322					{
1323						crate::utilities::notify!("TODO");
1324					}
1325					Scope::Block {} => {
1326						crate::utilities::notify!("TODO");
1327					}
1328					Scope::PassThrough { .. }
1329					| Scope::Conditional { .. }
1330					| Scope::TryBlock {}
1331					| Scope::CatchBlock {}
1332					| Scope::FinallyBlock {}
1333					| Scope::DefaultFunctionParameter {} => {}
1334				}
1335			}
1336		}
1337		None
1338	}
1339
1340	pub fn declare_interface<'b, A: crate::ASTImplementation>(
1341		&mut self,
1342		name: &str,
1343		parameters: Option<&'b [A::TypeParameter<'b>]>,
1344		extends: Option<&'b [A::TypeAnnotation<'b>]>,
1345		types: &mut TypeStore,
1346	) -> Result<DeclareInterfaceResult, AlreadyExists> {
1347		// Interface merging
1348		{
1349			if let Some(id) = self.named_types.get(name) {
1350				let ty = types.get_type_by_id(*id);
1351				return if let Type::Interface { .. } = ty {
1352					Ok(DeclareInterfaceResult::Merging { ty: *id, in_same_context: true })
1353				} else {
1354					Err(AlreadyExists)
1355				};
1356			}
1357
1358			// It is fine that it doesn't necessarily need to be an interface
1359			let result = self
1360				.parents_iter()
1361				.find_map(|env| get_on_ctx!(env.named_types.get(name)))
1362				.and_then(|id| {
1363					matches!(types.get_type_by_id(*id), Type::Interface { .. }).then_some(*id)
1364				});
1365
1366			if let Some(existing) = result {
1367				return Ok(DeclareInterfaceResult::Merging {
1368					ty: existing,
1369					in_same_context: false,
1370				});
1371			};
1372		}
1373
1374		let parameters = parameters.map(|parameters| {
1375			parameters
1376				.iter()
1377				.map(|parameter| {
1378					let ty = Type::RootPolyType(PolyNature::StructureGeneric {
1379						name: A::type_parameter_name(parameter).to_owned(),
1380						// This is assigned later
1381						extends: TypeId::ANY_TO_INFER_TYPE,
1382					});
1383					types.register_type(ty)
1384				})
1385				.collect()
1386		});
1387
1388		let ty = Type::Interface {
1389			name: name.to_owned(),
1390			parameters,
1391			extends: extends.map(|_| TypeId::ANY_TO_INFER_TYPE),
1392		};
1393		let interface_ty = types.register_type(ty);
1394		self.named_types.insert(name.to_owned(), interface_ty);
1395		Ok(DeclareInterfaceResult::New(interface_ty))
1396	}
1397
1398	/// Registers the class type
1399	pub fn declare_class<'b, A: crate::ASTImplementation>(
1400		&mut self,
1401		name: &str,
1402		type_parameters: Option<&'b [A::TypeParameter<'b>]>,
1403		types: &mut TypeStore,
1404	) -> Result<TypeId, AlreadyExists> {
1405		{
1406			// Special
1407			if let Some(Scope::DefinitionModule { .. }) =
1408				self.context_type.as_syntax().map(|s| &s.scope)
1409			{
1410				match name {
1411					"Array" => {
1412						return Ok(TypeId::ARRAY_TYPE);
1413					}
1414					"Promise" => {
1415						return Ok(TypeId::PROMISE_TYPE);
1416					}
1417					"String" => {
1418						return Ok(TypeId::STRING_TYPE);
1419					}
1420					"Number" => {
1421						return Ok(TypeId::NUMBER_TYPE);
1422					}
1423					"Boolean" => {
1424						return Ok(TypeId::BOOLEAN_TYPE);
1425					}
1426					"RegExp" => {
1427						return Ok(TypeId::REGEXP_TYPE);
1428					}
1429					"Function" => {
1430						return Ok(TypeId::FUNCTION_TYPE);
1431					}
1432					"ImportMeta" => {
1433						return Ok(TypeId::IMPORT_META);
1434					}
1435					_ => {}
1436				}
1437			}
1438		}
1439
1440		let type_parameters = type_parameters.map(|type_parameters| {
1441			type_parameters
1442				.iter()
1443				.map(|parameter| {
1444					let ty = Type::RootPolyType(PolyNature::StructureGeneric {
1445						name: A::type_parameter_name(parameter).to_owned(),
1446						//A::parameter_constrained(parameter),
1447						// TODO
1448						extends: TypeId::ANY_TO_INFER_TYPE,
1449					});
1450					types.register_type(ty)
1451				})
1452				.collect()
1453		});
1454
1455		let ty = Type::Class { name: name.to_owned(), type_parameters };
1456		let class_type = types.register_type(ty);
1457		self.named_types.insert(name.to_owned(), class_type);
1458		// TODO duplicates
1459
1460		Ok(class_type)
1461	}
1462
1463	pub fn declare_alias<'b, A: crate::ASTImplementation>(
1464		&mut self,
1465		name: &str,
1466		parameters: Option<&'b [A::TypeParameter<'b>]>,
1467		_position: Span,
1468		types: &mut TypeStore,
1469	) -> Result<TypeId, AlreadyExists> {
1470		let parameters = parameters.map(|parameters| {
1471			parameters
1472				.iter()
1473				.map(|parameter| {
1474					let ty = Type::RootPolyType(PolyNature::StructureGeneric {
1475						name: A::type_parameter_name(parameter).to_owned(),
1476						// Set later for recursion
1477						extends: TypeId::ANY_TO_INFER_TYPE,
1478					});
1479					types.register_type(ty)
1480				})
1481				.collect()
1482		});
1483
1484		let ty = Type::AliasTo { to: TypeId::ANY_TO_INFER_TYPE, name: name.to_owned(), parameters };
1485		let alias_ty = types.register_type(ty);
1486		let existing_type = self.named_types.insert(name.to_owned(), alias_ty);
1487
1488		if existing_type.is_none() {
1489			Ok(alias_ty)
1490		} else {
1491			Err(AlreadyExists)
1492		}
1493	}
1494
1495	// TODO copy this logic for interface and class
1496	pub fn register_alias<'b, U: crate::ReadFromFS, A: crate::ASTImplementation>(
1497		&mut self,
1498		on: TypeId,
1499		ast_parameters: Option<&'b [A::TypeParameter<'b>]>,
1500		to: &'b A::TypeAnnotation<'b>,
1501		position: Span,
1502		checking_data: &mut CheckingData<U, A>,
1503	) {
1504		if on == TypeId::ERROR_TYPE {
1505			return;
1506		}
1507
1508		let new_to = if let Type::AliasTo { to: _, parameters: Some(parameters), name: _ } =
1509			checking_data.types.get_type_by_id(on)
1510		{
1511			let mut sub_environment = self.new_lexical_environment(Scope::TypeAlias);
1512			let parameters = parameters.clone();
1513			for parameter in parameters.iter().copied() {
1514				let Type::RootPolyType(PolyNature::StructureGeneric { name, .. }) =
1515					checking_data.types.get_type_by_id(parameter)
1516				else {
1517					unreachable!()
1518				};
1519				sub_environment.named_types.insert(name.clone(), parameter);
1520			}
1521			for (parameter, ast_parameter) in parameters.into_iter().zip(ast_parameters.unwrap()) {
1522				let new_to = A::synthesise_type_parameter_extends(
1523					ast_parameter,
1524					&mut sub_environment,
1525					checking_data,
1526				);
1527				checking_data.types.update_generic_extends(parameter, new_to);
1528			}
1529			let ty = A::synthesise_type_annotation(to, &mut sub_environment, checking_data);
1530			// TODO temp as object types use the same environment.properties representation
1531			{
1532				let crate::LocalInformation { current_properties, prototypes, .. } =
1533					sub_environment.info;
1534				self.info.current_properties.extend(current_properties);
1535				self.info.prototypes.extend(prototypes);
1536			}
1537
1538			// TODO check cycles
1539			ty
1540		} else {
1541			let ty = A::synthesise_type_annotation(to, self, checking_data);
1542
1543			// Cycle checking
1544			let disjoint = crate::types::disjoint::types_are_disjoint(
1545				ty,
1546				on,
1547				&mut Vec::new(),
1548				self,
1549				&checking_data.types,
1550			);
1551
1552			if disjoint {
1553				ty
1554			} else {
1555				checking_data.diagnostics_container.add_error(TypeCheckError::CyclicTypeAlias {
1556					position: position.with_source(self.get_source()),
1557				});
1558				TypeId::ERROR_TYPE
1559			}
1560		};
1561
1562		checking_data.types.update_alias(on, new_to);
1563	}
1564
1565	/// For functions and classes
1566	pub(crate) fn register_constructable_function(
1567		&mut self,
1568		referenced_in_scope_as: TypeId,
1569		function: crate::FunctionId,
1570	) {
1571		self.info.events.push(Event::Miscellaneous(
1572			crate::events::MiscellaneousEvents::CreateConstructor {
1573				referenced_in_scope_as,
1574				function,
1575			},
1576		));
1577	}
1578
1579	pub fn new_infer_type(
1580		&mut self,
1581		expected: TypeId,
1582		infer_name: &str,
1583		types: &mut TypeStore,
1584	) -> TypeId {
1585		if let Scope::TypeAnnotationCondition { ref mut infer_parameters } = self.context_type.scope
1586		{
1587			let infer_type = types.register_type(Type::RootPolyType(PolyNature::InferGeneric {
1588				name: infer_name.to_owned(),
1589				extends: expected,
1590			}));
1591
1592			let existing = infer_parameters.insert(infer_name.to_owned(), infer_type);
1593			if existing.is_some() {
1594				crate::utilities::notify!("Raise error diagnostic");
1595			}
1596			infer_type
1597		} else {
1598			crate::utilities::notify!("Raise error diagnostic");
1599			TypeId::UNIMPLEMENTED_ERROR_TYPE
1600		}
1601	}
1602}