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
36pub type ContextLocation = Option<String>;
38
39pub 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 pub free_variables: HashSet<RootReference>,
55
56 pub closed_over_references: ClosedOverReferencesInScope,
59
60 pub location: ContextLocation,
62
63 pub requests: Vec<(TypeId, TypeId)>,
66}
67
68#[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 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#[derive(Debug, Clone)]
121pub enum FunctionScope {
122 ArrowFunction {
123 free_this_type: TypeId,
125 is_async: bool,
126 expected_return: Option<ExpectedReturnType>,
127 },
128 MethodFunction {
130 free_this_type: TypeId,
132 is_async: bool,
133 is_generator: bool,
134
135 expected_return: Option<ExpectedReturnType>,
136 },
137 Function {
139 is_generator: bool,
140 is_async: bool,
141 expected_return: Option<ExpectedReturnType>,
142 this_type: TypeId,
144 type_of_super: TypeId,
145 location: ContextLocation,
146 },
147 Constructor {
148 extends: bool,
150 type_of_super: Option<TypeId>,
151 this_object_type: TypeId,
153 },
154}
155
156impl FunctionScope {
157 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
168pub 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#[derive(Debug, Clone)]
180pub enum Scope {
181 Function(FunctionScope),
182 InterfaceEnvironment {
183 this_constraint: TypeId,
184 },
185 DefaultFunctionParameter {},
186 FunctionAnnotation {},
187 Conditional {
189 antecedent: TypeId,
191
192 is_switch: Option<Label>,
193 },
194 Iteration {
196 label: Label, },
198 TryBlock {},
199 CatchBlock {},
200 FinallyBlock {},
201 Block {},
203 Module {
204 source: SourceId,
205 exported: Exported,
206 },
207 DefinitionModule {
208 source: SourceId,
209 },
210 TypeAlias,
212 StaticBlock {
213 this_type: TypeId,
214 },
215 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 pub fn assign_handle_errors<'b, T: crate::ReadFromFS, A: crate::ASTImplementation>(
246 &mut self,
247 lhs: Assignable<A>,
248 operator: AssignmentKind,
249 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 let existing = self.get_reference(
279 reference.clone(),
280 checking_data,
281 AccessMode::Regular,
282 );
283
284 let expression = expression.unwrap();
285 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 position = reference.get_position();
342 let existing = self.get_reference(
343 reference.clone(),
344 checking_data,
345 AccessMode::Regular,
346 );
347
348 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 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 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 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 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 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 if let Some((kind, result)) = get_property {
845 Ok(match kind {
846 PropertyKind::Getter => Instance::GValue(result),
847 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 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 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 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 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 let variable_id = og_var.get_id();
983
984 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 for _ in 0..=(*count) {
1031 reversed_events.next();
1032 }
1033 }
1034 }
1035 }
1036
1037 let ty = if let Some(reused_reference) = reused_reference {
1038 let narrowed = self.get_narrowed_or_object(reused_reference, &checking_data.types);
1041 narrowed.unwrap_or(reused_reference)
1042 } else {
1043 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 self.context_type.free_variables.insert(reference);
1052
1053 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 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 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 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 {
1144 if let Some(ExpectedReturnType::FromReturnAnnotation(expected, position)) = expected {
1146 let mut state = State {
1149 already_checked: Default::default(),
1150 mode: Default::default(),
1151 contributions: Default::default(),
1152 others: SubTypingOptions::default(),
1153 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 {
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 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 #[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 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 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 {
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 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 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 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 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 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 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 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 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 {
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 ty
1540 } else {
1541 let ty = A::synthesise_type_annotation(to, self, checking_data);
1542
1543 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 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}