From a891b69ba49da1eeb0bf106ee2af6fb4363a0714 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 20 Mar 2024 22:27:54 +0000 Subject: [PATCH] Closure & variable declaration fixes --- checker/definitions/full.d.ts | 1 - checker/specification/specification.md | 19 +----- checker/specification/staging.md | 6 +- checker/src/context/environment.rs | 15 ++++- checker/src/context/mod.rs | 5 +- checker/src/diagnostics.rs | 7 +++ checker/src/synthesis/hoisting.rs | 3 +- checker/src/synthesis/type_annotations.rs | 2 + checker/src/types/calling.rs | 46 ++++++++------ .../generics/generic_type_arguments.rs | 63 +++++++++++-------- 10 files changed, 94 insertions(+), 73 deletions(-) diff --git a/checker/definitions/full.d.ts b/checker/definitions/full.d.ts index f4b01887..55e678d6 100644 --- a/checker/definitions/full.d.ts +++ b/checker/definitions/full.d.ts @@ -259,7 +259,6 @@ declare function context_id_chain(): void; @Constant declare function satisfies(t: T): T; - @Constant declare function compile_type_to_object(): any; // ↑↑ Ezno Functions ↑↑ \ No newline at end of file diff --git a/checker/specification/specification.md b/checker/specification/specification.md index 7aced7bd..e250046e 100644 --- a/checker/specification/specification.md +++ b/checker/specification/specification.md @@ -58,7 +58,7 @@ a = 3; let a = 2; ``` -- Cannot assign to variable 'a' before initialisation +- Cannot assign to 'a' before declaration #### Assignment to non-existent variable @@ -2064,23 +2064,6 @@ callFunction(a => { - Expected number, found string -#### Returning a function - -> Yes, returns another function - -```ts -type ExpectedFunction = () => ((a: string) => string) - -const x: ExpectedFunction = function () { - return function (b) { - b satisfies number; - return b - } -} -``` - -- Expected number, found string - ### Object constraint > Any references to a annotated variable **must** be within its LHS type. These test that it carries down to objects. diff --git a/checker/specification/staging.md b/checker/specification/staging.md index e515abf7..efecd6f3 100644 --- a/checker/specification/staging.md +++ b/checker/specification/staging.md @@ -418,12 +418,12 @@ This contains new features (which don't have) #### Comments as type annotations ```ts -function x(a /* : string */) { +function x(a /** string */) { a satisfies number } -const c /* : number */ = "5" +const c /** number */ = "5" ``` - Expected number, found string -- Cannot assign "5" to type number +- Type "5" is not assignable to type number diff --git a/checker/src/context/environment.rs b/checker/src/context/environment.rs index 6c9da4e5..b6196e7c 100644 --- a/checker/src/context/environment.rs +++ b/checker/src/context/environment.rs @@ -504,7 +504,7 @@ impl<'a> Environment<'a> { // Get without the effects let variable_in_map = self.get_variable_unbound(variable_name); - if let Some((_, _, variable)) = variable_in_map { + if let Some((_, boundary, variable)) = variable_in_map { match variable { VariableOrImport::Variable { mutability, declared_at, context: _ } => { match mutability { @@ -514,6 +514,17 @@ impl<'a> Environment<'a> { VariableMutability::Mutable { reassignment_constraint } => { let variable = variable.clone(); let variable_site = *declared_at; + let variable_id = variable.get_id(); + + if boundary.is_none() + && !self.get_chain_of_info().any(|info| { + info.variable_current_value.contains_key(&variable_id) + }) { + return Err(AssignmentError::TDZ(TDZ { + position: assignment_position, + variable_name: variable_name.to_owned(), + })); + } if let Some(reassignment_constraint) = *reassignment_constraint { // TODO tuple with position: @@ -554,8 +565,6 @@ impl<'a> Environment<'a> { } } - let variable_id = variable.get_id(); - self.info.events.push(Event::SetsVariable( variable_id, new_type, diff --git a/checker/src/context/mod.rs b/checker/src/context/mod.rs index 7c9d50c7..8b6f47c4 100644 --- a/checker/src/context/mod.rs +++ b/checker/src/context/mod.rs @@ -19,7 +19,7 @@ use source_map::{Span, SpanWithSource}; use crate::{ context::environment::ExpectedReturnType, diagnostics::{ - CannotRedeclareVariable, TypeCheckError, TypeCheckWarning, TypeStringRepresentation, + CannotRedeclareVariable, TypeCheckError, TypeCheckWarning, TypeStringRepresentation, TDZ, }, events::{ApplicationResult, RootReference}, features::{ @@ -354,6 +354,8 @@ impl Context { } /// Similar to [`Context::get_this_unbound`] + /// + /// First `bool` is whether this variable is on [`Context`] fn get_variable_unbound( &self, variable_name: &str, @@ -1080,6 +1082,7 @@ pub enum AssignmentError { value_type: TypeStringRepresentation, assignment_position: SpanWithSource, }, + TDZ(TDZ), } /// Wraps logic diff --git a/checker/src/diagnostics.rs b/checker/src/diagnostics.rs index ca3ad1b6..c59a3407 100644 --- a/checker/src/diagnostics.rs +++ b/checker/src/diagnostics.rs @@ -599,6 +599,13 @@ mod defined_errors_and_warnings { kind, } } + AssignmentError::TDZ(TDZ { variable_name, position }) => { + Diagnostic::Position { + reason: format!("Cannot assign to '{variable_name}' before declaration"), + position, + kind, + } + } }, TypeCheckError::InvalidJSXAttribute { attribute_name, diff --git a/checker/src/synthesis/hoisting.rs b/checker/src/synthesis/hoisting.rs index b97c89ec..0e08159c 100644 --- a/checker/src/synthesis/hoisting.rs +++ b/checker/src/synthesis/hoisting.rs @@ -228,12 +228,13 @@ pub(crate) fn hoist_statements( } } - // Second stage + // Second stage: variables and function type hoisting for item in items { match item { StatementOrDeclaration::Statement(stmt) => { if let Statement::VarVariable(stmt) = stmt { for declaration in &stmt.declarations { + crate::utils::notify!("declaration.name {:?}", declaration.name); let constraint = get_annotation_from_declaration( declaration, environment, diff --git a/checker/src/synthesis/type_annotations.rs b/checker/src/synthesis/type_annotations.rs index 79b4d994..a90d9d54 100644 --- a/checker/src/synthesis/type_annotations.rs +++ b/checker/src/synthesis/type_annotations.rs @@ -502,6 +502,7 @@ pub(crate) fn comment_as_type_annotation( annotation.get_position().with_source(source), )) } else { + crate::utils::notify!("Failed comment as type annotation"); // TODO warning None } @@ -525,6 +526,7 @@ pub(crate) fn get_annotation_from_declaration< else if let parser::WithComment::PostfixComment(_item, possible_declaration, position) = &declaration.name { + crate::utils::notify!("Here {:?}", possible_declaration); comment_as_type_annotation( possible_declaration, &position.with_source(environment.get_source()), diff --git a/checker/src/types/calling.rs b/checker/src/types/calling.rs index db6acaa7..1c36b193 100644 --- a/checker/src/types/calling.rs +++ b/checker/src/types/calling.rs @@ -55,8 +55,6 @@ struct FunctionLike { pub(crate) function: FunctionId, /// For generic calls pub(crate) from: Option, - /// TODO WIP - pub(crate) _is_dependent: bool, pub(crate) this_value: ThisValue, } @@ -82,22 +80,34 @@ pub fn call_type_handle_errors { // Always from Ok(Logical::Pure(FunctionLike { - _is_dependent: from.is_some(), from: Some(from.unwrap_or(ty)), function: *f, this_value: on.unwrap_or(*t), @@ -252,7 +259,6 @@ fn get_logical_callable_from_type( } Type::SpecialObject(SpecialObjects::ClassConstructor { constructor, .. }) => { Ok(Logical::Pure(FunctionLike { - _is_dependent: from.is_some(), from, function: *constructor, this_value: ThisValue::UseParent, diff --git a/checker/src/types/poly_types/generics/generic_type_arguments.rs b/checker/src/types/poly_types/generics/generic_type_arguments.rs index 7a2e20c4..24eeb64e 100644 --- a/checker/src/types/poly_types/generics/generic_type_arguments.rs +++ b/checker/src/types/poly_types/generics/generic_type_arguments.rs @@ -78,37 +78,42 @@ impl TypeArgumentStore for FunctionTypeArguments { None } - fn curry_arguments(&self, types: &mut TypeStore, id: TypeId) -> TypeId { + fn curry_arguments(&self, types: &mut TypeStore, on: TypeId) -> TypeId { // TODO some types might not have parameters, but still need specialising so this here will miss things out // types.get_type_by_id(id).get_parameters() { // let arguments = parameters // .into_iter() // .map(|p| (p, (self.local_arguments.get(&p).copied().unwrap_or(p), self.call_site))) // .collect(); - let id = if self.local_arguments.is_empty() { - id - } else { - types.register_type(Type::Constructor(crate::types::Constructor::StructureGenerics( - StructureGenerics { - on: id, - arguments: StructureGenericArguments::ExplicitRestrictions( - self.local_arguments - .iter() - .map(|(on, arg)| (*on, (*arg, self.call_site))) - .collect(), - ), - }, - ))) - }; - if self.closure_ids.is_empty() { - id + if let Type::Object(crate::types::ObjectNature::RealDeal) | Type::SpecialObject(..) = + types.get_type_by_id(on) + { + if self.closure_ids.is_empty() { + on + } else { + types.register_type(Type::Constructor( + crate::types::Constructor::StructureGenerics(StructureGenerics { + on, + arguments: StructureGenericArguments::Closure(self.closure_ids.clone()), + }), + )) + } } else { - types.register_type(Type::Constructor(crate::types::Constructor::StructureGenerics( - StructureGenerics { - on: id, - arguments: StructureGenericArguments::Closure(self.closure_ids.clone()), - }, - ))) + if self.local_arguments.is_empty() { + on + } else { + types.register_type(Type::Constructor( + crate::types::Constructor::StructureGenerics(StructureGenerics { + on, + arguments: StructureGenericArguments::ExplicitRestrictions( + self.local_arguments + .iter() + .map(|(on, arg)| (*on, (*arg, self.call_site))) + .collect(), + ), + }), + )) + } } } @@ -135,6 +140,11 @@ pub enum StructureGenericArguments { /// The object that has a generic prototype on: TypeId, }, + // /// TODO this shouldn't exist, but as there is no way to disce + // ClosuresAndGenerics { + // closures: Vec, + // restrictions: TypeRestrictions, + // }, } impl StructureGenericArguments { @@ -155,8 +165,9 @@ impl StructureGenericArguments { types: &TypeStore, ) -> Option> { match self { - StructureGenericArguments::ExplicitRestrictions(s) => { - s.get(&under).map(|(ty, _)| vec![*ty]) + // | Self::ClosuresAndGenerics { restrictions, .. } => { + StructureGenericArguments::ExplicitRestrictions(restrictions) => { + restrictions.get(&under).map(|(ty, _)| vec![*ty]) } StructureGenericArguments::Closure(_) => None, StructureGenericArguments::LookUp { on } => {