diff --git a/.github/workflows/performance-and-size.yml b/.github/workflows/performance-and-size.yml index 179cf6b3..792754b6 100644 --- a/.github/workflows/performance-and-size.yml +++ b/.github/workflows/performance-and-size.yml @@ -42,18 +42,16 @@ jobs: # Generate a file which contains everything that Ezno currently implements cargo run -p ezno-parser --example code_blocks_to_script ./checker/specification/specification.md demo.ts - echo "### Checking">> $GITHUB_STEP_SUMMARY - echo "\`\`\`ts">> $GITHUB_STEP_SUMMARY + echo "
Input\`\`\`ts" >> $GITHUB_STEP_SUMMARY cat demo.ts >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - - echo "### Output">> $GITHUB_STEP_SUMMARY - echo "\`\`\`shell">> $GITHUB_STEP_SUMMARY - ./target/release/ezno check demo.ts >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`
" >> $GITHUB_STEP_SUMMARY + + echo "
Diagnostics\`\`\`shell" >> $GITHUB_STEP_SUMMARY + ./target/release/ezno check demo.ts &>> $GITHUB_STEP_SUMMARY + echo "\`\`\`
" >> $GITHUB_STEP_SUMMARY - echo "### Performance">> $GITHUB_STEP_SUMMARY - echo "\`\`\`shell">> $GITHUB_STEP_SUMMARY + echo "### Checking" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`shell" >> $GITHUB_STEP_SUMMARY hyperfine './target/release/ezno check demo.ts' >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY diff --git a/checker/examples/check.rs b/checker/examples/check.rs index 99cde5ee..8d7bd9af 100644 --- a/checker/examples/check.rs +++ b/checker/examples/check.rs @@ -23,6 +23,7 @@ fn main() { } }, None, + (), ); let args: Vec<_> = env::args().collect(); diff --git a/checker/specification/specification.md b/checker/specification/specification.md index 12221e07..4030c084 100644 --- a/checker/specification/specification.md +++ b/checker/specification/specification.md @@ -38,10 +38,10 @@ const b: string = a ```ts let a = 2 a = "not a number" -let b: number = a +let b: boolean = a ``` -- Type "not a number" is not assignable to type number +- Type "not a number" is not assignable to type boolean #### Variable references does not exist @@ -222,6 +222,20 @@ const x: (a: string) => number = a => a.to; - No property 'to' on string +#### Assignment to parameter + +```ts +function alterParameter(a: number, b: { prop: string }) { + a = 2; + a = "hi"; + b.prop = 6; +} +``` + +> Assigning straight to `a` might be disallowed by an option in the future. Right now it is allowed by JavaScript and so is allowed + +- Type \"hi\" is not assignable to type number + ### Function calling #### Argument type against parameter @@ -420,7 +434,8 @@ value.getValue() satisfies 6 let a: number = 0 function func() { a = 4; - // Important that subsequent reads use the new value, not the same free variable + // Important that subsequent reads use the + // new value, not the same free variable a satisfies 4; } @@ -529,6 +544,20 @@ setAtoString(myObject); - Assignment mismatch +#### Property assignment from conditional + +```ts +function getObject(condition: boolean) { + const mainObject = { a: 2 }; + const object = condition ? mainObject : { b: 3 }; + object.c = 4; + mainObject.c satisfies string; + return mainObject +} +``` + +- Expected string, found 4 + #### Mutating an object by a function > This is where the object loses its constant-ness @@ -979,6 +1008,20 @@ while (a < i) { > Important that type is widened to 'number' (think it is an open poly in this case) +#### Limit to iterations + +```ts +let a: number = 0; +while (a++ < 1_000_000) {} + +a satisfies string; +``` + +> The important part is that it doesn't run the loop. Eventually this might be run in a way that is not calling the assign to variable +> function that evaluates `a = a + 1` a million times. There also should be per project, per module, per loop configuration + +- Expected string, found number + #### While loop unrolling as an effect ```ts @@ -1013,6 +1056,29 @@ while (i++ < 10) { - Expected 2, found 8 +#### Break with label + +```ts +let a: number = 0; +let result; + +top: while (a++ < 10) { + let b: number = 0; + while (b++ < 10) { + if (a === 3 && b === 2) { + result = a * b; + break top + } + } +} + +a satisfies string; +result satisfies boolean; +``` + +- Expected string, found 3 +- Expected boolean, found 6 + #### Continue in a while loop > With the continue the update to `a` only happens on even runs (5 times) @@ -1089,6 +1155,35 @@ interface X { - Expected 4, found 5 - Type { a: 3 } is not assignable to type X +#### RegExp + +> RegExp = Regular expression +> In the future, their definition could be considered and evaluated at runtime + +```ts +/hi/ satisfies string; +``` + +- Expected string, found /hi/ + +#### Null and undefined + +```ts +undefined satisfies null; +null satisfies undefined; +``` + +- Expected null, found undefined +- Expected undefined, found null + +#### void operator + +```ts +(void 2) satisfies string; +``` + +- Expected string, found undefined + #### (untagged) Template literal ```ts @@ -1437,6 +1532,34 @@ const y: (a: number | string) => string = (p: number) => "hi" > I think reasons contains more information +#### Function return type subtyping + +```ts +const x: (a: number) => number = p => 4 +const y: (a: number) => number = p => "a number" +``` + +- Type (p: number) => "a number" is not assignable to type (a: number) => number + +#### `void` return type + +> This works similarly to undefined except that it accepts any function return type + +```ts +function runWithCallback(cb: () => void): void { + cb() satisfies string; + + return 5; +} + +runWithCallback(() => 3) +``` + +> Here argument is fine. In the body the return type is `any` (inferred constraint, but doesn't matter) + +- Expected string, found any +- Cannot return 5 because the function is expected to return void + #### Indexing into (fixed) type ```ts diff --git a/checker/specification/staging.md b/checker/specification/staging.md index 1e469a36..4bea3856 100644 --- a/checker/specification/staging.md +++ b/checker/specification/staging.md @@ -1,96 +1,5 @@ Currently implementing: -### Iterations - -#### Limit to iterations - -```ts -let a: number = 0; -while (a++ < 1_000_000) {} - -a satisfies string; -``` - -> The important part is that it doesn't run the loop. Eventually this might be run in a way that is not calling the assign to variable -> function that evaluates `a = a + 1` a million times. There also should be per project, per module, per loop configuration - -- Expected string, found number - -### Functions - -#### Assignment to parameter - -```ts -function alterParameter(a: number, b: { prop: string }) { - a = 2; - a = "hi"; - b.prop = 6; -} -``` - -> Assigning straight to `a` might be disallowed by an option in the future. Right now it is allowed by JavaScript and so is allowed - -- Type \"hi\" is not assignable to type number - -### Statements - -#### RegExp - -> RegExp = Regular expression -> In the future, their definition could be considered and evaluated at runtime - -```ts -/hi/ satisfies string; -``` - -- Expected string, found /hi/ - -#### Null and undefined - -```ts -undefined satisfies null; -null satisfies undefined; -``` - -- Expected null, found undefined -- Expected undefined, found null - -#### void operator - -```ts -(void 2) satisfies string; -``` - -- Expected string, found undefined - -#### Function return type subtyping - -```ts -const x: (a: number) => number = p => 4 -const y: (a: number) => number = p => "a number" -``` - -- Type (p: number) => "a number" is not assignable to type (a: number) => number - -#### void return type - -> This works similarly to undefined except that it accepts any function return type - -```ts -function runWithCallback(cb: () => void): void { - cb() satisfies string; - - return 5; -} - -runWithCallback(() => 3) -``` - -> Here argument is fine. In the body the return type is `any` (inferred constraint, but doesn't matter) - -- Expected string, found any -- Cannot return 5 because the function is expected to return void - ### Not sure #### Set property on dependent observed @@ -110,7 +19,7 @@ function add_property(obj: { prop: number }) { #### Constant call and operation with a parameter -> An example of the generic constructor type (namely call and operation) +> An example of the generic constructor type (namely call and operation) ```ts function floorPlusB(a: number, b: number) { @@ -121,3 +30,15 @@ floorPlusB(100.22, 5) satisfies 8 ``` - Expected 8, found 105 + +#### Calling new on a function + +```ts +function MyClass(value) { + this.value = value +} + +new MyClass("hi").value satisfies "hello" +``` + +- Expected "hello", found "hi" diff --git a/checker/specification/test.rs b/checker/specification/test.rs index cab98403..623ab3bf 100644 --- a/checker/specification/test.rs +++ b/checker/specification/test.rs @@ -68,6 +68,7 @@ fn check_errors( } }, type_check_options, + (), ); // }); diff --git a/checker/specification/to_implement.md b/checker/specification/to_implement.md index 6d08ae37..d02aa6ae 100644 --- a/checker/specification/to_implement.md +++ b/checker/specification/to_implement.md @@ -189,18 +189,6 @@ join(["a", "b", "c"]) satisfies "cba" ### This -#### Calling new on a function - -```ts -function MyClass(value) { - this.value = value -} - -new MyClass("hi").value satisfies "hello" -``` - -- Expected "hello", found "hi" - #### Bind function ```ts diff --git a/checker/src/behavior/functions.rs b/checker/src/behavior/functions.rs index 22809318..36830ca0 100644 --- a/checker/src/behavior/functions.rs +++ b/checker/src/behavior/functions.rs @@ -587,15 +587,14 @@ where *on, None::<&crate::types::poly_types::FunctionTypeArguments>, ); - match get_value_of_variable { - Some(value) => value, - None => { - let name = base_environment.get_variable_name(*on); - panic!("Could not find value for closed over reference '{name}' ({on:?}) in {:?}", function.get_name()); - } + if let Some(value) = get_value_of_variable { + value + } else { + let name = base_environment.get_variable_name(*on); + panic!("Could not find value for closed over reference '{name}' ({on:?}) in {:?}", function.get_name()); } } - // TODO not sure + // TODO unsure RootReference::This => TypeId::ANY_INFERRED_FREE_THIS, }; @@ -643,7 +642,7 @@ where // Keep if body does not contain id let contains = base_environment .parents_iter() - .any(|c| get_on_ctx!(&c.variable_names).contains_key(&id)); + .any(|c| get_on_ctx!(&c.variable_names).contains_key(id)); crate::utils::notify!("v-id {:?} con {:?}", id, contains); contains diff --git a/checker/src/behavior/iteration.rs b/checker/src/behavior/iteration.rs index 3ae15d87..abc4263a 100644 --- a/checker/src/behavior/iteration.rs +++ b/checker/src/behavior/iteration.rs @@ -4,8 +4,7 @@ use crate::{ behavior::operations::CanonicalEqualityAndInequality, context::{calling::Target, environment::Label, get_value_of_variable, CallCheckingBehavior}, events::{ - application::ErrorsAndInfo, apply_event, Event, EventResult, InitialVariables, - RootReference, + application::ErrorsAndInfo, apply_event, Event, FinalEvent, InitialVariables, RootReference, }, types::{ poly_types::{generic_type_arguments::TypeArgumentStore, FunctionTypeArguments}, @@ -57,14 +56,18 @@ pub fn synthesise_iteration( // TODO not always needed let break_event = Event::Conditionally { condition, - events_if_truthy: Default::default(), - else_events: Box::new([Event::Break { position: None, carry: 0 }]), + true_events: Default::default(), + else_events: Box::new([ + FinalEvent::Break { position: None, carry: 0 }.into() + ]), position: None, }; environment.facts.events.push(break_event); loop_body(environment, checking_data); + crate::utils::notify!("Loop does {:#?}", environment.facts.events); + condition }, ); @@ -85,18 +88,32 @@ pub fn synthesise_iteration( &loop_facts, ); - if let Some(_value) = run_iteration_block( + let mut errors_and_info = ErrorsAndInfo::default(); + + if let Some(early_return) = run_iteration_block( IterationKind::Condition { under: fixed_iterations.ok(), postfix_condition: false }, events, InitialVariablesInput::Compute, &mut FunctionTypeArguments::new(), environment, - &mut crate::context::calling::Target::new_default(), - // TODO shouldn't be needed - &mut Default::default(), + &mut crate::context::calling::Target::new_empty(), + &mut errors_and_info, &mut checking_data.types, ) { - todo!() + crate::utils::notify!("Loop returned {:?}", early_return); + environment.facts.events.push(Event::FinalEvent(early_return)); + } + + // TODO for other blocks + for warning in errors_and_info.warnings { + checking_data.diagnostics_container.add_info( + crate::diagnostics::Diagnostic::Position { + reason: warning.0, + // TODO temp + position: source_map::SpanWithSource::NULL_SPAN, + kind: crate::diagnostics::DiagnosticKind::Info, + }, + ); } } IterationBehavior::DoWhile(condition) => { @@ -119,8 +136,10 @@ pub fn synthesise_iteration( // TODO not always needed let break_event = Event::Conditionally { condition, - events_if_truthy: Default::default(), - else_events: Box::new([Event::Break { position: None, carry: 0 }]), + true_events: Default::default(), + else_events: Box::new([ + FinalEvent::Break { position: None, carry: 0 }.into() + ]), position: None, }; environment.facts.events.push(break_event); @@ -145,18 +164,18 @@ pub fn synthesise_iteration( &loop_facts, ); - if let Some(_value) = run_iteration_block( + if let Some(early_return) = run_iteration_block( IterationKind::Condition { under: fixed_iterations.ok(), postfix_condition: true }, events, InitialVariablesInput::Compute, &mut FunctionTypeArguments::new(), environment, - &mut crate::context::calling::Target::new_default(), + &mut crate::context::calling::Target::new_empty(), // TODO shouldn't be needed &mut Default::default(), &mut checking_data.types, ) { - todo!() + todo!("{early_return:?}") } } IterationBehavior::For { initialiser, condition, afterthought } => { @@ -210,11 +229,12 @@ pub fn synthesise_iteration( // TODO not always needed let break_event = Event::Conditionally { condition, - events_if_truthy: Default::default(), - else_events: Box::new([Event::Break { + true_events: Default::default(), + else_events: Box::new([FinalEvent::Break { position: None, carry: 0, - }]), + } + .into()]), position: None, }; environment.facts.events.push(break_event); @@ -274,18 +294,18 @@ pub fn synthesise_iteration( environment.facts.variable_current_value.insert(var, start); } - if let Some(_value) = run_iteration_block( + if let Some(early_return) = run_iteration_block( IterationKind::Condition { under: fixed_iterations.ok(), postfix_condition: false }, events, InitialVariablesInput::Compute, &mut FunctionTypeArguments::new(), environment, - &mut crate::context::calling::Target::new_default(), + &mut crate::context::calling::Target::new_empty(), // TODO shouldn't be needed &mut Default::default(), &mut checking_data.types, ) { - todo!() + todo!("{early_return:?}") } } IterationBehavior::ForIn { lhs: _, rhs } => { @@ -307,18 +327,18 @@ pub fn synthesise_iteration( let events = result.unwrap().0.events; - if let Some(_value) = run_iteration_block( + if let Some(early_return) = run_iteration_block( IterationKind::Properties(on), events, InitialVariablesInput::Compute, &mut FunctionTypeArguments::new(), environment, - &mut crate::context::calling::Target::new_default(), + &mut crate::context::calling::Target::new_empty(), // TODO shouldn't be needed &mut Default::default(), &mut checking_data.types, ) { - todo!() + todo!("{early_return:?}") } } IterationBehavior::ForOf { lhs: _, rhs: _ } => todo!(), @@ -352,7 +372,7 @@ pub(crate) fn run_iteration_block( target: &mut Target, errors: &mut ErrorsAndInfo, types: &mut TypeStore, -) -> Option { +) -> Option { /// TODO via config const MAX_ITERATIONS: usize = 1000; @@ -368,6 +388,7 @@ pub(crate) fn run_iteration_block( // ); // crate::utils::notify!("events in iteration = {}", buf); + // TODO if depends on something maybe limit to 10? let non_exorbitant_amount_of_iterations = under .and_then(|under| under.calculate_iterations(types).ok()) .and_then(|iterations| (iterations < MAX_ITERATIONS).then_some(iterations)); @@ -390,8 +411,6 @@ pub(crate) fn run_iteration_block( .variable_current_value .insert(*variable_id, *initial_value); } - } else { - crate::utils::notify!("Here ??"); } evaluate_iterations( @@ -503,7 +522,7 @@ fn evaluate_iterations( target: &mut Target, errors: &mut ErrorsAndInfo, types: &mut TypeStore, -) -> Option { +) -> Option { // TODO temp fix if !errors.errors.is_empty() { return None; @@ -511,17 +530,17 @@ fn evaluate_iterations( 'main_iterations: for _ in 0..iterations { 'inner_loop: for event in events { - let result = apply_event( - event.clone(), - crate::behavior::functions::ThisValue::UseParent, - arguments, - environment, - // TODO new nested target - target, - types, - // Shouldn't matter - errors, - ); + let result = target.new_loop_iteration(|target| { + apply_event( + event.clone(), + crate::behavior::functions::ThisValue::UseParent, + arguments, + environment, + target, + types, + errors, + ) + }); if !errors.errors.is_empty() { unreachable!("errors when calling loop") @@ -529,19 +548,19 @@ fn evaluate_iterations( if let Some(result) = result { match result { - EventResult::Continue { carry: 0 } => { + FinalEvent::Continue { carry: 0, position: _ } => { break 'inner_loop; } - EventResult::Break { carry: 0 } => { + FinalEvent::Break { carry: 0, position: _ } => { break 'main_iterations; } - EventResult::Continue { carry } => { - return Some(EventResult::Continue { carry: carry - 1 }) + FinalEvent::Continue { carry, position } => { + return Some(FinalEvent::Continue { carry: carry - 1, position }) } - EventResult::Break { carry } => { - return Some(EventResult::Break { carry: carry - 1 }) + FinalEvent::Break { carry, position } => { + return Some(FinalEvent::Break { carry: carry - 1, position }) } - e @ (EventResult::Return(..) | EventResult::Throw) => return Some(e), + e @ (FinalEvent::Return { .. } | FinalEvent::Throw { .. }) => return Some(e), } } } diff --git a/checker/src/context/calling.rs b/checker/src/context/calling.rs index 116ac5de..545bfe8b 100644 --- a/checker/src/context/calling.rs +++ b/checker/src/context/calling.rs @@ -1,5 +1,5 @@ use super::facts::Facts; -use crate::{events::EventResult, Environment, FunctionId}; +use crate::{events::FinalEvent, Environment, FunctionId}; /// For anything that might involve a call, including gets, sets and actual calls pub(crate) trait CallCheckingBehavior { @@ -46,6 +46,7 @@ pub(crate) struct Target(Vec); pub(crate) enum TargetKind { Conditional(Facts), Function(FunctionId), + LoopIteration, } impl CallCheckingBehavior for Target { @@ -79,14 +80,14 @@ impl CallCheckingBehavior for Target { impl Target { /// TODO temp for loop unrolling - pub(crate) fn new_default() -> Self { + pub(crate) fn new_empty() -> Self { Target(Vec::new()) } pub(crate) fn new_conditional_target( &mut self, - cb: impl for<'a> FnOnce(&'a mut Target) -> Option, - ) -> (Facts, Option) { + cb: impl for<'a> FnOnce(&'a mut Target) -> Option, + ) -> (Facts, Option) { self.0.push(TargetKind::Conditional(Facts::default())); let result = cb(self); if let Some(TargetKind::Conditional(facts)) = self.0.pop() { @@ -95,4 +96,21 @@ impl Target { unreachable!() } } + + pub(crate) fn new_loop_iteration( + &mut self, + cb: impl for<'a> FnOnce(&'a mut Target) -> T, + ) -> T { + self.0.push(TargetKind::LoopIteration); + let value = cb(self); + self.0.pop(); + value + } + + pub(crate) fn get_iteration_depth(&self) -> u8 { + let depth = self.0.iter().filter(|p| matches!(p, TargetKind::LoopIteration)).count() as u8; + // TODO can this every go > 1 + crate::utils::notify!("Iteration depth {}", depth); + depth + } } diff --git a/checker/src/context/environment.rs b/checker/src/context/environment.rs index cb16061a..2c06355f 100644 --- a/checker/src/context/environment.rs +++ b/checker/src/context/environment.rs @@ -13,7 +13,7 @@ use crate::{ variables::{VariableMutability, VariableOrImport, VariableWithValue}, }, diagnostics::{NotInLoopOrCouldNotFindLabel, TypeCheckError, TypeStringRepresentation, TDZ}, - events::{Event, RootReference}, + events::{Event, FinalEvent, RootReference}, subtyping::BasicEquality, types::{ is_type_truthy_falsy, @@ -57,6 +57,7 @@ pub enum DynamicBoundaryKind { } impl DynamicBoundaryKind { + #[must_use] pub fn can_use_variable_before_definition(self) -> bool { matches!(self, Self::Function) } @@ -871,6 +872,7 @@ impl<'a> Environment<'a> { { if let Decidable::Known(result) = is_type_truthy_falsy(condition, &checking_data.types) { // TODO emit warning + crate::utils::notify!("Constant result {:?}", result); return if result { then_evaluate(self, checking_data) } else if let Some(else_evaluate) = else_evaluate { @@ -903,10 +905,11 @@ impl<'a> Environment<'a> { R::combine(condition, truthy_result, falsy_result, &mut checking_data.types); let falsy_events = falsy_environment.facts.events; + // TODO It might be possible to get position from one of the SynthesisableConditional but its `get_position` is not implemented yet self.facts.events.push(Event::Conditionally { condition, - events_if_truthy: truthy_events.into_boxed_slice(), + true_events: truthy_events.into_boxed_slice(), else_events: falsy_events.into_boxed_slice(), position: None, }); @@ -919,7 +922,7 @@ impl<'a> Environment<'a> { } else { self.facts.events.push(Event::Conditionally { condition, - events_if_truthy: truthy_events.into_boxed_slice(), + true_events: truthy_events.into_boxed_slice(), else_events: Default::default(), position: None, }); @@ -930,12 +933,13 @@ impl<'a> Environment<'a> { } } - pub fn throw_value(&mut self, value: TypeId, position: SpanWithSource) { - self.facts.events.push(Event::Throw(value, position)); + pub fn throw_value(&mut self, thrown: TypeId, position: SpanWithSource) { + self.facts.events.push(FinalEvent::Throw { thrown, position }.into()); } pub fn return_value(&mut self, returned: TypeId, returned_position: SpanWithSource) { - self.facts.events.push(Event::Return { returned, returned_position }); + crate::utils::notify!("Returning value here"); + self.facts.events.push(FinalEvent::Return { returned, returned_position }.into()); } pub fn add_continue( @@ -944,10 +948,13 @@ impl<'a> Environment<'a> { position: Span, ) -> Result<(), NotInLoopOrCouldNotFindLabel> { if let Some(carry) = self.find_label_or_conditional_count(label, true) { - self.facts.events.push(Event::Continue { - position: Some(position.with_source(self.get_source())), - carry, - }); + self.facts.events.push( + FinalEvent::Continue { + position: Some(position.with_source(self.get_source())), + carry, + } + .into(), + ); Ok(()) } else { Err(NotInLoopOrCouldNotFindLabel { @@ -963,10 +970,14 @@ impl<'a> Environment<'a> { position: Span, ) -> Result<(), NotInLoopOrCouldNotFindLabel> { if let Some(carry) = self.find_label_or_conditional_count(label, false) { - self.facts.events.push(Event::Break { - position: Some(position.with_source(self.get_source())), - carry, - }); + crate::utils::notify!("Carry is {}", carry); + self.facts.events.push( + FinalEvent::Break { + position: Some(position.with_source(self.get_source())), + carry, + } + .into(), + ); Ok(()) } else { Err(NotInLoopOrCouldNotFindLabel { @@ -992,7 +1003,7 @@ impl<'a> Environment<'a> { on, publicity, under, - &PropertyValue::Value(new), + PropertyValue::Value(new), self, &mut CheckThings, types, @@ -1028,8 +1039,8 @@ impl<'a> Environment<'a> { if label == looking_for_label.unwrap() { return Some(falling_through_structures); } - falling_through_structures += 1; } + falling_through_structures += 1; } Scope::Conditional { is_switch: Some(_label @ Some(_)), .. } if !is_continue && looking_for_label.is_some() => @@ -1046,6 +1057,7 @@ impl<'a> Environment<'a> { None } + #[allow(clippy::too_many_arguments)] pub fn import_items< 'b, P: Iterator>, diff --git a/checker/src/context/facts.rs b/checker/src/context/facts.rs index f87f6971..10b4002a 100644 --- a/checker/src/context/facts.rs +++ b/checker/src/context/facts.rs @@ -67,8 +67,9 @@ impl Facts { } } - pub(crate) fn throw_value(&mut self, value: TypeId, position: SpanWithSource) { - self.events.push(Event::Throw(value, position)); + /// This is how invocation contexts register throws... + pub(crate) fn throw_value_in_facts(&mut self, value: TypeId, position: SpanWithSource) { + self.events.push(crate::events::FinalEvent::Throw { thrown: value, position }.into()); } #[must_use] diff --git a/checker/src/context/mod.rs b/checker/src/context/mod.rs index 3187fff2..3f1d298b 100644 --- a/checker/src/context/mod.rs +++ b/checker/src/context/mod.rs @@ -168,7 +168,7 @@ pub struct Context { /// For debugging AND noting what contexts contain what variables pub(crate) variable_names: HashMap, - /// TODO not sure if needed + /// TODO unsure if needed pub(crate) deferred_function_constraints: HashMap, pub(crate) bases: bases::Bases, @@ -755,25 +755,17 @@ impl Context { checking_data, |env, cd| { func(env, cd); - let mut thrown = Vec::new(); + let mut thrown = TypeId::NEVER_TYPE; let events = mem::take(&mut env.facts.events); + env.facts.events = crate::events::helpers::extract_throw_events(events, &mut thrown); + thrown }, ); - let mut thrown = thrown.into_iter(); - - if let Some(first) = thrown.next() { - let mut acc = first; - for next in thrown { - acc = checking_data.types.new_or_type(acc, next); - } - acc - } else { - TypeId::NEVER_TYPE - } + thrown } /// TODO @@ -1104,7 +1096,7 @@ impl Context { if let Entry::Vacant(vacant) = entry { vacant.insert(variable); - // TODO not sure ... + // TODO unsure ... let ty = if let Type::Function(..) = types.get_type_by_id(variable_ty) { variable_ty } else { diff --git a/checker/src/events/application.rs b/checker/src/events/application.rs index 08c50f59..e2b6f6c9 100644 --- a/checker/src/events/application.rs +++ b/checker/src/events/application.rs @@ -1,4 +1,4 @@ -use super::{CallingTiming, Event, EventResult, PrototypeArgument, RootReference}; +use super::{CallingTiming, Event, FinalEvent, PrototypeArgument, RootReference}; use crate::{ behavior::{ @@ -32,7 +32,7 @@ pub(crate) fn apply_event( target: &mut Target, types: &mut TypeStore, errors: &mut ErrorsAndInfo, -) -> Option { +) -> Option { match event { Event::ReadsReference { reference, reflects_dependency, position } => { if let Some(id) = reflects_dependency { @@ -157,8 +157,16 @@ pub(crate) fn apply_event( .get_latest_facts(environment) .register_property(on, publicity, under, new, true, position); } else { - let result = - set_property(on, publicity, &under, &new, environment, target, types, position); + let result = set_property( + on, + publicity, + &under, + new.clone(), + environment, + target, + types, + position, + ); if let Err(err) = result { if let SetPropertyError::DoesNotMeetConstraint { @@ -246,7 +254,7 @@ pub(crate) fn apply_event( // TODO different CallingTiming::QueueTask | CallingTiming::AtSomePointManyTimes => { todo!() - // TODO not sure whether need function id here + // TODO unsure whether need function id here // if let Some(Constant::FunctionReference(function)) = // environment.get_constant_type(on) // { @@ -265,20 +273,17 @@ pub(crate) fn apply_event( } } } - Event::Throw(thrown, position) => { - let substituted_thrown = substitute(thrown, type_arguments, environment, types); - - target.get_latest_facts(environment).throw_value(substituted_thrown, position); - - // TODO write down why result isn't added here - return Some(EventResult::Throw); - } // TODO extract - Event::Conditionally { condition, events_if_truthy, else_events, position } => { + Event::Conditionally { + condition, + true_events: events_if_truthy, + else_events, + position, + } => { let condition = substitute(condition, type_arguments, environment, types); let result = is_type_truthy_falsy(condition, types); - // crate::utils::notify!("Condition {:?}", result); + // crate::utils::notify!("Condition {:?} {:?}", types.get_type_by_id(condition), result); if let Decidable::Known(result) = result { let to_evaluate = if result { events_if_truthy } else { else_events }; @@ -299,7 +304,7 @@ pub(crate) fn apply_event( // TODO early returns // TODO could inject proofs but probably already worked out - let (truthy_facts, _early_return) = + let (mut truthy_facts, truthy_early_return) = target.new_conditional_target(|target: &mut Target| { for event in events_if_truthy.into_vec() { if let Some(early) = apply_event( @@ -317,7 +322,7 @@ pub(crate) fn apply_event( None }); - let (mut else_facts, _early_return) = + let (mut else_facts, else_early_return) = target.new_conditional_target(|target: &mut Target| { for event in else_events.into_vec() { if let Some(early) = apply_event( @@ -335,37 +340,62 @@ pub(crate) fn apply_event( None }); - // TODO early return + // TODO what about two early returns? + // crate::utils::notify!("TER {:?}, EER {:?}", truthy_early_return, else_early_return); + + if let Some(truthy_early_return) = truthy_early_return { + truthy_facts.events.push(truthy_early_return.into()); + } - // crate::utils::notify!("TF {:?}\n EF {:?}", truthy_facts, else_facts); + if let Some(else_early_return) = else_early_return { + else_facts.events.push(else_early_return.into()); + } // TODO all things that are // - variable and property values (these aren't read from events) // - immutable, mutable, prototypes etc // } let facts = target.get_latest_facts(environment); + + // Merge variable current values conditionally. TODO other facts...? for (var, truth) in truthy_facts.variable_current_value { let entry = facts.variable_current_value.entry(var); entry.and_modify(|existing| { - *existing = types.new_conditional_type( - condition, - truth, - else_facts.variable_current_value.remove(&var).unwrap_or(*existing), - ); + let else_result = + else_facts.variable_current_value.remove(&var).unwrap_or(*existing); + + *existing = types.new_conditional_type(condition, truth, else_result); }); } - target.get_latest_facts(environment).events.push(Event::Conditionally { + facts.events.push(Event::Conditionally { condition, - events_if_truthy: truthy_facts.events.into_boxed_slice(), + true_events: truthy_facts.events.into_boxed_slice(), else_events: else_facts.events.into_boxed_slice(), position, }); } } - Event::Return { returned, returned_position } => { - let substituted_returned = substitute(returned, type_arguments, environment, types); - return Some(EventResult::Return(substituted_returned, returned_position)); + Event::FinalEvent(final_event) => { + return Some(match final_event { + e @ (FinalEvent::Break { carry: 0, position: _ } + | FinalEvent::Continue { carry: 0, position: _ }) => e, + FinalEvent::Break { carry, position } => { + FinalEvent::Break { carry: carry - target.get_iteration_depth(), position } + } + FinalEvent::Continue { carry, position } => { + FinalEvent::Continue { carry: carry - target.get_iteration_depth(), position } + } + FinalEvent::Throw { thrown, position } => { + let substituted_thrown = substitute(thrown, type_arguments, environment, types); + FinalEvent::Throw { thrown: substituted_thrown, position } + } + FinalEvent::Return { returned, returned_position } => { + let substituted_returned = + substitute(returned, type_arguments, environment, types); + FinalEvent::Return { returned: substituted_returned, returned_position } + } + }); } // TODO Needs a position (or not?) Event::CreateObject { @@ -410,8 +440,6 @@ pub(crate) fn apply_event( type_arguments.set_id_from_reference(referenced_in_scope_as, new_object_id); } - Event::Break { position: _, carry } => return Some(EventResult::Break { carry }), - Event::Continue { position: _, carry } => return Some(EventResult::Continue { carry }), Event::Iterate { kind, iterate_over, initial } => { // TODO this might clash let initial = initial diff --git a/checker/src/events/helpers.rs b/checker/src/events/helpers.rs index d16fe65b..a4b5631d 100644 --- a/checker/src/events/helpers.rs +++ b/checker/src/events/helpers.rs @@ -1,4 +1,4 @@ -use super::Event; +use super::{Event, FinalEvent}; use crate::{types::new_logical_or_type, CheckingData, Environment, TypeId}; pub(crate) enum ReturnedTypeFromBlock { @@ -18,7 +18,7 @@ pub(crate) fn get_return_from_events<'a, T: crate::ReadFromFS, A: crate::ASTImpl ) -> ReturnedTypeFromBlock { while let Some(event) = iter.next() { match event { - Event::Return { returned, returned_position } => { + Event::FinalEvent(FinalEvent::Return { returned, returned_position }) => { if let Some((expected_return_type, annotation_span)) = expected_return_type { let mut behavior = crate::subtyping::BasicEquality { add_property_restrictions: true, @@ -58,9 +58,10 @@ pub(crate) fn get_return_from_events<'a, T: crate::ReadFromFS, A: crate::ASTImpl } return ReturnedTypeFromBlock::Returned(*returned); } - Event::Conditionally { condition: on, events_if_truthy, else_events, position: _ } => { + // TODO and for + Event::Conditionally { condition: on, true_events, else_events, position: _ } => { let return_if_truthy = get_return_from_events( - &mut events_if_truthy.iter(), + &mut true_events.iter(), checking_data, environment, expected_return_type, @@ -167,7 +168,7 @@ pub(crate) fn get_return_from_events<'a, T: crate::ReadFromFS, A: crate::ASTImpl } }; } - Event::Throw(_, _) => { + Event::FinalEvent(FinalEvent::Throw { .. }) => { // TODO ReturnedTypeFromBlock::Thrown? however this does work return ReturnedTypeFromBlock::Returned(TypeId::NEVER_TYPE); } @@ -180,11 +181,15 @@ pub(crate) fn get_return_from_events<'a, T: crate::ReadFromFS, A: crate::ASTImpl /// TODO improve /// /// This actually removes the events as they are caught -pub(crate) fn extract_throw_events(events: Vec, thrown: &mut Vec) -> Vec { +pub(crate) fn extract_throw_events(events: Vec, thrown: &mut TypeId) -> Vec { let mut new_events = Vec::new(); for event in events { - if let Event::Throw(value, _position) = event { - thrown.push(value); + if let Event::FinalEvent(FinalEvent::Throw { thrown: value, position: _ }) = event { + *thrown = value; + } else if let Event::Conditionally { .. } = event { + todo!() + } else if let Event::Iterate { .. } = event { + todo!() } else { // TODO nested grouping new_events.push(event); diff --git a/checker/src/events/mod.rs b/checker/src/events/mod.rs index 453b1547..4bfdf05a 100644 --- a/checker/src/events/mod.rs +++ b/checker/src/events/mod.rs @@ -34,21 +34,6 @@ impl RootReference { } } -/// If `carry == 0` then break -#[derive(Debug)] -pub enum EventResult { - Return(TypeId, SpanWithSource), - Break { - carry: u8, - }, - /// from `continue` statements, which should be called `skip`. - /// TODO maybe this can be abstracted - Continue { - carry: u8, - }, - Throw, -} - /// For iterations. TODO up for debate pub type InitialVariables = map_vec::Map; @@ -58,8 +43,6 @@ pub type InitialVariables = map_vec::Map; /// /// `reflects_dependency` means the result goes into the type argument map. This corresponds to the /// type id (of constructor) it goes under -/// -/// TODO store positions? #[derive(Debug, Clone, binary_serialize_derive::BinarySerializable)] pub enum Event { /// Reads a reference (as a free variable or `this`) @@ -102,12 +85,10 @@ pub enum Event { called_with_new: CalledWithNew, position: SpanWithSource, }, - /// From a `throw ***` statement (or expression) - Throw(TypeId, SpanWithSource), /// Run events conditionally Conditionally { condition: TypeId, - events_if_truthy: Box<[Event]>, + true_events: Box<[Event]>, else_events: Box<[Event]>, position: Option, }, @@ -120,11 +101,7 @@ pub enum Event { /// Contains initial values that the iteration runs over. Without, initial iterations can't access anything...? initial: InitialVariables, }, - /// TODO not sure but whatever - Return { - returned: TypeId, - returned_position: SpanWithSource, - }, + /// *lil bit magic*, handles: /// - Creating objects `{}` /// - Creating objects with prototypes: @@ -150,14 +127,35 @@ pub enum Event { /// Debug only is_function_this: bool, }, + FinalEvent(FinalEvent), +} + +impl From for Event { + fn from(value: FinalEvent) -> Self { + Event::FinalEvent(value) + } +} + +/// Nothing runs after this event +#[derive(Debug, Clone, binary_serialize_derive::BinarySerializable)] +pub enum FinalEvent { + Return { + returned: TypeId, + returned_position: SpanWithSource, + }, + /// From a `throw ***` statement (or expression) + Throw { + thrown: TypeId, + position: SpanWithSource, + }, Break { - position: Option, carry: u8, + position: Option, }, /// TODO explain why this can't be done with just (or at least label makes it more difficult) Continue { - position: Option, carry: u8, + position: Option, }, } diff --git a/checker/src/lib.rs b/checker/src/lib.rs index aab1ea51..b2ea031b 100644 --- a/checker/src/lib.rs +++ b/checker/src/lib.rs @@ -8,7 +8,6 @@ pub mod events; mod options; pub mod range_map; mod serialization; -pub mod structures; mod type_mappings; pub mod types; mod utils; @@ -39,7 +38,6 @@ use types::{subtyping::check_satisfies, TypeStore}; pub use context::{GeneralContext, RootContext}; pub use diagnostics::{Diagnostic, DiagnosticKind, DiagnosticsContainer}; pub use options::TypeCheckOptions; -pub use structures::jsx::*; pub use types::{calling::call_type_handle_errors, poly_types::GenericTypeParameters, subtyping}; pub use type_mappings::*; @@ -56,19 +54,23 @@ pub use source_map::{self, SourceId, Span}; /// Contains all the modules and mappings for import statements /// /// TODO could files and `synthesised_modules` be merged? (with a change to the source map crate) -pub struct ModuleData<'a, FileReader, ModuleAST: ASTImplementation> { +pub struct ModuleData<'a, FileReader, AST: ASTImplementation> { pub(crate) file_reader: &'a FileReader, + pub(crate) parser_requirements: AST::ParserRequirements, pub(crate) _current_working_directory: PathBuf, /// Contains the text content of files (for source maps and diagnostics) pub(crate) files: MapFileStore, /// To catch cyclic imports pub(crate) _currently_checking_modules: HashSet, /// The result of checking. Includes exported variables and facts - pub(crate) synthesised_modules: HashMap>, + pub(crate) synthesised_modules: HashMap>, } pub trait ASTImplementation: Sized { type ParseOptions; + /// Custom allocator etc + type ParserRequirements; + type ParseError: Into; type Module<'a>; @@ -88,19 +90,17 @@ pub trait ASTImplementation: Sized { type ClassMethod<'a>: SynthesisableFunction; - /// # Errors - /// TODO fn module_from_string( source_id: SourceId, string: String, options: Self::ParseOptions, + parser_requirements: &mut Self::ParserRequirements, ) -> Result, Self::ParseError>; - /// # Errors - /// TODO fn definition_module_from_string( source_id: SourceId, string: String, + parser_requirements: &mut Self::ParserRequirements, ) -> Result, Self::ParseError>; #[allow(clippy::needless_lifetimes)] @@ -156,11 +156,16 @@ pub trait ASTImplementation: Sized { fn owned_module_from_module(m: Self::Module<'static>) -> Self::OwnedModule; } -impl<'a, T: crate::ReadFromFS, ModuleAST: ASTImplementation> ModuleData<'a, T, ModuleAST> { +impl<'a, T, A> ModuleData<'a, T, A> +where + T: crate::ReadFromFS, + A: ASTImplementation, +{ pub(crate) fn new( file_resolver: &'a T, current_working_directory: PathBuf, files: Option>, + parser_requirements: A::ParserRequirements, ) -> Self { Self { files: files.unwrap_or_default(), @@ -169,6 +174,7 @@ impl<'a, T: crate::ReadFromFS, ModuleAST: ASTImplementation> ModuleData<'a, T, M // custom_module_resolvers, file_reader: file_resolver, _current_working_directory: current_working_directory, + parser_requirements, } } @@ -236,16 +242,21 @@ pub struct CheckingData<'a, FSResolver, ModuleAST: ASTImplementation> { #[derive(Debug, Clone)] pub struct CouldNotOpenFile(pub PathBuf); -impl<'a, T: crate::ReadFromFS, A: crate::ASTImplementation> CheckingData<'a, T, A> { +impl<'a, T, A> CheckingData<'a, T, A> +where + T: crate::ReadFromFS, + A: crate::ASTImplementation, +{ // TODO improve on this function pub fn new( options: TypeCheckOptions, resolver: &'a T, existing_files: Option>, + parser_requirements: A::ParserRequirements, ) -> Self { // let custom_file_resolvers = HashMap::default(); let cwd = Default::default(); - let modules = ModuleData::new(resolver, cwd, existing_files); + let modules = ModuleData::new(resolver, cwd, existing_files, parser_requirements); Self { options, @@ -291,7 +302,13 @@ impl<'a, T: crate::ReadFromFS, A: crate::ASTImplementation> CheckingData<'a, T, let parse_options = A::parse_options(is_js, checking_data.options.parse_comments); - match A::module_from_string(source, content, parse_options) { + let module_from_string = A::module_from_string( + source, + content, + parse_options, + &mut checking_data.modules.parser_requirements, + ); + match module_from_string { Ok(module) => { let new_module_context = environment.get_root().new_module_context( source, @@ -409,13 +426,20 @@ pub struct PostCheckData { pub modules: HashMap>, } +#[allow(clippy::needless_pass_by_value)] pub fn check_project( entry_points: Vec, type_definition_files: HashSet, resolver: T, options: Option, + parser_requirements: A::ParserRequirements, ) -> (crate::DiagnosticsContainer, Result, MapFileStore>) { - let mut checking_data = CheckingData::::new(options.unwrap_or_default(), &resolver, None); + let mut checking_data = CheckingData::::new( + options.unwrap_or_default(), + &resolver, + None, + parser_requirements, + ); let mut root = crate::context::RootContext::new_with_primitive_references(); @@ -426,7 +450,7 @@ pub fn check_project( } for point in &entry_points { - let entry_content = (checking_data.modules.file_reader)(&point); + let entry_content = (checking_data.modules.file_reader)(point); if let Some(content) = entry_content { let source = checking_data.modules.files.new_source_id(point.clone(), content.clone()); @@ -436,7 +460,12 @@ pub fn check_project( let parse_options = A::parse_options(is_js, checking_data.options.parse_comments); - let module = A::module_from_string(source, content, parse_options); + let module = A::module_from_string( + source, + content, + parse_options, + &mut checking_data.modules.parser_requirements, + ); match module { Ok(module) => { root.new_module_context(source, module, &mut checking_data); @@ -491,7 +520,11 @@ pub(crate) fn add_definition_files_to_root { diff --git a/checker/src/serialization.rs b/checker/src/serialization.rs index 45172ba4..e9646033 100644 --- a/checker/src/serialization.rs +++ b/checker/src/serialization.rs @@ -9,7 +9,7 @@ use std::{ use source_map::{SourceId, SpanWithSource}; -/// TODO not sure about iterator +/// TODO unsure about iterator /// This is automated by the derive macro TODO link pub(crate) trait BinarySerializable { fn serialize(self, buf: &mut Vec); diff --git a/checker/src/structures/README.md b/checker/src/structures/README.md deleted file mode 100644 index f883beb4..00000000 --- a/checker/src/structures/README.md +++ /dev/null @@ -1 +0,0 @@ -TODO random structures diff --git a/checker/src/structures/jsx.rs b/checker/src/structures/jsx.rs deleted file mode 100644 index 39ff2681..00000000 --- a/checker/src/structures/jsx.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::TypeId; - -pub enum ForwardInterpolationSpot { - Attribute { name: TypeId }, - NodeChild { idx: usize }, -} diff --git a/checker/src/structures/mod.rs b/checker/src/structures/mod.rs deleted file mode 100644 index 559dc535..00000000 --- a/checker/src/structures/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Contains definitions and implementations of structures used throughout the checker - -pub mod jsx; -pub mod modules; -pub mod proxy; -pub mod variables; diff --git a/checker/src/structures/modules.rs b/checker/src/structures/modules.rs deleted file mode 100644 index 8b137891..00000000 --- a/checker/src/structures/modules.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/checker/src/structures/proxy.rs b/checker/src/structures/proxy.rs deleted file mode 100644 index bb92df6b..00000000 --- a/checker/src/structures/proxy.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::TypeId; - -#[derive(Debug, Clone, binary_serialize_derive::BinarySerializable)] -pub struct Proxy { - pub(crate) wraps: TypeId, - pub(crate) trap_object: TypeId, -} diff --git a/checker/src/structures/variables.rs b/checker/src/structures/variables.rs deleted file mode 100644 index 8b137891..00000000 --- a/checker/src/structures/variables.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/checker/src/synthesis/classes.rs b/checker/src/synthesis/classes.rs index 02a277da..db927737 100644 --- a/checker/src/synthesis/classes.rs +++ b/checker/src/synthesis/classes.rs @@ -60,7 +60,7 @@ pub(super) fn synthesise_class_declaration< // Property keys on `static` items let mut static_property_keys: Vec> = Vec::new(); - for (_idx, member) in class.members.iter().enumerate() { + for member in &class.members { match &member.on { ClassMember::Method(None, method) => { let publicity = match method.name.get_ast_ref() { diff --git a/checker/src/synthesis/extensions/jsx.rs b/checker/src/synthesis/extensions/jsx.rs index 0a9b3aa3..c2f43452 100644 --- a/checker/src/synthesis/extensions/jsx.rs +++ b/checker/src/synthesis/extensions/jsx.rs @@ -332,7 +332,7 @@ pub(crate) fn synthesise_jsx_element( // // &None, // // checking_data, // // environment, - // // // TODO not sure, this won't work for classes right... + // // // TODO unsure, this won't work for classes right... // // crate::events::CalledWithNew::None, // // ) // // .unwrap() diff --git a/checker/src/synthesis/hoisting.rs b/checker/src/synthesis/hoisting.rs index 382e552a..c4210502 100644 --- a/checker/src/synthesis/hoisting.rs +++ b/checker/src/synthesis/hoisting.rs @@ -174,7 +174,7 @@ pub(crate) fn hoist_statements( } // Second stage - for (_idx, item) in items.iter().enumerate() { + for item in items { match item { StatementOrDeclaration::Statement(stmt) => { if let Statement::VarVariable(_) = stmt { diff --git a/checker/src/synthesis/mod.rs b/checker/src/synthesis/mod.rs index b36083b5..d0d38fe8 100644 --- a/checker/src/synthesis/mod.rs +++ b/checker/src/synthesis/mod.rs @@ -33,81 +33,6 @@ use self::{ type_annotations::synthesise_type_annotation, }; -pub(super) fn parser_property_key_to_checker_property_key< - P: parser::property_key::PropertyKeyKind, - T: crate::ReadFromFS, ->( - property_key: &ParserPropertyKey

, - environment: &mut Environment, - checking_data: &mut CheckingData, -) -> PropertyKey<'static> { - match property_key { - ParserPropertyKey::StringLiteral(value, ..) | ParserPropertyKey::Ident(value, ..) => { - PropertyKey::String(std::borrow::Cow::Owned(value.clone())) - } - ParserPropertyKey::NumberLiteral(number, _) => { - let result = f64::try_from(number.clone()); - match result { - Ok(v) => { - // TODO is there a better way - #[allow(clippy::float_cmp)] - if v.floor() == v { - PropertyKey::from_usize(v as usize) - } else { - // TODO - PropertyKey::String(std::borrow::Cow::Owned(v.to_string())) - } - } - // TODO - Err(()) => todo!(), - } - } - ParserPropertyKey::Computed(expression, _) => { - let key_type = - synthesise_expression(expression, environment, checking_data, TypeId::ANY_TYPE); - PropertyKey::from_type(key_type, &checking_data.types) - } - } -} - -impl From<(parser::ParseError, SourceId)> for Diagnostic { - fn from(parse_error: (parser::ParseError, SourceId)) -> Self { - Diagnostic::Position { - reason: parse_error.0.reason, - position: parse_error.0.position.with_source(parse_error.1), - kind: crate::diagnostics::DiagnosticKind::Error, - } - } -} - -pub enum Performs<'a> { - Block(&'a parser::Block), - Const(String), - None, -} - -impl crate::GenericTypeParameter for parser::GenericTypeConstraint { - fn get_name(&self) -> &str { - self.name() - } -} - -impl<'a> From> for Performs<'a> { - fn from(value: Option<&'a parser::types::AnnotationPerforms>) -> Self { - match value { - Some(parser::types::AnnotationPerforms::PerformsConst { - performs_keyword: _, - identifier, - }) => Performs::Const(identifier.clone()), - Some(parser::types::AnnotationPerforms::PerformsStatements { - performs_keyword: _, - statements, - }) => Performs::Block(statements), - None => Performs::None, - } - } -} - pub struct EznoParser; // Clippy suggests a fix that breaks the code @@ -115,6 +40,7 @@ pub struct EznoParser; impl crate::ASTImplementation for EznoParser { type ParseOptions = parser::ParseOptions; type ParseError = (parser::ParseError, SourceId); + type ParserRequirements = (); type Module<'a> = parser::Module; type OwnedModule = parser::Module; @@ -133,6 +59,7 @@ impl crate::ASTImplementation for EznoParser { source_id: SourceId, string: String, options: Self::ParseOptions, + _parser_requirements: &mut Self::ParserRequirements, ) -> Result, Self::ParseError> { ::from_string(string, options, source_id, None) .map_err(|err| (err, source_id)) @@ -141,6 +68,7 @@ impl crate::ASTImplementation for EznoParser { fn definition_module_from_string( source_id: SourceId, string: String, + _parser_requirements: &mut Self::ParserRequirements, ) -> Result, Self::ParseError> { let options = Default::default(); parser::TypeDefinitionModule::from_string(&string, options, source_id) @@ -232,6 +160,82 @@ impl crate::ASTImplementation for EznoParser { } } +pub(super) fn parser_property_key_to_checker_property_key< + P: parser::property_key::PropertyKeyKind, + T: crate::ReadFromFS, +>( + property_key: &ParserPropertyKey

