1use source_map::{BaseSpan, Nullable, SpanWithSource};
2
3use crate::{
4 context::{invocation::CheckThings, CallCheckingBehavior, Environment, InformationChain},
5 diagnostics::{
6 InfoDiagnostic, TypeCheckError, TypeCheckWarning, TypeStringRepresentation,
7 VariableUsedInTDZ,
8 },
9 events::{
10 application::ApplicationInput, apply_events, ApplicationResult, Event, RootReference,
11 },
12 features::{
13 constant_functions::{
14 call_constant_function, CallSiteTypeArguments, ConstantFunctionError, ConstantOutput,
15 },
16 objects::{ObjectBuilder, SpecialObject},
17 },
18 subtyping::{
19 type_is_subtype, type_is_subtype_with_generics, State, SubTypeResult, SubTypingMode,
20 SubTypingOptions,
21 },
22 types::{
23 functions::{FunctionBehavior, FunctionEffect, FunctionType},
24 generics::substitution::SubstitutionArguments,
25 helpers::get_structure_arguments_based_on_object_constraint,
26 logical::{Invalid, Logical, LogicalOrValid, NeedsCalculation, PossibleLogical},
27 properties::AccessMode,
28 substitute, GenericChainLink, ObjectNature, PartiallyAppliedGenerics, Type,
29 },
30 FunctionId, GenericTypeParameters, ReadFromFS, SpecialExpressions, TypeId,
31};
32
33use super::{
34 generics::{contributions::Contributions, generic_type_arguments::GenericArguments},
35 get_constraint,
36 properties::PropertyKey,
37 Constructor, GenericChain, PolyNature, TypeRestrictions, TypeStore,
38};
39
40#[derive(Clone, Copy)]
42pub struct CallingInput {
43 pub called_with_new: CalledWithNew,
45 pub call_site: SpanWithSource,
46
47 pub max_inline: u16,
49}
50
51#[derive(Clone, Copy, Debug, Default, binary_serialize_derive::BinarySerializable)]
52pub enum ThisValue {
53 Passed(TypeId),
54 #[default]
56 UseParent,
57}
58
59impl ThisValue {
60 pub(crate) fn get(
61 self,
62 environment: &mut Environment,
63 types: &TypeStore,
64 position: SpanWithSource,
65 ) -> TypeId {
66 match self {
67 ThisValue::Passed(value) => value,
68 ThisValue::UseParent => environment.get_value_of_this(types, position),
69 }
70 }
71
72 pub(crate) fn get_passed(self) -> Option<TypeId> {
73 match self {
74 ThisValue::Passed(value) => Some(value),
75 ThisValue::UseParent => None,
76 }
77 }
78}
79
80#[derive(Copy, Clone, Default)]
82pub enum CallingContext {
83 #[default]
84 Regular,
85 Getter,
86 Setter,
87 JSX,
88 TemplateLiteral,
89 Super,
90 Iteration,
91}
92
93#[derive(Default)]
94pub struct CallingDiagnostics {
95 pub errors: Vec<FunctionCallingError>,
96 pub warnings: Vec<crate::diagnostics::TypeCheckWarning>,
97 pub info: Vec<crate::diagnostics::InfoDiagnostic>,
98}
99
100impl CallingDiagnostics {
101 pub(crate) fn append_to(
102 self,
103 context: CallingContext,
104 diagnostics_container: &mut crate::DiagnosticsContainer,
105 ) {
106 self.errors.into_iter().for_each(|error| {
107 let error = match context {
108 CallingContext::Regular => TypeCheckError::FunctionCallingError(error),
109 CallingContext::JSX => TypeCheckError::JSXCallingError(error),
110 CallingContext::TemplateLiteral => {
111 TypeCheckError::TemplateLiteralCallingError(error)
112 }
113 CallingContext::Getter => TypeCheckError::GetterCallingError(error),
114 CallingContext::Setter => TypeCheckError::SetterCallingError(error),
115 CallingContext::Super => TypeCheckError::SuperCallError(error),
116 #[allow(clippy::match_same_arms)]
118 CallingContext::Iteration => TypeCheckError::FunctionCallingError(error),
119 };
120 diagnostics_container.add_error(error);
121 });
122 self.warnings.into_iter().for_each(|warning| diagnostics_container.add_warning(warning));
123 self.info.into_iter().for_each(|crate::diagnostics::InfoDiagnostic(message, position)| {
124 diagnostics_container.add_info(crate::diagnostics::Diagnostic::Position {
125 reason: message,
126 position,
127 kind: crate::diagnostics::DiagnosticKind::Info,
128 });
129 });
130 }
131}
132
133#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
134pub struct SynthesisedArgument {
135 pub(crate) spread: bool,
136 pub(crate) value: TypeId,
137 pub(crate) position: SpanWithSource,
138}
139
140impl SynthesisedArgument {
141 pub fn non_spread_type(&self) -> Result<TypeId, ()> {
142 if self.spread {
143 Err(())
144 } else {
145 Ok(self.value)
146 }
147 }
148}
149
150pub struct UnsynthesisedArgument<'a, A: crate::ASTImplementation> {
152 pub spread: bool,
153 pub expression: &'a A::Expression<'a>,
154}
155
156#[derive(Debug, Clone, binary_serialize_derive::BinarySerializable)]
160pub struct FunctionLike {
161 pub(crate) function: FunctionId,
162 pub(crate) from: Option<TypeId>,
164 pub(crate) this_value: ThisValue,
166}
167
168pub struct CallingOutput {
169 pub called: Option<FunctionId>,
170 pub result: Option<ApplicationResult>,
172 pub special: Option<SpecialExpressions>,
173 pub result_was_const_computation: bool,
175}
176
177pub struct BadCallOutput {
178 pub returned_type: TypeId,
180}
181
182pub fn call_type_handle_errors<T: crate::ReadFromFS, A: crate::ASTImplementation>(
184 ty: TypeId,
185 call_site_type_arguments: Option<Vec<(TypeId, SpanWithSource)>>,
186 arguments: &[UnsynthesisedArgument<A>],
187 input: CallingInput,
188 environment: &mut Environment,
189 checking_data: &mut crate::CheckingData<T, A>,
190 _expected: TypeId,
191) -> (TypeId, Option<SpecialExpressions>) {
192 let call_site = input.call_site;
193
194 let callable = get_logical_callable_from_type(ty, None, None, &checking_data.types);
196
197 match callable {
198 Ok(LogicalOrValid::Logical(callable)) => {
199 let parent_arguments = if let Logical::Pure(FunctionLike {
203 this_value: ThisValue::Passed(this_passed),
204 ..
205 }) = callable
206 {
207 if let Type::Object(..) = checking_data.types.get_type_by_id(this_passed) {
208 if let Some(arguments) = get_structure_arguments_based_on_object_constraint(
209 this_passed,
210 environment,
211 &checking_data.types,
212 ) {
213 crate::utilities::notify!("Here :)");
214 Some(arguments.clone())
215 } else {
216 let prototype = environment
217 .get_chain_of_info()
218 .find_map(|facts| facts.prototypes.get(&this_passed))
219 .copied();
220
221 if prototype.is_some_and(|prototype| {
222 checking_data.types.lookup_generic_map.contains_key(&prototype)
223 }) {
224 crate::utilities::notify!("Registering lookup for calling");
225
226 Some(GenericArguments::LookUp { on: this_passed })
227 } else {
228 None
229 }
230 }
231 } else {
232 None
233 }
234 } else {
235 None
236 };
237
238 let (arguments, type_argument_restrictions) =
239 synthesise_argument_expressions_wrt_parameters(
240 &callable,
241 arguments,
242 (call_site_type_arguments, parent_arguments.as_ref()),
243 environment,
244 checking_data,
245 );
246
247 let mut check_things = CheckThings { debug_types: checking_data.options.debug_types };
248 let mut diagnostics = CallingDiagnostics::default();
249 let result = call_logical(
250 callable,
251 (arguments, type_argument_restrictions, parent_arguments),
252 input,
253 environment,
254 &mut checking_data.types,
255 (&mut check_things, &mut diagnostics),
256 );
257
258 diagnostics
259 .append_to(CallingContext::Regular, &mut checking_data.diagnostics_container);
260
261 match result {
262 Ok(CallingOutput {
263 result,
264 called: _,
265 special,
266 result_was_const_computation: _,
267 }) => {
268 let returned_type = application_result_to_return_type(
269 result,
270 environment,
271 &mut checking_data.types,
272 );
273
274 (returned_type, special)
275 }
276 Err(error) => (error.returned_type, None),
277 }
278 }
279 Ok(LogicalOrValid::NeedsCalculation(l)) => match l {
280 NeedsCalculation::Infer { on } => {
281 if on == TypeId::ERROR_TYPE {
282 (TypeId::UNIMPLEMENTED_ERROR_TYPE, None)
283 } else {
284 crate::utilities::notify!("TODO function calling inference on {:?}", on);
285 (TypeId::UNIMPLEMENTED_ERROR_TYPE, None)
286 }
287 }
288 NeedsCalculation::Proxy(..) => {
289 crate::utilities::notify!("TODO calling proxy");
290 (TypeId::UNIMPLEMENTED_ERROR_TYPE, None)
291 }
292 },
293 Err(Invalid(ty)) => {
294 checking_data.diagnostics_container.add_error(TypeCheckError::FunctionCallingError(
295 FunctionCallingError::NotCallable {
296 calling: TypeStringRepresentation::from_type_id(
297 ty,
298 environment,
299 &checking_data.types,
300 checking_data.options.debug_types,
301 ),
302 call_site,
303 },
304 ));
305 (TypeId::ERROR_TYPE, None)
306 }
307 }
308}
309
310pub fn application_result_to_return_type(
312 result: Option<ApplicationResult>,
313 environment: &mut Environment,
314 types: &mut TypeStore,
315) -> TypeId {
316 if let Some(result) = result {
317 match result {
318 ApplicationResult::Return { returned, position: _ } => returned,
320 ApplicationResult::Throw { thrown, position } => {
321 environment.throw_value(thrown, position, types);
322 TypeId::NEVER_TYPE
323 }
324 ApplicationResult::Yield {} => todo!("Create generator object"),
325 ApplicationResult::Or { on, truthy_result, otherwise_result } => {
326 let truthy_result =
327 application_result_to_return_type(Some(*truthy_result), environment, types);
328 let otherwise_result =
329 application_result_to_return_type(Some(*otherwise_result), environment, types);
330 types.new_conditional_type(on, truthy_result, otherwise_result)
331 }
332 ApplicationResult::Continue { .. } | ApplicationResult::Break { .. } => {
333 unreachable!("returning conditional or break (carry failed)")
334 }
335 }
336 } else {
337 TypeId::UNDEFINED_TYPE
338 }
339}
340
341#[derive(Debug, Copy, Clone, binary_serialize_derive::BinarySerializable)]
342pub enum Callable {
343 Fixed(FunctionId, ThisValue),
345 Type(TypeId),
346}
347
348impl Callable {
349 pub(crate) fn from_type(ty: TypeId, types: &TypeStore) -> Self {
350 if let Type::SpecialObject(SpecialObject::Function(func_id, _)) = types.get_type_by_id(ty) {
351 Callable::Fixed(*func_id, ThisValue::UseParent)
352 } else {
353 crate::utilities::notify!("Here!!");
354 Callable::Type(ty)
355 }
356 }
357
358 pub(crate) fn new_from_function(function: FunctionType, types: &mut TypeStore) -> Self {
359 let id = function.id;
360 types.functions.insert(id, function);
361 Callable::Fixed(id, ThisValue::UseParent)
362 }
363
364 pub(crate) fn into_type(self, types: &mut TypeStore) -> TypeId {
365 match self {
366 Callable::Fixed(id, this_value) => {
367 types.register_type(Type::SpecialObject(SpecialObject::Function(id, this_value)))
368 }
369 Callable::Type(ty) => ty,
370 }
371 }
372
373 pub(crate) fn get_return_type(self, types: &TypeStore) -> TypeId {
374 match self {
375 Callable::Fixed(id, _this_value) => types.get_function_from_id(id).return_type,
376 Callable::Type(ty) => {
377 if let Type::SpecialObject(SpecialObject::Function(id, _)) =
378 types.get_type_by_id(ty)
379 {
380 types.get_function_from_id(*id).return_type
381 } else {
382 crate::utilities::notify!("Cannot get return type");
383 TypeId::UNIMPLEMENTED_ERROR_TYPE
384 }
385 }
386 }
387 }
388
389 pub(crate) fn get_first_argument(self, types: &TypeStore) -> TypeId {
390 match self {
391 Callable::Fixed(id, _this_value) => types
392 .get_function_from_id(id)
393 .parameters
394 .get_parameter_type_at_index(0)
395 .map_or(TypeId::ERROR_TYPE, |(ty, _)| ty),
396 Callable::Type(ty) => {
397 if let Type::SpecialObject(SpecialObject::Function(id, _)) =
398 types.get_type_by_id(ty)
399 {
400 types
401 .get_function_from_id(*id)
402 .parameters
403 .get_parameter_type_at_index(0)
404 .map_or(TypeId::ERROR_TYPE, |(ty, _)| ty)
405 } else {
406 crate::utilities::notify!("Cannot get first arugment");
407 TypeId::ERROR_TYPE
408 }
409 }
410 }
411 }
412
413 pub(crate) fn call<B: CallCheckingBehavior>(
414 self,
415 arguments: Vec<SynthesisedArgument>,
416 input: CallingInput,
417 top_environment: &mut Environment,
418 (behavior, diagnostics): (&mut B, &mut CallingDiagnostics),
419 types: &mut TypeStore,
420 ) -> Result<CallingOutput, BadCallOutput> {
421 match self {
422 Callable::Fixed(on, this_value) => {
423 let function_like = FunctionLike { function: on, from: None, this_value };
424
425 call_logical(
426 Logical::Pure(function_like),
427 (arguments, None, None),
428 input,
429 top_environment,
430 types,
431 (behavior, diagnostics),
432 )
433 }
434 Callable::Type(on) => {
435 let callable = get_logical_callable_from_type(on, None, None, types);
436 if let Ok(LogicalOrValid::Logical(callable)) = callable {
437 call_logical(
438 callable,
439 (arguments, None, None),
440 input,
441 top_environment,
442 types,
443 (behavior, diagnostics),
444 )
445 } else {
446 crate::utilities::notify!("callable={:?}", callable);
447
448 diagnostics.errors.push(FunctionCallingError::NotCallable {
449 calling: crate::diagnostics::TypeStringRepresentation::from_type_id(
450 on,
451 top_environment,
452 types,
453 behavior.debug_types(),
454 ),
455 call_site: input.call_site,
456 });
457
458 Err(BadCallOutput { returned_type: TypeId::ERROR_TYPE })
459 }
460 }
461 }
462 }
463}
464
465fn get_logical_callable_from_type(
467 ty: TypeId,
468 on: Option<ThisValue>,
469 from: Option<TypeId>,
470 types: &TypeStore,
471) -> PossibleLogical<FunctionLike> {
472 if ty == TypeId::ANY_TYPE {
476 crate::utilities::notify!("Calling ANY");
477 return Ok(NeedsCalculation::Infer { on: from.unwrap_or(TypeId::ERROR_TYPE) }.into());
479 }
480
481 let le_ty = types.get_type_by_id(ty);
482
483 match le_ty {
484 Type::Class { .. } | Type::Interface { .. } | Type::Constant(_) | Type::Object(_) => {
485 Err(Invalid(ty))
486 }
487 Type::And(_, _) => todo!(),
488 Type::Or(left, right) => {
489 let left = get_logical_callable_from_type(*left, on, from, types)?;
490 let right = get_logical_callable_from_type(*right, on, from, types)?;
491 Ok(Logical::Or {
492 condition: TypeId::OPEN_BOOLEAN_TYPE,
493 left: Box::new(left),
494 right: Box::new(right),
495 }
496 .into())
497 }
498 Type::Narrowed { narrowed_to, from } => {
499 get_logical_callable_from_type(*narrowed_to, on, Some(*from), types)
500 }
501 Type::AliasTo { to, name: _, parameters } => {
502 if parameters.is_some() {
503 todo!()
504 }
505 get_logical_callable_from_type(*to, on, from, types)
506 }
507 Type::FunctionReference(f) => {
508 let function = FunctionLike {
509 function: *f,
511 from,
512 this_value: on.unwrap_or(ThisValue::UseParent),
513 };
514 Ok(Logical::Pure(function).into())
515 }
516 Type::SpecialObject(SpecialObject::Function(f, t)) => {
517 let this_value = on.unwrap_or(*t);
518 let from = Some(from.unwrap_or(ty));
519 Ok(Logical::Pure(FunctionLike { from, function: *f, this_value }).into())
520 }
521 Type::SpecialObject(so) => match so {
522 crate::features::objects::SpecialObject::Proxy { .. } => todo!(),
523 _ => Err(Invalid(ty)),
524 },
525 Type::PartiallyAppliedGenerics(generic) => {
526 let result = get_logical_callable_from_type(generic.on, on, from, types)?;
527 if let LogicalOrValid::Logical(result) = result {
528 Ok(Logical::Implies { on: Box::new(result), antecedent: generic.arguments.clone() }
529 .into())
530 } else {
531 crate::utilities::notify!("Should not be here");
532 Ok(result)
533 }
534 }
535 Type::Constructor(Constructor::Property { on, under: _, result, mode }) => {
536 crate::utilities::notify!("Passing {:?}", on);
537
538 let this_value = if let AccessMode::DoNotBindThis = mode {
539 ThisValue::UseParent
540 } else {
541 ThisValue::Passed(*on)
542 };
543 let result =
544 get_logical_callable_from_type(*result, Some(this_value), Some(ty), types)?;
545
546 let and_then = get_constraint(*on, types).and_then(|c| {
547 if let Type::PartiallyAppliedGenerics(generic) = types.get_type_by_id(c) {
548 Some(generic.arguments.clone())
549 } else {
550 None
551 }
552 });
553
554 if let Some(antecedent) = and_then {
555 if let LogicalOrValid::Logical(result) = result {
556 Ok(Logical::Implies { on: Box::new(result), antecedent }.into())
557 } else {
558 crate::utilities::notify!("TODO not antecedent {:?}", antecedent);
559 Ok(result)
560 }
561 } else {
562 Ok(result)
563 }
564 }
565 Type::RootPolyType(_) | Type::Constructor(_) => {
566 let constraint = get_constraint(ty, types).unwrap();
567 crate::utilities::notify!(
568 "Getting callable constructor / root poly type! {:?}",
569 constraint
570 );
571 get_logical_callable_from_type(constraint, on, Some(ty), types)
572 }
573 }
574}
575
576#[allow(clippy::too_many_arguments)]
577fn call_logical<B: CallCheckingBehavior>(
578 logical: Logical<FunctionLike>,
579 (arguments, explicit_type_arguments, structure_generics): (
580 Vec<SynthesisedArgument>,
581 Option<CallSiteTypeArguments>,
582 Option<GenericArguments>,
583 ),
584 input: CallingInput,
585 top_environment: &mut Environment,
586 types: &mut TypeStore,
587 (behavior, diagnostics): (&mut B, &mut CallingDiagnostics),
588) -> Result<CallingOutput, BadCallOutput> {
589 match logical {
590 Logical::Pure(function) => {
591 if let Some(function_type) = types.functions.get(&function.function) {
592 let function_type = function_type.clone();
594
595 if let FunctionEffect::Constant { identifier: ref const_fn_ident, .. } =
596 &function_type.effect
597 {
598 let has_dependent_argument =
599 arguments.iter().any(|arg| types.get_type_by_id(arg.value).is_dependent());
600
601 crate::utilities::notify!(
604 "has_dependent_argument={:?}, const_fn_ident={:?}",
605 has_dependent_argument,
606 const_fn_ident
607 );
608
609 let is_independent_function = const_fn_ident.ends_with("independent");
611
612 let call_anyway = const_fn_ident.starts_with("debug")
613 || const_fn_ident.starts_with("print")
614 || is_independent_function
615 || matches!(
616 const_fn_ident.as_str(),
617 "satisfies"
618 | "is_dependent" | "bind"
619 | "proxy:constructor" | "setPrototypeOf"
620 | "getPrototypeOf"
621 );
622
623 if is_independent_function && B::CHECK_PARAMETERS {
639 let function_id = function.function;
640 let value = Event::CallsType {
641 on: Callable::Fixed(function.function, function.this_value),
642 with: arguments.clone().into_boxed_slice(),
643 timing: crate::events::CallingTiming::Synchronous,
644 called_with_new: input.called_with_new,
645 reflects_dependency: None,
646 call_site: input.call_site,
647 possibly_thrown: None,
648 };
649 behavior.get_latest_info(top_environment).events.push(value);
650 return Ok(CallingOutput {
651 called: Some(function_id),
652 result: None,
653 special: Some(SpecialExpressions::Marker),
654 result_was_const_computation: true,
655 });
656 }
657
658 if call_anyway || !has_dependent_argument {
661 let result = call_constant_function(
663 const_fn_ident,
664 function.this_value,
666 explicit_type_arguments.as_ref(),
667 &arguments,
668 types,
669 top_environment,
670 input.call_site,
671 diagnostics,
672 );
673
674 match result {
675 Ok(ConstantOutput::Value(value)) => {
676 let special = if const_fn_ident == "compile_type_to_object" {
678 Some(SpecialExpressions::CompileOut)
679 } else {
680 None
681 };
682 return Ok(CallingOutput {
683 result: Some(ApplicationResult::Return {
684 returned: value,
685 position: input.call_site,
686 }),
687 called: None,
688 result_was_const_computation: !is_independent_function,
689 special,
690 });
691 }
692 Ok(ConstantOutput::Diagnostic(diagnostic)) => {
693 diagnostics.info.push(InfoDiagnostic(diagnostic, input.call_site));
694 return Ok(CallingOutput {
695 result: None,
696 called: None,
697 result_was_const_computation: !is_independent_function,
698 special: Some(SpecialExpressions::Marker),
700 });
701 }
702 Err(ConstantFunctionError::NoLogicForIdentifier(name)) => {
703 let err = FunctionCallingError::NoLogicForIdentifier(
704 name,
705 input.call_site,
706 );
707 diagnostics.errors.push(err);
708 return Err(BadCallOutput {
709 returned_type: types.new_error_type(function_type.return_type),
710 });
711 }
712 Err(ConstantFunctionError::FunctionCallingError(err)) => {
713 diagnostics.errors.push(err);
714 return Err(BadCallOutput {
715 returned_type: types.new_error_type(function_type.return_type),
716 });
717 }
718 Err(ConstantFunctionError::CannotComputeConstant) => {
719 crate::utilities::notify!(
720 "Constant function calling failed, non constant params"
721 );
722 }
723 }
724 } else if !has_dependent_argument {
725 let call = function_type.call(
727 (
728 function.this_value,
729 &arguments,
730 explicit_type_arguments,
731 structure_generics,
732 ),
733 input,
734 top_environment,
735 (behavior, diagnostics),
736 types,
737 );
738
739 return match call {
740 Ok(call) => Ok(CallingOutput {
741 result: call.result,
742 called: None,
743 special: None,
744 result_was_const_computation: false,
745 }),
747 Err(err) => {
748 crate::utilities::notify!(
749 "Calling function with dependent argument failed"
750 );
751 Err(err)
752 }
753 };
754 }
755 }
756
757 let structure_generics = if let (false, Some(on)) =
759 (structure_generics.is_some(), function.this_value.get_passed())
760 {
761 if let Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
762 on: _,
763 arguments,
764 }) = types.get_type_by_id(get_constraint(on, types).unwrap_or(on))
765 {
766 Some(arguments.clone())
767 } else {
768 None
769 }
770 } else {
771 structure_generics
772 };
773
774 let mut result = function_type.call(
775 (function.this_value, &arguments, explicit_type_arguments, structure_generics),
776 input,
777 top_environment,
778 (behavior, diagnostics),
779 types,
780 )?;
781
782 let is_poly_or_failed_const_call = matches!(
786 function_type.effect,
787 FunctionEffect::Unknown | FunctionEffect::InputOutput { .. }
788 ) || (matches!(function_type.effect, FunctionEffect::Constant { .. } if !result.result_was_const_computation));
789
790 if is_poly_or_failed_const_call && function.from.is_some() {
791 let with = arguments.clone().into_boxed_slice();
822 let result_as_type = application_result_to_return_type(
823 result.result.take(),
824 top_environment,
825 types,
826 );
827 let reflects_dependency = if types.get_type_by_id(result_as_type).is_constant()
828 {
829 None
830 } else {
831 let id = types.register_type(Type::Constructor(Constructor::Image {
832 on: function.from.expect("function `on`"),
834 with: with.clone(),
836 result: result_as_type,
837 }));
838
839 Some(id)
840 };
841
842 result.result = Some(ApplicationResult::Return {
843 returned: reflects_dependency.unwrap_or(result_as_type),
844 position: input.call_site,
845 });
846
847 let possibly_thrown = if let FunctionEffect::InputOutput { may_throw, .. }
848 | FunctionEffect::Constant { may_throw, .. } = &function_type.effect
849 {
850 *may_throw
852 } else {
853 None
854 };
855
856 let on = match function.from {
857 Some(ty) => Callable::Type(ty),
858 None => Callable::Fixed(function.function, function.this_value),
859 };
860 behavior.get_latest_info(top_environment).events.push(Event::CallsType {
861 on,
862 with,
863 timing: crate::events::CallingTiming::Synchronous,
864 called_with_new: input.called_with_new,
865 reflects_dependency,
866 call_site: input.call_site,
867 possibly_thrown,
868 });
869 } else {
870 let value = Event::Miscellaneous(
873 crate::events::MiscellaneousEvents::MarkFunctionAsCalled(function.function),
874 );
875 behavior.get_latest_info(top_environment).events.push(value);
876 }
877
878 Ok(result)
879 } else {
880 panic!("no function")
881 }
882 }
883 Logical::Or { .. } => {
884 crate::utilities::notify!("Calling OR");
885 Err(BadCallOutput { returned_type: TypeId::UNIMPLEMENTED_ERROR_TYPE })
886 }
939 Logical::Implies { on, antecedent } => {
940 call_logical(
942 *on,
943 (arguments, explicit_type_arguments, Some(antecedent)),
944 input,
945 top_environment,
946 types,
947 (behavior, diagnostics),
948 )
949 }
950 Logical::BasedOnKey { .. } => {
951 crate::utilities::notify!("Calling based on key?");
952 Err(BadCallOutput { returned_type: TypeId::UNIMPLEMENTED_ERROR_TYPE })
953 }
954 }
955}
956
957fn mark_possible_mutation(
958 argument: &SynthesisedArgument,
959 parameter_type: TypeId,
960 types: &mut TypeStore,
961 top_environment: &mut Environment,
962) {
963 match types.get_type_by_id(argument.value) {
964 Type::Interface { .. }
965 | Type::Class { .. }
966 | Type::AliasTo { .. }
967 | Type::And(_, _)
968 | Type::Object(ObjectNature::AnonymousTypeAnnotation(_))
969 | Type::FunctionReference(_)
970 | Type::PartiallyAppliedGenerics(_)
971 | Type::Or(_, _) => {
972 crate::utilities::notify!("Unreachable");
973 }
974 Type::Constant(_) => {}
975 Type::Narrowed { .. } | Type::RootPolyType(_) | Type::Constructor(_) => {
976 crate::utilities::notify!("TODO if any properties set etc");
978 }
979 Type::SpecialObject(SpecialObject::Function(_, _)) => {
980 crate::utilities::notify!("TODO record that function could be called");
981 }
982 Type::Object(ObjectNature::RealDeal) => {
983 top_environment.possibly_mutated_objects.insert(argument.value, parameter_type);
984 crate::utilities::notify!("TODO record methods could be called here as well");
985 }
986 Type::SpecialObject(_) => {
987 crate::utilities::notify!("TODO record stuff if mutable");
988 }
989 }
990}
991
992pub enum FunctionCallingError {
994 InvalidArgumentType {
995 parameter_type: TypeStringRepresentation,
996 argument_type: TypeStringRepresentation,
997 argument_position: SpanWithSource,
998 parameter_position: SpanWithSource,
999 restriction: Option<(SpanWithSource, TypeStringRepresentation)>,
1000 },
1001 MissingArgument {
1002 parameter_position: SpanWithSource,
1003 call_site: SpanWithSource,
1004 },
1005 ExcessArguments {
1006 count: usize,
1007 position: SpanWithSource,
1008 },
1009 ExcessTypeArguments {
1010 expected_count: usize,
1011 count: usize,
1012 position: SpanWithSource,
1013 },
1014 NotCallable {
1015 calling: TypeStringRepresentation,
1016 call_site: SpanWithSource,
1017 },
1018 ReferenceRestrictionDoesNotMatch {
1019 reference: RootReference,
1020 requirement: TypeStringRepresentation,
1021 found: TypeStringRepresentation,
1022 },
1023 CyclicRecursion(FunctionId, SpanWithSource),
1024 NoLogicForIdentifier(String, SpanWithSource),
1025 NeedsToBeCalledWithNewKeyword(SpanWithSource),
1026 VariableUsedInTDZ {
1027 error: VariableUsedInTDZ,
1028 call_site: SpanWithSource,
1030 },
1031 InvalidRegExp(crate::diagnostics::InvalidRegExp),
1032 SetPropertyConstraint {
1034 property_type: TypeStringRepresentation,
1035 value_type: TypeStringRepresentation,
1036 assignment_position: SpanWithSource,
1037 call_site: SpanWithSource,
1039 },
1040 DeleteConstraint {
1042 constraint: TypeStringRepresentation,
1043 delete_position: SpanWithSource,
1044 call_site: SpanWithSource,
1046 },
1047 NotConfigurable {
1048 property: crate::diagnostics::PropertyKeyRepresentation,
1049 call_site: SpanWithSource,
1051 },
1052 MismatchedThis {
1053 expected: TypeStringRepresentation,
1054 found: TypeStringRepresentation,
1055 call_site: SpanWithSource,
1056 },
1057 CannotCatch {
1058 catch: TypeStringRepresentation,
1059 thrown: TypeStringRepresentation,
1060 thrown_position: SpanWithSource,
1061 },
1062}
1063
1064#[derive(Debug, Default, Clone, Copy, binary_serialize_derive::BinarySerializable)]
1065pub enum CalledWithNew {
1066 New {
1068 on: TypeId,
1070 },
1071 GetterOrSetter {
1072 this_type: TypeId,
1073 },
1074 Super {
1076 this_type: TypeId,
1077 },
1078 #[default]
1079 None,
1080}
1081
1082impl FunctionType {
1083 pub(crate) fn call<B: CallCheckingBehavior>(
1085 &self,
1086 (this_value, arguments, call_site_type_arguments, parent_arguments): (
1087 ThisValue,
1088 &[SynthesisedArgument],
1089 Option<CallSiteTypeArguments>,
1090 Option<GenericArguments>,
1091 ),
1092 input: CallingInput,
1093 environment: &mut Environment,
1094 (behavior, diagnostics): (&mut B, &mut CallingDiagnostics),
1095 types: &mut crate::TypeStore,
1096 ) -> Result<CallingOutput, BadCallOutput> {
1097 if behavior.in_recursive_cycle(self.id) {
1099 crate::utilities::notify!("Encountered recursion");
1100 crate::utilities::notify!("TODO should be BadCallOutput");
1101 let returned = types.new_error_type(self.return_type);
1102 return Ok(CallingOutput {
1103 called: Some(self.id),
1104 result: Some(ApplicationResult::Return { returned, position: input.call_site }),
1105 special: None,
1107 result_was_const_computation: false,
1108 });
1109 }
1112
1113 if environment.is_always_run() {
1114 types.called_functions.insert(self.id);
1115 }
1116
1117 let errors = CallingDiagnostics::default();
1118
1119 let mut type_arguments = SubstitutionArguments {
1120 parent: None,
1121 arguments: crate::Map::default(),
1122 closures: if let Some(GenericArguments::Closure(ref cs)) = parent_arguments {
1123 cs.clone()
1124 } else {
1125 Default::default()
1126 },
1127 };
1128
1129 self.set_this_for_behavior(
1130 input.called_with_new,
1131 this_value,
1132 &mut type_arguments.arguments,
1133 environment,
1134 types,
1135 input.call_site,
1136 (behavior, diagnostics),
1137 );
1138
1139 self.assign_arguments_to_parameters::<B>(
1140 arguments,
1141 &mut type_arguments,
1142 (call_site_type_arguments.clone(), parent_arguments.as_ref()),
1143 environment,
1144 types,
1145 input.call_site,
1146 matches!(self.effect, FunctionEffect::SideEffects { .. }),
1147 (behavior, diagnostics),
1148 );
1149
1150 if !diagnostics.errors.is_empty() {
1151 return Err(BadCallOutput {
1152 returned_type: types.new_error_type(self.return_type),
1154 });
1155 }
1156
1157 let result = if let FunctionEffect::SideEffects {
1158 events,
1159 closed_over_variables,
1160 free_variables: _,
1161 } = &self.effect
1162 {
1163 behavior.new_function_context(self.id, |target| {
1164 {
1166 let substitution: &mut SubstitutionArguments = &mut type_arguments;
1167 if !closed_over_variables.0.is_empty() {
1168 let closure_id = types.new_closure_id();
1169 substitution.closures.push(closure_id);
1170
1171 crate::utilities::notify!("Setting closure variables");
1172
1173 for (variable, value) in closed_over_variables.0.iter() {
1176 let value = substitute(*value, substitution, environment, types);
1177 environment
1178 .info
1179 .closure_current_values
1180 .insert((closure_id, RootReference::Variable(*variable)), value);
1181
1182 crate::utilities::notify!(
1183 "in {:?} set {:?} to {:?}",
1184 closure_id,
1185 variable,
1186 value
1187 );
1188 }
1189 }
1190
1191 let current_errors = diagnostics.errors.len();
1192 let current_warnings = diagnostics.warnings.len();
1193
1194 let result = apply_events(
1196 events,
1197 &ApplicationInput {
1198 this_value,
1199 call_site: input.call_site,
1200 max_inline: input.max_inline,
1201 },
1202 substitution,
1203 environment,
1204 target,
1205 types,
1206 diagnostics,
1207 );
1208
1209 for d in &mut diagnostics.errors[current_errors..] {
1211 if let FunctionCallingError::VariableUsedInTDZ {
1212 call_site: ref mut c,
1213 ..
1214 }
1215 | FunctionCallingError::SetPropertyConstraint {
1216 call_site: ref mut c,
1217 ..
1218 } = d
1219 {
1220 *c = input.call_site;
1221 }
1222 }
1223 for d in &mut diagnostics.warnings[current_warnings..] {
1224 if let TypeCheckWarning::ConditionalExceptionInvoked {
1225 call_site: ref mut c,
1226 ..
1227 } = d
1228 {
1229 *c = input.call_site;
1230 }
1231 }
1232
1233 result
1234 }
1235 })
1236 } else {
1237 if let Some(_parent_arguments) = parent_arguments {
1238 crate::utilities::notify!("TODO");
1239 }
1240 if let Some(ref call_site_type_arguments) = call_site_type_arguments {
1241 for (k, (v, _)) in call_site_type_arguments.iter() {
1242 type_arguments.arguments.insert(*k, *v);
1243 }
1244 }
1245
1246 let returned = substitute(self.return_type, &type_arguments, environment, types);
1256 Some(ApplicationResult::Return { returned, position: input.call_site })
1257 };
1258
1259 if !diagnostics.errors.is_empty() {
1260 crate::utilities::notify!("Got {} application errors", errors.errors.len());
1261 return Err(BadCallOutput {
1262 returned_type: types.new_error_type(self.return_type),
1264 });
1265 }
1266
1267 let result = if let CalledWithNew::New { .. } = input.called_with_new {
1269 let returned = match self.behavior {
1271 FunctionBehavior::ArrowFunction { .. } | FunctionBehavior::Method { .. } => {
1272 TypeId::ERROR_TYPE
1273 }
1274 FunctionBehavior::Constructor { prototype: _, this_object_type, name: _ } => {
1275 *type_arguments.arguments.get(&this_object_type).expect("no this argument?")
1276 }
1277 FunctionBehavior::Function { is_async: _, is_generator: _, this_id, .. } => {
1278 if let Type::Constructor(Constructor::ConditionalResult {
1279 truthy_result, ..
1280 }) = types.get_type_by_id(this_id)
1281 {
1282 *type_arguments.arguments.get(truthy_result).expect("no this argument?")
1283 } else {
1284 unreachable!()
1285 }
1286 }
1287 };
1288 Some(ApplicationResult::Return { returned, position: input.call_site })
1290 } else {
1291 result
1292 };
1293
1294 Ok(CallingOutput {
1295 result,
1296 called: Some(self.id),
1297 special: None,
1298 result_was_const_computation: false,
1299 })
1300 }
1301
1302 #[allow(clippy::too_many_arguments)]
1304 fn set_this_for_behavior<B: CallCheckingBehavior>(
1305 &self,
1306 called_with_new: CalledWithNew,
1307 this_value: ThisValue,
1308 type_arguments: &mut crate::Map<TypeId, TypeId>,
1309 environment: &mut Environment,
1310 types: &mut TypeStore,
1311 call_site: SpanWithSource,
1312 (behavior, diagnostics): (&mut B, &mut CallingDiagnostics),
1313 ) {
1314 match self.behavior {
1315 FunctionBehavior::ArrowFunction { .. } => {}
1316 FunctionBehavior::Method { free_this_id, .. } => {
1317 let value_of_this =
1319 if let CalledWithNew::GetterOrSetter { this_type } = called_with_new {
1320 this_type
1321 } else if let Some(value) = this_value.get_passed() {
1322 value
1323 } else {
1324 crate::utilities::notify!(
1325 "method has no 'this' passed :?. Passing `undefined` here"
1326 );
1327 TypeId::UNDEFINED_TYPE
1328 };
1329
1330 let base_type = get_constraint(free_this_id, types).unwrap_or(free_this_id);
1331
1332 let mut state = State {
1333 already_checked: Default::default(),
1334 contributions: None,
1335 mode: SubTypingMode::default(),
1336 object_constraints: None,
1337 others: Default::default(),
1338 };
1339
1340 let type_is_subtype =
1341 type_is_subtype(base_type, value_of_this, &mut state, environment, types);
1342
1343 if let SubTypeResult::IsNotSubType(_reason) = type_is_subtype {
1344 diagnostics.errors.push(FunctionCallingError::MismatchedThis {
1345 expected: TypeStringRepresentation::from_type_id(
1346 free_this_id,
1347 environment,
1348 types,
1349 behavior.debug_types(),
1350 ),
1351 found: TypeStringRepresentation::from_type_id(
1352 value_of_this,
1353 environment,
1354 types,
1355 behavior.debug_types(),
1356 ),
1357 call_site,
1358 });
1359 }
1360
1361 crate::utilities::notify!(
1362 "free this id {:?} & value of this {:?}",
1363 free_this_id,
1364 value_of_this
1365 );
1366
1367 type_arguments.insert(free_this_id, value_of_this);
1368 }
1369 FunctionBehavior::Function {
1370 is_async: _,
1371 is_generator: _,
1372 this_id,
1373 prototype,
1374 name: _,
1375 } => {
1376 match called_with_new {
1377 CalledWithNew::New { on: _ } => {
1378 let (this_id, constraint) =
1381 if let Type::Constructor(Constructor::ConditionalResult {
1382 truthy_result: this_id,
1383 otherwise_result: constraint,
1384 ..
1385 }) = types.get_type_by_id(this_id)
1386 {
1387 (*this_id, *constraint)
1388 } else {
1389 unreachable!()
1390 };
1391
1392 {
1416 let this_constraint = get_constraint(constraint, types);
1417
1418 if let Some(this_constraint) = this_constraint {
1420 let mut state = State {
1421 already_checked: Default::default(),
1422 mode: SubTypingMode::default(),
1423 contributions: None,
1424 object_constraints: None,
1425 others: SubTypingOptions::default(),
1426 };
1427
1428 let result = type_is_subtype(
1429 this_constraint,
1430 prototype,
1431 &mut state,
1432 environment,
1433 types,
1434 );
1435
1436 if let SubTypeResult::IsNotSubType(_reason) = result {
1439 diagnostics.errors.push(FunctionCallingError::MismatchedThis {
1440 expected: TypeStringRepresentation::from_type_id(
1441 this_constraint,
1442 environment,
1443 types,
1444 behavior.debug_types(),
1445 ),
1446 found: TypeStringRepresentation::from_type_id(
1447 prototype,
1448 environment,
1449 types,
1450 behavior.debug_types(),
1451 ),
1452 call_site,
1453 });
1454 }
1455 }
1456 }
1457
1458 {
1460 let is_under_dyn = true;
1462 let value_of_this = environment.info.new_object(
1463 Some(prototype),
1464 types,
1465 call_site,
1466 is_under_dyn,
1467 );
1468
1469 type_arguments.insert(this_id, value_of_this);
1470
1471 }
1474 }
1475 CalledWithNew::GetterOrSetter { this_type }
1476 | CalledWithNew::Super { this_type } => {
1477 crate::utilities::notify!("Super / getter / setter on regular function?");
1478
1479 type_arguments.insert(this_id, this_type);
1480 }
1481 CalledWithNew::None => {
1482 let value_of_this = this_value.get(environment, types, call_site);
1484
1485 type_arguments.insert(this_id, value_of_this);
1486 }
1487 }
1488 }
1489 FunctionBehavior::Constructor { prototype, this_object_type, name: _ } => {
1490 crate::utilities::notify!("Here {:?}", called_with_new);
1491 match called_with_new {
1492 CalledWithNew::GetterOrSetter { .. } | CalledWithNew::None => {
1493 diagnostics
1494 .errors
1495 .push(FunctionCallingError::NeedsToBeCalledWithNewKeyword(call_site));
1496 }
1497 CalledWithNew::New { on: _ } => {
1498 let is_under_dyn = true;
1500 crate::utilities::notify!(
1501 "Creating new class object with prototype={:?}",
1502 prototype
1503 );
1504 let value_of_this = environment.info.new_object(
1505 Some(prototype),
1506 types,
1507 call_site,
1508 is_under_dyn,
1509 );
1510
1511 crate::utilities::notify!("Here with new");
1512 type_arguments.insert(this_object_type, value_of_this);
1513 }
1514 CalledWithNew::Super { this_type } => {
1515 crate::utilities::notify!(
1516 "Setting this_object {:?} to {:?} in super call",
1517 this_object_type,
1518 this_type
1519 );
1520 type_arguments.insert(this_object_type, this_type);
1521 }
1522 }
1523 }
1524 }
1525
1526 {
1527 let new_target_value = match called_with_new {
1528 CalledWithNew::New { on } => on,
1529 CalledWithNew::Super { .. } => {
1530 crate::utilities::notify!("Get this type for super new.target");
1531 TypeId::UNIMPLEMENTED_ERROR_TYPE
1532 }
1542 CalledWithNew::GetterOrSetter { .. } | CalledWithNew::None => {
1544 TypeId::UNDEFINED_TYPE
1545 }
1546 };
1547
1548 type_arguments.insert(TypeId::NEW_TARGET_ARG, new_target_value);
1549 }
1550 }
1551
1552 #[allow(clippy::too_many_arguments)]
1553 fn assign_arguments_to_parameters<B: CallCheckingBehavior>(
1554 &self,
1555 arguments: &[SynthesisedArgument],
1556 type_arguments: &mut SubstitutionArguments<'static>,
1557 (call_site_type_arguments, parent_arguments): (
1558 Option<CallSiteTypeArguments>,
1559 Option<&GenericArguments>,
1560 ),
1561 environment: &mut Environment,
1562 types: &mut TypeStore,
1563 call_site: SpanWithSource,
1564 evaluating_effects: bool,
1565 (behavior, diagnostics): (&mut B, &mut CallingDiagnostics),
1566 ) {
1567 for (parameter_idx, parameter) in self.parameters.parameters.iter().enumerate() {
1568 let argument = arguments.get(parameter_idx);
1572
1573 if let Some(argument) = argument {
1574 if argument.spread {
1575 crate::utilities::notify!("TODO spread arguments");
1576 }
1577
1578 if B::CHECK_PARAMETERS {
1579 let result = check_parameter_type(
1580 parameter.ty,
1581 call_site_type_arguments.as_ref(),
1582 parent_arguments,
1583 argument,
1584 type_arguments,
1585 environment,
1586 types,
1587 );
1588
1589 if let SubTypeResult::IsNotSubType(_reasons) = result {
1590 let type_arguments = Some(GenericChainLink::FunctionRoot {
1591 parent_arguments,
1592 call_site_type_arguments: call_site_type_arguments.as_ref(),
1593 type_arguments: &type_arguments.arguments,
1594 });
1595
1596 crate::utilities::notify!("Type arguments are {:?}", type_arguments);
1597
1598 diagnostics.errors.push(FunctionCallingError::InvalidArgumentType {
1599 parameter_type: TypeStringRepresentation::from_type_id_with_generics(
1600 parameter.ty,
1601 type_arguments,
1602 environment,
1603 types,
1604 behavior.debug_types(),
1605 ),
1606 argument_type: TypeStringRepresentation::from_type_id_with_generics(
1607 argument.value,
1608 type_arguments,
1609 environment,
1610 types,
1611 behavior.debug_types(),
1612 ),
1613 parameter_position: parameter.position,
1614 argument_position: argument.position,
1615 restriction: None,
1616 });
1617 }
1618 } else {
1619 type_arguments.arguments.insert(parameter.ty, argument.value);
1621 }
1622 } else if parameter.is_optional {
1623 type_arguments.arguments.insert(parameter.ty, TypeId::UNDEFINED_TYPE);
1624 } else {
1625 diagnostics.errors.push(FunctionCallingError::MissingArgument {
1626 parameter_position: parameter.position,
1627 call_site,
1628 });
1629 }
1630 }
1631
1632 if self.parameters.parameters.len() < arguments.len() {
1634 if let Some(ref rest_parameter) = self.parameters.rest_parameter {
1635 let mut basis = evaluating_effects.then(|| {
1637 ObjectBuilder::new(
1638 Some(TypeId::ARRAY_TYPE),
1639 types,
1640 rest_parameter.position,
1641 &mut environment.info,
1642 )
1643 });
1644
1645 let mut count = 0;
1646
1647 for argument in arguments.iter().skip(self.parameters.parameters.len()) {
1648 if B::CHECK_PARAMETERS {
1649 let result = check_parameter_type(
1650 rest_parameter.item_type,
1651 call_site_type_arguments.as_ref(),
1652 parent_arguments,
1653 argument,
1654 type_arguments,
1655 environment,
1656 types,
1657 );
1658
1659 if let SubTypeResult::IsNotSubType(_reasons) = result {
1661 let type_arguments = Some(GenericChainLink::FunctionRoot {
1662 parent_arguments,
1663 call_site_type_arguments: call_site_type_arguments.as_ref(),
1664 type_arguments: &type_arguments.arguments,
1665 });
1666
1667 diagnostics.errors.push(FunctionCallingError::InvalidArgumentType {
1668 parameter_type:
1669 TypeStringRepresentation::from_type_id_with_generics(
1670 rest_parameter.ty,
1671 type_arguments,
1672 environment,
1673 types,
1674 behavior.debug_types(),
1675 ),
1676 argument_type: TypeStringRepresentation::from_type_id_with_generics(
1677 argument.value,
1678 type_arguments,
1679 environment,
1680 types,
1681 behavior.debug_types(),
1682 ),
1683 parameter_position: rest_parameter.position,
1684 argument_position: argument.position,
1685 restriction: None,
1686 });
1687 }
1688 }
1689
1690 if let Some(basis) = basis.as_mut() {
1692 let key = PropertyKey::from_usize(count);
1693 basis.append(
1694 crate::types::properties::Publicity::Public,
1695 key,
1696 crate::types::properties::PropertyValue::Value(argument.value),
1697 argument.position,
1698 &mut environment.info,
1699 );
1700 }
1701
1702 count += 1;
1703 }
1704
1705 if let Some(mut basis) = basis {
1707 let length = types.new_constant_type(crate::Constant::Number(
1708 (count as f64).try_into().unwrap(),
1709 ));
1710
1711 basis.append(
1712 crate::types::properties::Publicity::Public,
1713 PropertyKey::String("length".into()),
1714 crate::types::properties::PropertyValue::Value(length),
1715 rest_parameter.position,
1716 &mut environment.info,
1717 );
1718
1719 let rest_parameter_array_type = basis.build_object();
1720 type_arguments.arguments.insert(rest_parameter.ty, rest_parameter_array_type);
1721 }
1722 } else {
1723 let mut left_over = arguments.iter().skip(self.parameters.parameters.len());
1725 let first = left_over.next().unwrap();
1726 let mut count = 1;
1727 let mut end = None;
1728 while let arg @ Some(_) = left_over.next() {
1729 count += 1;
1730 end = arg;
1731 }
1732 let position = if let Some(end) = end {
1734 first
1735 .position
1736 .without_source()
1737 .union(end.position.without_source())
1738 .with_source(end.position.source)
1739 } else {
1740 first.position
1741 };
1742
1743 if B::CHECK_PARAMETERS {
1744 diagnostics
1745 .errors
1746 .push(FunctionCallingError::ExcessArguments { count, position });
1747 }
1748 }
1749 }
1750
1751 if let Some(_call_site_type_arguments) = call_site_type_arguments {
1753 crate::utilities::notify!("TODO type_arguments.covariants");
1754 }
1760 }
1761}
1762
1763fn check_parameter_type(
1764 parameter_type: TypeId,
1765 call_site_type_arguments: Option<&CallSiteTypeArguments>,
1766 parent: Option<&GenericArguments>,
1767 argument: &SynthesisedArgument,
1768 type_arguments: &mut SubstitutionArguments,
1769 environment: &mut Environment,
1770 types: &mut TypeStore,
1771) -> SubTypeResult {
1772 let contributions = Contributions {
1776 parent,
1777 call_site_type_arguments,
1778 staging_covariant: Default::default(),
1779 staging_contravariant: Default::default(),
1780 };
1781
1782 let mut state = State {
1784 already_checked: Vec::new(),
1785 mode: Default::default(),
1786 contributions: Some(contributions),
1787 others: SubTypingOptions { allow_errors: true },
1788 object_constraints: None,
1789 };
1790
1791 let result = type_is_subtype_with_generics(
1792 (parameter_type, GenericChain::None),
1793 (argument.value, GenericChain::None),
1794 &mut state,
1795 environment,
1796 types,
1797 );
1798
1799 if result.is_subtype() {
1800 let Contributions { staging_covariant, staging_contravariant, .. } =
1802 state.contributions.unwrap();
1803
1804 for (on, (value, _)) in staging_covariant.iter() {
1805 crate::utilities::notify!("TODO pick highest covariant?");
1806 if let Some(value) = type_arguments.arguments.get_mut(on) {
1807 *value = types.new_or_type(*value, *value);
1808 } else {
1809 type_arguments.arguments.insert(*on, *value);
1810 }
1811 }
1812
1813 for (idx, (on, (value, depth))) in staging_contravariant.iter().enumerate() {
1814 let is_weaker =
1818 staging_contravariant.iter().enumerate().any(|(idx2, (on2, (_, other_depth)))| {
1819 (on == on2) && idx != idx2 && depth < other_depth
1820 });
1821
1822 if is_weaker {
1823 crate::utilities::notify!("Here skipping as weaker");
1824 continue;
1825 }
1826
1827 let value = value.clone().into_type(types);
1829 if let Some(existing) = type_arguments.arguments.get_mut(on) {
1830 crate::utilities::notify!("Here");
1831 *existing = types.new_or_type(*existing, value);
1832 } else {
1833 type_arguments.arguments.insert(*on, value);
1834 }
1835 }
1836
1837 let no_events = false;
1839 if no_events {
1840 mark_possible_mutation(argument, parameter_type, types, environment);
1841 }
1842 }
1843
1844 result
1847}
1848
1849#[allow(clippy::type_complexity)]
1850fn synthesise_argument_expressions_wrt_parameters<T: ReadFromFS, A: crate::ASTImplementation>(
1851 callable: &Logical<FunctionLike>,
1852 arguments: &[UnsynthesisedArgument<A>],
1853 (call_site_type_arguments, parent_arguments): (
1854 Option<Vec<(TypeId, SpanWithSource)>>,
1855 Option<&GenericArguments>,
1856 ),
1857 environment: &mut Environment,
1858 checking_data: &mut crate::CheckingData<T, A>,
1859) -> (Vec<SynthesisedArgument>, Option<TypeRestrictions>) {
1860 fn synthesise_call_site_type_argument_hints(
1861 type_parameters: &GenericTypeParameters,
1862 call_site_type_arguments: Vec<(TypeId, SpanWithSource)>,
1863 types: &crate::types::TypeStore,
1864 environment: &mut Environment,
1865 ) -> TypeRestrictions {
1866 crate::utilities::notify!("call_site_type_arguments {:?}", call_site_type_arguments);
1867
1868 type_parameters
1869 .0
1870 .iter()
1871 .zip(call_site_type_arguments)
1872 .map(|(param, (ty, position))| {
1873 if let Type::RootPolyType(
1875 PolyNature::FunctionGeneric { extends, .. }
1876 | PolyNature::StructureGeneric { extends, .. },
1877 ) = types.get_type_by_id(param.type_id)
1878 {
1879 let mut state = State {
1880 already_checked: Default::default(),
1881 mode: SubTypingMode::default(),
1882 contributions: None,
1883 others: Default::default(),
1884 object_constraints: None,
1885 };
1886 let type_is_subtype =
1887 type_is_subtype(*extends, ty, &mut state, environment, types);
1888
1889 if let SubTypeResult::IsNotSubType(_) = type_is_subtype {
1890 todo!("generic argument does not match restriction")
1891 }
1892 } else {
1893 todo!();
1894 };
1896
1897 (param.type_id, (ty, position))
1898 })
1899 .collect()
1900 }
1901
1902 match callable {
1903 Logical::Pure(function) => {
1904 let function = checking_data.types.get_function_from_id(function.function);
1905
1906 let type_arguments_restrictions =
1907 match (&function.type_parameters, call_site_type_arguments) {
1908 (None, Some(call_site_type_arguments)) => {
1909 let first_excess_type_parameter = &call_site_type_arguments[0];
1910 checking_data.diagnostics_container.add_error(
1911 TypeCheckError::FunctionCallingError(
1912 FunctionCallingError::ExcessTypeArguments {
1913 expected_count: 0,
1914 count: call_site_type_arguments.len(),
1915 position: first_excess_type_parameter.1,
1916 },
1917 ),
1918 );
1919
1920 None
1921 }
1922 (Some(ref function_type_parameters), Some(call_site_type_arguments)) => {
1923 let expected_parameters_length = function_type_parameters.0.len();
1924 let provided_parameters_length = call_site_type_arguments.len();
1925 if provided_parameters_length > expected_parameters_length {
1926 let first_excess_type_parameter =
1927 &call_site_type_arguments[expected_parameters_length];
1928 let last_excess_type_parameter = call_site_type_arguments
1929 .last()
1930 .unwrap_or(first_excess_type_parameter);
1931
1932 let error_position = first_excess_type_parameter
1933 .1
1934 .without_source()
1935 .union(last_excess_type_parameter.1.without_source())
1936 .with_source(first_excess_type_parameter.1.source);
1937
1938 checking_data.diagnostics_container.add_error(
1939 TypeCheckError::FunctionCallingError(
1940 FunctionCallingError::ExcessTypeArguments {
1941 expected_count: expected_parameters_length,
1942 count: provided_parameters_length,
1943 position: error_position,
1944 },
1945 ),
1946 );
1947 }
1948 Some(synthesise_call_site_type_argument_hints(
1949 function_type_parameters,
1950 call_site_type_arguments,
1951 &checking_data.types,
1952 environment,
1953 ))
1954 }
1955
1956 _ => None,
1957 };
1958
1959 let parameters = function.parameters.clone();
1960
1961 let type_arguments = if type_arguments_restrictions.is_some()
1962 || parent_arguments.is_some()
1963 {
1964 let mut arguments = type_arguments_restrictions.clone().unwrap_or_default();
1965 match parent_arguments {
1966 Some(GenericArguments::LookUp { on }) => {
1967 let prototype = environment
1969 .get_chain_of_info()
1970 .find_map(|env| env.prototypes.get(on))
1971 .unwrap();
1972
1973 crate::utilities::notify!(
1974 "Here calculating lookup argument prototype={:?} {:?}",
1975 prototype,
1976 on
1977 );
1978 let map =
1979 checking_data.types.lookup_generic_map.get(prototype).unwrap().clone();
1980
1981 for (under, lookup) in map.iter() {
1982 let entries =
1983 lookup.calculate_lookup(environment, &checking_data.types, *on);
1984 let mut iter = entries.into_iter();
1985 let mut ty = iter.next().unwrap_or(TypeId::NEVER_TYPE);
1986 for other in iter {
1987 ty = checking_data.types.new_or_type(ty, other);
1989 }
1990
1991 arguments.insert(*under, (ty, BaseSpan::NULL));
1992 }
1993 }
1994 Some(GenericArguments::ExplicitRestrictions(ers)) => {
1995 arguments.extend(ers.iter().map(|(k, v)| (*k, *v)));
1996 }
1997 Some(GenericArguments::Closure(..)) | None => {}
1998 }
1999
2000 Some(arguments)
2001 } else {
2002 None
2003 };
2004
2005 let arguments = arguments
2006 .iter()
2007 .enumerate()
2008 .map(|(idx, argument)| {
2009 let expected_type = parameters.get_parameter_type_at_index(idx).map_or(
2010 TypeId::ANY_TYPE,
2011 |(parameter_type, _)| {
2012 let ty = checking_data.types.get_type_by_id(parameter_type);
2015 let parameter_type = if let Type::RootPolyType(
2016 PolyNature::Parameter { fixed_to },
2017 ) = ty
2018 {
2019 *fixed_to
2020 } else {
2021 crate::utilities::notify!(
2022 "Parameter is not `PolyNature::Parameter`? {:?}",
2023 ty
2024 );
2025 parameter_type
2026 };
2027
2028 if let Some(arguments) = type_arguments.clone() {
2029 if let Some((ty, _)) = arguments.get(¶meter_type) {
2030 *ty
2031 } else {
2032 crate::utilities::notify!("Here");
2034 checking_data.types.register_type(
2035 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
2036 on: parameter_type,
2037 arguments: GenericArguments::ExplicitRestrictions(
2038 arguments,
2039 ),
2040 }),
2041 )
2042 }
2043 } else {
2044 parameter_type
2045 }
2046 },
2047 );
2048
2049 let value = A::synthesise_expression(
2063 argument.expression,
2064 expected_type,
2065 environment,
2066 checking_data,
2067 );
2068
2069 let position = A::expression_position(argument.expression)
2070 .with_source(environment.get_source());
2071
2072 SynthesisedArgument { spread: argument.spread, position, value }
2073 })
2074 .collect();
2075
2076 (arguments, type_arguments_restrictions)
2077 }
2078 Logical::Implies { on, antecedent } => synthesise_argument_expressions_wrt_parameters(
2079 on,
2080 arguments,
2081 (call_site_type_arguments, Some(antecedent)),
2083 environment,
2084 checking_data,
2085 ),
2086 Logical::Or { .. } => (
2087 arguments
2088 .iter()
2089 .map(|argument| SynthesisedArgument {
2090 spread: argument.spread,
2091 position: A::expression_position(argument.expression)
2092 .with_source(environment.get_source()),
2093 value: A::synthesise_expression(
2094 argument.expression,
2095 TypeId::ANY_TYPE,
2097 environment,
2098 checking_data,
2099 ),
2100 })
2101 .collect(),
2102 None,
2103 ),
2104 Logical::BasedOnKey { .. } => todo!(),
2105 }
2106}