, + environment: &mut Environment, + checking_data: &mut CheckingData, +) -> PropertyKey<'static> { + match property_key { + ParserPropertyKey::StringLiteral(value, ..) | ParserPropertyKey::Ident(value, ..) => { + PropertyKey::String(std::borrow::Cow::Owned(value.clone())) + } + ParserPropertyKey::NumberLiteral(number, _) => { + let result = f64::try_from(number.clone()); + match result { + Ok(v) => { + // TODO is there a better way + #[allow(clippy::float_cmp)] + if v.floor() == v { + PropertyKey::from_usize(v as usize) + } else { + // TODO + PropertyKey::String(std::borrow::Cow::Owned(v.to_string())) + } + } + // TODO + Err(()) => todo!(), + } + } + ParserPropertyKey::Computed(expression, _) => { + let key_type = + synthesise_expression(expression, environment, checking_data, TypeId::ANY_TYPE); + PropertyKey::from_type(key_type, &checking_data.types) + } + } +} + +impl From<(parser::ParseError, SourceId)> for Diagnostic { + fn from(parse_error: (parser::ParseError, SourceId)) -> Self { + Diagnostic::Position { + reason: parse_error.0.reason, + position: parse_error.0.position.with_source(parse_error.1), + kind: crate::diagnostics::DiagnosticKind::Error, + } + } +} + +pub enum Performs<'a> { + Block(&'a parser::Block), + Const(String), + None, +} + +impl crate::GenericTypeParameter for parser::GenericTypeConstraint { + fn get_name(&self) -> &str { + self.name() + } +} + +impl<'a> From> for Performs<'a> { + fn from(value: Option<&'a parser::types::AnnotationPerforms>) -> Self { + match value { + Some(parser::types::AnnotationPerforms::PerformsConst { + performs_keyword: _, + identifier, + }) => Performs::Const(identifier.clone()), + Some(parser::types::AnnotationPerforms::PerformsStatements { + performs_keyword: _, + statements, + }) => Performs::Block(statements), + None => Performs::None, + } + } +} + +/// For the REPL in Ezno's CLI pub mod interactive { use std::{collections::HashSet, mem, path::PathBuf}; @@ -257,7 +261,7 @@ pub mod interactive { ) -> Result)> { let mut root = RootContext::new_with_primitive_references(); let mut checking_data = - CheckingData::new(Default::default(), resolver, Default::default()); + CheckingData::new(Default::default(), resolver, Default::default(), ()); add_definition_files_to_root(type_definition_files, &mut root, &mut checking_data); diff --git a/checker/src/synthesis/type_annotations.rs b/checker/src/synthesis/type_annotations.rs index c7b3ebc7..5c3cc5c6 100644 --- a/checker/src/synthesis/type_annotations.rs +++ b/checker/src/synthesis/type_annotations.rs @@ -381,11 +381,7 @@ pub(super) fn synthesise_type_annotation( synthesise_type_annotation(being_indexed, environment, checking_data); let indexer = synthesise_type_annotation(indexer, environment, checking_data); - checking_data.types.new_property_on_type_annotation( - being_indexed, - indexer, - &environment, - ) + checking_data.types.new_property_on_type_annotation(being_indexed, indexer, environment) } TypeAnnotation::KeyOf(_, _) => unimplemented!(), TypeAnnotation::Conditional { condition, resolve_true, resolve_false, position: _ } => { @@ -470,7 +466,7 @@ pub(crate) fn comment_as_type_annotation( let offset = Some(position.end - 2 - possible_declaration.len() as u32); let possible_declaration = - possible_declaration.strip_prefix("*").unwrap_or(possible_declaration); + possible_declaration.strip_prefix('*').unwrap_or(possible_declaration); let annotation = parser::TypeAnnotation::from_string( possible_declaration.to_owned(), diff --git a/checker/src/types/calling.rs b/checker/src/types/calling.rs index 1a9b4277..d0eaa3c6 100644 --- a/checker/src/types/calling.rs +++ b/checker/src/types/calling.rs @@ -8,7 +8,7 @@ use crate::{ }, context::{calling::CheckThings, CallCheckingBehavior, Environment, Logical}, diagnostics::{TypeCheckError, TypeStringRepresentation, TDZ}, - events::{application::ErrorsAndInfo, apply_event, Event, EventResult, RootReference}, + events::{application::ErrorsAndInfo, apply_event, Event, FinalEvent, RootReference}, subtyping::{type_is_subtype, BasicEquality, SubTypeResult}, types::{ functions::SynthesisedArgument, poly_types::generic_type_arguments::TypeArgumentStore, @@ -94,14 +94,22 @@ pub(crate) fn call_type( behavior: &mut E, types: &mut TypeStore, ) -> Result> { - if on == TypeId::ERROR_TYPE - || arguments.iter().any(|arg| match arg { - SynthesisedArgument::NonSpread { ty, .. } => *ty == TypeId::ERROR_TYPE, - }) { - crate::utils::notify!("Exiting earlier because of ERROR_TYPE fail"); + let never_or_error_type = + matches!(on, TypeId::ERROR_TYPE | TypeId::NEVER_TYPE).then_some(on).or_else(|| { + arguments.iter().find_map(|a| match a { + SynthesisedArgument::NonSpread { ty, .. } => { + matches!(*ty, TypeId::ERROR_TYPE | TypeId::NEVER_TYPE).then_some(*ty) + } + }) + }); + + if let Some(never_or_error_type) = never_or_error_type { + crate::utils::notify!( + "Exiting earlier because of Never or Error being called or as argument" + ); return Ok(FunctionCallResult { called: None, - returned_type: TypeId::ERROR_TYPE, + returned_type: never_or_error_type, warnings: Vec::new(), special: None, found_dependent_argument: false, @@ -234,7 +242,7 @@ fn create_generic_function_call( behavior: &mut E, types: &mut TypeStore, ) -> Result> { - crate::utils::notify!("On {:?}", types.get_type_by_id(constraint)); + // crate::utils::notify!("On {:?}", types.get_type_by_id(constraint)); let result = call_type( constraint, @@ -324,16 +332,20 @@ fn create_generic_function_call( result.returned_type }; - let constructor = Constructor::Image { - // TODO on or to - on, - with: with.clone(), - result: returned_type_space, - }; + if result.found_dependent_argument { + Some(returned_type_space) + } else { + let constructor = Constructor::Image { + // TODO on or to + on, + with: with.clone(), + result: returned_type_space, + }; - let constructor_return = types.register_type(Type::Constructor(constructor)); + let constructor_return = types.register_type(Type::Constructor(constructor)); - Some(constructor_return) + Some(constructor_return) + } }; // Event already added if dependent argument @@ -507,7 +519,7 @@ impl FunctionType { }); } Ok(ConstantOutput::Diagnostic(diagnostic)) => { - crate::utils::notify!("Here, constant output"); + // crate::utils::notify!("Here, constant output"); return Ok(FunctionCallResult { returned_type: TypeId::UNDEFINED_TYPE, warnings: vec![InfoDiagnostic(diagnostic)], @@ -868,9 +880,20 @@ impl FunctionType { } } - // set events should cover property specialisation here: - let returned_type = if let Some(EventResult::Return(returned_type, _)) = early_return { - returned_type + let returned_type = if let Some(early_return) = early_return { + match early_return { + FinalEvent::Break { .. } | FinalEvent::Continue { .. } => { + unreachable!("function ended on continue / break") + } + FinalEvent::Throw { thrown: value, position } => { + behavior.get_latest_facts(environment).throw_value_in_facts(value, position); + TypeId::NEVER_TYPE + } + FinalEvent::Return { returned, returned_position: _ } => { + // set events should cover property specialisation here: + returned + } + } } else { crate::utils::notify!("Substituting return type (no return)"); substitute(self.return_type, &mut type_arguments, environment, types) diff --git a/checker/src/types/functions.rs b/checker/src/types/functions.rs index 90e5cfd7..87b8c34f 100644 --- a/checker/src/types/functions.rs +++ b/checker/src/types/functions.rs @@ -22,7 +22,7 @@ pub struct FunctionType { /// If async, generator and what to do with `this` pub behavior: FunctionBehavior, - /// TODO not sure about this field and how it tails with Pi Types + /// TODO unsure about this field and how it tails with Pi Types pub type_parameters: Option, pub parameters: SynthesisedParameters, /// This is just aesthetic TODO also throw diff --git a/checker/src/types/mod.rs b/checker/src/types/mod.rs index 0a47dde1..d955958e 100644 --- a/checker/src/types/mod.rs +++ b/checker/src/types/mod.rs @@ -200,7 +200,7 @@ impl Type { Type::And(_, _) | Type::Or(_, _) => false, // TODO what about if it aliases Type::AliasTo { .. } | Type::Interface { .. } => { - // TODO not sure + // TODO unsure false } Type::Constant(_) @@ -482,7 +482,7 @@ pub(crate) fn get_constraint(on: TypeId, types: &TypeStore) -> Option { PolyNature::RecursiveFunction(_, return_ty) => return_ty, }; - // TODO not sure + // TODO unsure Some(*based_on) @@ -635,7 +635,7 @@ pub(crate) fn get_constraint(on: TypeId, types: &TypeStore) -> Option { // .get_property_unbound(on_constraint, PublicityKind::Public, property, types) // .map(|property| match property { // Logical::Pure(PropertyValue::Value(v)) => v, - // // TODO not sure? + // // TODO unsure? // Logical::Pure(PropertyValue::Getter(g)) => g.return_type, // result => todo!("{:?}", result), // }) diff --git a/checker/src/types/poly_types/substitution.rs b/checker/src/types/poly_types/substitution.rs index 8a2a32e6..cc99b48d 100644 --- a/checker/src/types/poly_types/substitution.rs +++ b/checker/src/types/poly_types/substitution.rs @@ -145,7 +145,7 @@ pub(crate) fn substitute( substitute(else_result, arguments, environment, types) } } else { - crate::utils::notify!("{:?} not decidable", condition); + crate::utils::notify!("{:?} is undecidable", condition); let truthy_result = substitute(truthy_result, arguments, environment, types); let else_result = substitute(else_result, arguments, environment, types); // TODO result_union @@ -203,7 +203,7 @@ pub(crate) fn substitute( } } Constructor::Image { .. } => { - todo!("Constructor::Image should be covered by events"); + todo!("Constructor::Image {id:?} should be covered by events"); // id // let on = substitute(on, arguments, environment); diff --git a/checker/src/types/printing.rs b/checker/src/types/printing.rs index ad03eb8a..eaa7321c 100644 --- a/checker/src/types/printing.rs +++ b/checker/src/types/printing.rs @@ -5,7 +5,7 @@ use super::{properties::PropertyKey, PolyNature, Type, TypeArguments, TypeId, Ty use crate::{ behavior::objects::SpecialObjects, context::{facts::Publicity, get_on_ctx, Logical}, - events::Event, + events::{Event, FinalEvent}, types::{get_constraint, Constructor, StructureGenerics}, Constant, GeneralContext, PropertyValue, }; @@ -524,11 +524,12 @@ pub fn debug_effects( }); // TODO args } - Event::Throw(value, _) => { - buf.push_str("throw "); - print_type_into_buf(*value, buf, &mut HashSet::new(), None, types, ctx, debug); - } - Event::Conditionally { condition, events_if_truthy, else_events, position: _ } => { + Event::Conditionally { + condition, + true_events: events_if_truthy, + else_events, + position: _, + } => { buf.push_str("if "); print_type_into_buf(*condition, buf, &mut HashSet::new(), None, types, ctx, debug); buf.push_str(" then "); @@ -538,10 +539,7 @@ pub fn debug_effects( debug_effects(buf, else_events, types, ctx, debug); } } - Event::Return { returned, returned_position: _ } => { - buf.push_str("return "); - print_type_into_buf(*returned, buf, &mut HashSet::new(), None, types, ctx, debug); - } + Event::CreateObject { prototype: _, referenced_in_scope_as, @@ -555,17 +553,25 @@ pub fn debug_effects( .unwrap(); } } - Event::Break { .. } => { - buf.push_str("break"); - } - Event::Continue { .. } => { - buf.push_str("continue"); - } Event::Iterate { iterate_over, initial: _, kind: _ } => { buf.push_str("iterate\n"); debug_effects(buf, iterate_over, types, ctx, debug); buf.push_str("end"); } + Event::FinalEvent(FinalEvent::Throw { thrown, .. }) => { + buf.push_str("throw "); + print_type_into_buf(*thrown, buf, &mut HashSet::new(), None, types, ctx, debug); + } + Event::FinalEvent(FinalEvent::Break { .. }) => { + buf.push_str("break"); + } + Event::FinalEvent(FinalEvent::Continue { .. }) => { + buf.push_str("continue"); + } + Event::FinalEvent(FinalEvent::Return { returned, returned_position: _ }) => { + buf.push_str("return "); + print_type_into_buf(*returned, buf, &mut HashSet::new(), None, types, ctx, debug); + } } buf.push('\n'); } diff --git a/checker/src/types/properties.rs b/checker/src/types/properties.rs index 6663d42c..89669af1 100644 --- a/checker/src/types/properties.rs +++ b/checker/src/types/properties.rs @@ -21,7 +21,7 @@ use super::{calling::CalledWithNew, Constructor, Type, TypeStore}; pub enum PropertyKind { Direct, Getter, - /// TODO not sure + /// TODO unsure Generic, } @@ -113,7 +113,7 @@ impl PropertyValue { match self { PropertyValue::Value(value) => *value, PropertyValue::Getter(getter) => getter.return_type, - // TODO not sure about these two + // TODO unsure about these two PropertyValue::Setter(_) => TypeId::UNDEFINED_TYPE, PropertyValue::Deleted => TypeId::NEVER_TYPE, } @@ -124,7 +124,7 @@ impl PropertyValue { match self { PropertyValue::Value(value) => *value, PropertyValue::Setter(setter) => setter.return_type, - // TODO not sure about these two + // TODO unsure about these two PropertyValue::Getter(_) => TypeId::UNDEFINED_TYPE, PropertyValue::Deleted => TypeId::NEVER_TYPE, } @@ -153,9 +153,18 @@ pub(crate) fn get_property( return Some((PropertyKind::Direct, TypeId::ERROR_TYPE)); } - if let Some(constraint) = get_constraint(on, types) { + if get_constraint(on, types).is_some() { + // // TODO temp fix for assigning to a poly type. What about unions etc + // if let Some(value) = top_environment.facts_chain().find_map(|f| { + // f.current_properties.get(&on).and_then(|props| { + // props.iter().find_map(|(_publicity, key, value)| (key == &under).then_some(value)) + // }) + // }) { + // return Some((PropertyKind::Direct, value.as_get_type())); + // } + evaluate_get_on_poly( - constraint, + // constraint, on, publicity, under.clone(), @@ -174,9 +183,9 @@ pub(crate) fn get_property( } else { todo!("build and type") }; + // TODO ... evaluate_get_on_poly( constraint, - on, publicity, under.clone(), with, @@ -328,7 +337,6 @@ fn get_from_an_object( #[allow(clippy::too_many_arguments)] #[allow(clippy::needless_pass_by_value)] fn evaluate_get_on_poly( - constraint: TypeId, on: TypeId, publicity: Publicity, under: PropertyKey, @@ -453,7 +461,7 @@ fn evaluate_get_on_poly( } } - let fact = top_environment.get_property_unbound(constraint, publicity, under.clone(), types)?; + let fact = top_environment.get_property_unbound(on, publicity, under.clone(), types)?; // crate::utils::notify!("unbound is is {:?}", fact); @@ -478,7 +486,7 @@ pub(crate) fn set_property( on: TypeId, publicity: Publicity, under: &PropertyKey, - new: &PropertyValue, + new: PropertyValue, environment: &mut Environment, behavior: &mut E, types: &TypeStore, @@ -518,7 +526,7 @@ pub(crate) fn set_property( let result = type_is_subtype_of_property( &property_constraint, None, - *value, + value, &mut basic_subtyping, environment, types, @@ -565,7 +573,35 @@ pub(crate) fn set_property( // crate::utils::notify!("(2) Made it here assigning to {:?}", types.get_type_by_id(on)); - let new = PropertyValue::Value(new.as_get_type()); + // Cascade if it is a union (unsure tho) + if let Type::Constructor(Constructor::ConditionalResult { + truthy_result, + else_result, + condition: _, + result_union: _, + }) = types.get_type_by_id(on) + { + set_property( + *truthy_result, + publicity, + under, + new.clone(), + environment, + behavior, + types, + setter_position, + )?; + return set_property( + *else_result, + publicity, + under, + new, + environment, + behavior, + types, + setter_position, + ); + } if let Some(fact) = current_property { match fact { diff --git a/checker/src/types/store.rs b/checker/src/types/store.rs index 822c8b98..62236aea 100644 --- a/checker/src/types/store.rs +++ b/checker/src/types/store.rs @@ -137,11 +137,19 @@ impl TypeStore { } pub fn new_or_type(&mut self, lhs: TypeId, rhs: TypeId) -> TypeId { + if lhs == rhs { + return lhs; + } + let ty = Type::Or(lhs, rhs); self.register_type(ty) } pub fn new_and_type(&mut self, lhs: TypeId, rhs: TypeId) -> TypeId { + if lhs == rhs { + return lhs; + } + // TODO distribute or types let ty = Type::And(lhs, rhs); self.register_type(ty) @@ -291,28 +299,48 @@ impl TypeStore { } } Type::RootPolyType(_nature) => { - // TODO None here - let aliases = get_constraint(on, self).unwrap(); - // Don't think any properties exist on this poly type - self.get_fact_about_type(ctx, aliases, resolver, data) + // Can assign to properties on parameters etc + let on_root_type = ctx + .parents_iter() + .find_map(|env| resolver(&env, self, on, data)) + .map(Logical::Pure); + + on_root_type.or_else(|| { + let aliases = get_constraint(on, self).expect("poly type with no constraint"); + self.get_fact_about_type(ctx, aliases, resolver, data) + }) } Type::Constructor(Constructor::StructureGenerics(StructureGenerics { - on, + on: sg_base, arguments, })) => { - let fact_opt = self.get_fact_about_type(ctx, *on, resolver, data); + let on_sg_type = ctx + .parents_iter() + .find_map(|env| resolver(&env, self, on, data)) + .map(Logical::Pure); - fact_opt.map(|fact| Logical::Implies { - on: Box::new(fact), - antecedent: arguments.clone(), + on_sg_type.or_else(|| { + let fact_opt = self.get_fact_about_type(ctx, *sg_base, resolver, data); + + fact_opt.map(|fact| Logical::Implies { + on: Box::new(fact), + antecedent: arguments.clone(), + }) }) } Type::Constructor(_constructor) => { - // Don't think any properties exist on this poly type - // TODO None here - let constraint = get_constraint(on, self).unwrap(); - // TODO might need to send more information here, rather than forgetting via .get_type - self.get_fact_about_type(ctx, constraint, resolver, data) + let on_constructor_type = ctx + .parents_iter() + .find_map(|env| resolver(&env, self, on, data)) + .map(Logical::Pure); + + on_constructor_type.or_else(|| { + // TODO implies ??? + let constraint = + get_constraint(on, self).expect("no constraint for constructor"); + // TODO might need to send more information here, rather than forgetting via .get_type + self.get_fact_about_type(ctx, constraint, resolver, data) + }) } Type::Object(..) | Type::Interface { .. } => ctx .parents_iter() @@ -376,7 +404,7 @@ impl TypeStore { indexee, crate::context::facts::Publicity::Public, PropertyKey::from_type(indexer, self), - &self, + self, ) { match prop { crate::context::Logical::Pure(ty) => ty.as_get_type(), diff --git a/checker/src/types/terms.rs b/checker/src/types/terms.rs index 2350e5c0..47dd4366 100644 --- a/checker/src/types/terms.rs +++ b/checker/src/types/terms.rs @@ -6,7 +6,7 @@ use super::TypeId; /// - `BigInt` () /// - Separate `NotNull` term, and implement js subtyping /// -/// TODO not sure about some of these +/// TODO unsure about some of these #[derive(Eq, PartialEq, Hash, Debug, Clone, binary_serialize_derive::BinarySerializable)] pub enum Constant { Number(ordered_float::NotNan), diff --git a/parser/src/expressions/mod.rs b/parser/src/expressions/mod.rs index 7e5eba53..2526a9e2 100644 --- a/parser/src/expressions/mod.rs +++ b/parser/src/expressions/mod.rs @@ -1225,7 +1225,7 @@ impl Expression { | Self::SuperExpression(..) | Self::NewTarget(..) | Self::ClassExpression(..) - // TODO not sure about this one...? + // TODO unsure about this one...? | Self::DynamicImport { .. } | Self::Cursor { .. } => PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE, // TODO think this is true <- Self::BinaryOperation { operator, .. } => operator.precedence(), @@ -1245,10 +1245,10 @@ impl Expression { Self::PrefixComment(_, expression, _) | Self::PostfixComment(expression, _, _) => { expression.get_precedence() } - Self::Comment(..) => PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE, // TODO not sure about this + Self::Comment(..) => PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE, // TODO unsure about this // All these are relational and have the same precedence Self::SpecialOperators(..) => RELATION_PRECEDENCE, - // TODO not sure about this one...? + // TODO unsure about this one...? #[cfg(feature = "extras")] Self::IsExpression(..) => PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE, } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 682a285a..edce1367 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -131,7 +131,7 @@ impl ParseOptions { } } -// TODO not sure about some of these defaults, may change in future +// TODO unsure about some of these defaults, may change in future impl Default for ParseOptions { fn default() -> Self { Self { @@ -160,7 +160,7 @@ pub struct ToStringOptions { pub single_statement_on_new_line: bool, /// Include type annotation syntax pub include_types: bool, - /// TODO not sure about this + /// TODO unsure about this pub include_decorators: bool, pub comments: Comments, pub indent_with: String, diff --git a/parser/src/operators.rs b/parser/src/operators.rs index 2feb6233..5e17d08c 100644 --- a/parser/src/operators.rs +++ b/parser/src/operators.rs @@ -256,7 +256,7 @@ impl Operator for BinaryAssignmentOperator { } fn is_associative(&self) -> bool { - // dbg!("TODO not sure"); + // dbg!("TODO unsure"); true } } diff --git a/parser/src/statements/while_statement.rs b/parser/src/statements/while_statement.rs index b930460d..e723aa6e 100644 --- a/parser/src/statements/while_statement.rs +++ b/parser/src/statements/while_statement.rs @@ -56,7 +56,7 @@ impl ASTNode for WhileStatement { #[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))] pub struct DoWhileStatement { pub condition: MultipleExpression, - // TODO not sure about true here + // TODO unsure about true here pub inner: BlockOrSingleStatement, pub position: Span, } diff --git a/parser/src/tokens.rs b/parser/src/tokens.rs index 9ea268a3..a88e1f7c 100644 --- a/parser/src/tokens.rs +++ b/parser/src/tokens.rs @@ -325,7 +325,7 @@ pub enum TSXKeyword { Private, Public, Protected, // TS Keywords As, Declare, Readonly, Infer, Is, Satisfies, Namespace, KeyOf, - // TODO not sure + // TODO unsure #[cfg(feature = "extras")] Module, // Extra function modifiers #[cfg(feature = "extras")] Server, #[cfg(feature = "extras")] Worker, diff --git a/parser/src/types/type_annotations.rs b/parser/src/types/type_annotations.rs index cfceb5b3..835eab8b 100644 --- a/parser/src/types/type_annotations.rs +++ b/parser/src/types/type_annotations.rs @@ -615,7 +615,7 @@ impl TypeAnnotation { return Ok(reference); }; // Array shorthand & indexing type references. Loops as number[][] - // Not sure if index type can be looped + // unsure if index type can be looped while reader.conditional_next(|tok| *tok == TSXToken::OpenBracket).is_some() { let start = reference.get_position(); if let Some(Token(TSXToken::CloseBracket, _)) = reader.peek() { diff --git a/parser/src/variable_fields.rs b/parser/src/variable_fields.rs index e4aaae50..08041d49 100644 --- a/parser/src/variable_fields.rs +++ b/parser/src/variable_fields.rs @@ -432,7 +432,7 @@ impl ASTNode for ObjectDestructuringField { } } -/// TODO not sure about the positions here, is potential duplication if `T::OptionalExpression` is none +/// TODO unsure about the positions here, is potential duplication if `T::OptionalExpression` is none #[derive(Debug, Clone)] #[cfg_attr(feature = "self-rust-tokenize", derive(self_rust_tokenize::SelfRustTokenize))] #[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))] diff --git a/src/check.rs b/src/check.rs index 4f2be7d0..271b00a6 100644 --- a/src/check.rs +++ b/src/check.rs @@ -28,5 +28,5 @@ pub fn check( let type_check_options = None; - checker::check_project(entry_points, definitions, read_from_fs, type_check_options) + checker::check_project(entry_points, definitions, read_from_fs, type_check_options, ()) } diff --git a/src/cli.rs b/src/cli.rs index 013c6936..4adf0365 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -172,7 +172,7 @@ pub fn run_cli