From 523bf1689b497d3e656f5e6d6cfd7edc2110de4e Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 29 Aug 2024 12:54:15 +0100 Subject: [PATCH 1/4] Fix for #199 - Also adds type check support for it - Emoji fix in CLI --- .github/workflows/examples.yml | 21 +++++++++++---------- checker/specification/specification.md | 18 +++++++++++++++++- checker/src/features/functions.rs | 24 +++++++++++++++++++++++- checker/src/types/calling.rs | 7 +++++-- parser/src/expressions/mod.rs | 5 +++++ src/cli.rs | 22 ++++++++++++++++++---- 6 files changed, 79 insertions(+), 18 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 4c772b00..7f960df5 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -32,24 +32,25 @@ jobs: - name: Run checker on example files shell: bash + continue-on-error: true run: | files=( - "https://jsr.io/@yossydev/hello-world/1.0.0/index.ts" - "https://jsr.io/@bengineering/shuffle-binary/0.0.1/index.ts" - "https://jsr.io/@bengineering/mulberry32/0.0.1/mod.ts" - "https://jsr.io/@luca/cases/1.0.0/mod.ts" - "https://jsr.io/@std/assert/1.0.2/assertion_error.ts" - "https://jsr.io/@std/text/1.0.3/levenshtein_distance.ts" - "https://jsr.io/@gnome/monads/0.0.0/src/option.ts" - "https://raw.githubusercontent.com/getify/deePool/master/src/deePool.js" - "https://raw.githubusercontent.com/silen-z/fiveway/main/packages/fiveway/src/id.ts" + https://jsr.io/@yossydev/hello-world/1.0.0/index.ts + https://jsr.io/@bengineering/shuffle-binary/0.0.1/index.ts + https://jsr.io/@bengineering/mulberry32/0.0.1/mod.ts + https://jsr.io/@luca/cases/1.0.0/mod.ts + https://jsr.io/@std/assert/1.0.2/assertion_error.ts + https://jsr.io/@std/text/1.0.3/levenshtein_distance.ts + https://jsr.io/@gnome/monads/0.0.0/src/option.ts + https://raw.githubusercontent.com/getify/deePool/master/src/deePool.js + https://raw.githubusercontent.com/silen-z/fiveway/main/packages/fiveway/src/id.ts ) for url in "${files[@]}"; do header="--- $url ---" echo $header curl -s $url > temp.ts - ./target/release/ezno check temp.ts --timings + ./target/release/ezno check temp.ts --timings || true echo "${header//?/-}" echo "" done \ No newline at end of file diff --git a/checker/specification/specification.md b/checker/specification/specification.md index 6fb08cab..f218a2b4 100644 --- a/checker/specification/specification.md +++ b/checker/specification/specification.md @@ -3263,6 +3263,22 @@ doThingWithX(new Y()) - Argument of type [Y] { a: 2 } is not assignable to parameter of type X +#### Generics to constructor + +```ts +class Box { + value: T; + + constructor(value: T) { + this.value = value; + } +} + +const myBox = new Box("hi"); +``` + +- Argument of type "hi" is not assignable to parameter of type number + ### Types #### Non existent type @@ -3696,7 +3712,7 @@ type GetPrefix = S extends `${infer T} ${End}` ? T : false; - Expected "Hello", found 4 -#### `infer ... extends ...` +#### Infer with extends clause ```ts type X = T extends { a: infer I extends string } ? I : string; diff --git a/checker/src/features/functions.rs b/checker/src/features/functions.rs index 27542b95..6a7a6905 100644 --- a/checker/src/features/functions.rs +++ b/checker/src/features/functions.rs @@ -649,7 +649,29 @@ where let mut function_environment = base_environment.new_lexical_environment(Scope::Function(scope)); if function.has_body() { - let type_parameters = function.type_parameters(&mut function_environment, checking_data); + let type_parameters = if let Some((ref prototype, _)) = constructor { + // Class generics here + checking_data.types.get_type_by_id(*prototype).get_parameters().map(|parameters| { + parameters + .into_iter() + .map(|ty| { + let Type::RootPolyType(PolyNature::StructureGeneric { name, .. }) = + checking_data.types.get_type_by_id(ty) + else { + unreachable!() + }; + crate::types::generics::GenericTypeParameter { + name: name.clone(), + // Using its associated [`Type`], its restriction can be found + type_id: ty, + default: None, + } + }) + .collect() + }) + } else { + function.type_parameters(&mut function_environment, checking_data) + }; // TODO should be in function, but then requires mutable environment :( let this_constraint = diff --git a/checker/src/types/calling.rs b/checker/src/types/calling.rs index 3ea2723a..63f46696 100644 --- a/checker/src/types/calling.rs +++ b/checker/src/types/calling.rs @@ -1859,8 +1859,11 @@ fn synthesise_argument_expressions_wrt_parameters entry_points, Err(_) => return ExitCode::FAILURE, @@ -224,7 +232,10 @@ pub fn run_cli { @@ -374,7 +388,7 @@ pub fn run_cli Date: Thu, 29 Aug 2024 12:57:57 +0100 Subject: [PATCH 2/4] Fix because I can't stage correctly --- src/cli.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index ffdd6d85..d0118798 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -121,9 +121,6 @@ pub(crate) struct CheckArguments { /// compact diagnostics #[argh(switch)] pub compact_diagnostics: bool, - /// disable certain features - #[argh(switch)] - pub basic: bool, /// maximum diagnostics to print (defaults to 30, pass `all` for all and `0` to count) #[argh(option, default = "MaxDiagnostics::default()")] pub max_diagnostics: MaxDiagnostics, @@ -204,7 +201,6 @@ pub fn run_cli entry_points, Err(_) => return ExitCode::FAILURE, From f8591dc621a1813302dfb52118fcf2530abfa320 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 29 Aug 2024 15:03:22 +0100 Subject: [PATCH 3/4] More fixes - Add Exportable::Enum - Add temp enum implementation - Add fix to reporting - Class hoisting fix --- checker/src/diagnostics.rs | 17 +++- checker/src/features/functions.rs | 40 ++++---- checker/src/lib.rs | 4 +- checker/src/synthesis/block.rs | 4 +- checker/src/synthesis/classes.rs | 83 +++++++++++++--- checker/src/synthesis/declarations.rs | 131 +++++++++++++++++--------- checker/src/synthesis/definitions.rs | 2 +- checker/src/synthesis/expressions.rs | 10 +- checker/src/synthesis/hoisting.rs | 98 ++++++++++++++----- checker/src/types/properties/mod.rs | 6 ++ parser/src/block.rs | 2 +- parser/src/declarations/export.rs | 37 +++++--- parser/src/expressions/mod.rs | 3 +- parser/src/options.rs | 3 +- src/reporting.rs | 6 +- 15 files changed, 319 insertions(+), 127 deletions(-) diff --git a/checker/src/diagnostics.rs b/checker/src/diagnostics.rs index 94db0a0b..94cecf0a 100644 --- a/checker/src/diagnostics.rs +++ b/checker/src/diagnostics.rs @@ -932,8 +932,8 @@ pub enum TypeCheckWarning { }, IgnoringAsExpression(SpanWithSource), Unimplemented { - thing: &'static str, - at: SpanWithSource, + item: &'static str, + position: SpanWithSource, }, UselessExpression { expression_span: SpanWithSource, @@ -960,6 +960,10 @@ pub enum TypeCheckWarning { rhs: TypeStringRepresentation, position: SpanWithSource, }, + ItemMustBeUsedWithFlag { + item: &'static str, + position: SpanWithSource, + }, } impl From for Diagnostic { @@ -993,9 +997,14 @@ impl From for Diagnostic { position, kind, }, - TypeCheckWarning::Unimplemented { thing, at } => { - Diagnostic::Position { reason: format!("Unsupported: {thing}"), position: at, kind } + TypeCheckWarning::Unimplemented { item, position } => { + Diagnostic::Position { reason: format!("Unsupported: {item}"), position, kind } } + TypeCheckWarning::ItemMustBeUsedWithFlag { item, position } => Diagnostic::Position { + reason: format!("{item} must be used with 'extras' option"), + position, + kind, + }, TypeCheckWarning::UselessExpression { expression_span } => Diagnostic::Position { reason: "Expression is always true".to_owned(), position: expression_span, diff --git a/checker/src/features/functions.rs b/checker/src/features/functions.rs index 6a7a6905..95dae547 100644 --- a/checker/src/features/functions.rs +++ b/checker/src/features/functions.rs @@ -651,24 +651,7 @@ where if function.has_body() { let type_parameters = if let Some((ref prototype, _)) = constructor { // Class generics here - checking_data.types.get_type_by_id(*prototype).get_parameters().map(|parameters| { - parameters - .into_iter() - .map(|ty| { - let Type::RootPolyType(PolyNature::StructureGeneric { name, .. }) = - checking_data.types.get_type_by_id(ty) - else { - unreachable!() - }; - crate::types::generics::GenericTypeParameter { - name: name.clone(), - // Using its associated [`Type`], its restriction can be found - type_id: ty, - default: None, - } - }) - .collect() - }) + class_generics_to_function_generics(*prototype, &checking_data.types) } else { function.type_parameters(&mut function_environment, checking_data) }; @@ -1153,3 +1136,24 @@ pub fn extract_name(expecting: TypeId, types: &TypeStore, environment: &Environm TypeId::EMPTY_STRING } } + +pub fn class_generics_to_function_generics(prototype: TypeId, types: &TypeStore) -> Option { + types.get_type_by_id(prototype).get_parameters().map(|parameters| { + parameters + .into_iter() + .map(|ty| { + let Type::RootPolyType(PolyNature::StructureGeneric { name, .. }) = + types.get_type_by_id(ty) + else { + unreachable!() + }; + crate::types::generics::GenericTypeParameter { + name: name.clone(), + // Using its associated [`Type`], its restriction can be found + type_id: ty, + default: None, + } + }) + .collect() + }) +} \ No newline at end of file diff --git a/checker/src/lib.rs b/checker/src/lib.rs index f0faebba..39e60306 100644 --- a/checker/src/lib.rs +++ b/checker/src/lib.rs @@ -369,10 +369,10 @@ where } /// TODO temp, needs better place - pub fn raise_unimplemented_error(&mut self, item: &'static str, span: SpanWithSource) { + pub fn raise_unimplemented_error(&mut self, item: &'static str, position: SpanWithSource) { if self.unimplemented_items.insert(item) { self.diagnostics_container - .add_warning(TypeCheckWarning::Unimplemented { thing: item, at: span }); + .add_warning(TypeCheckWarning::Unimplemented { item, position }); } } diff --git a/checker/src/synthesis/block.rs b/checker/src/synthesis/block.rs index 9aba8f14..9f0bf7ea 100644 --- a/checker/src/synthesis/block.rs +++ b/checker/src/synthesis/block.rs @@ -1,4 +1,4 @@ -use parser::{ASTNode, Statement, StatementOrDeclaration}; +use parser::{ASTNode, Declaration, Statement, StatementOrDeclaration}; use crate::{context::Environment, diagnostics::TypeCheckWarning, CheckingData}; @@ -43,7 +43,7 @@ pub(super) fn synthesise_block( e, StatementOrDeclaration::Statement( Statement::Comment(..) | Statement::MultiLineComment(..) | Statement::Empty(..) - ) + ) | StatementOrDeclaration::Declaration(Declaration::Function(..)) ) }) { checking_data.diagnostics_container.add_warning(TypeCheckWarning::Unreachable( diff --git a/checker/src/synthesis/classes.rs b/checker/src/synthesis/classes.rs index 5495dc09..1d9047a5 100644 --- a/checker/src/synthesis/classes.rs +++ b/checker/src/synthesis/classes.rs @@ -9,12 +9,12 @@ use crate::{ diagnostics::TypeCheckError, features::functions::{ function_to_property, synthesise_function, ClassPropertiesToRegister, - FunctionRegisterBehavior, GetterSetter, SynthesisableFunction, + FunctionRegisterBehavior, GetterSetter, SynthesisableFunction, class_generics_to_function_generics, ReturnType }, types::{ classes::ClassValue, properties::{PropertyKey, Publicity}, - FunctionType, PolyNature, + FunctionType, PolyNature, SynthesisedParameters }, CheckingData, FunctionId, PropertyValue, Scope, Type, TypeId, }; @@ -492,12 +492,13 @@ fn synthesise_class_declaration_extends_and_members< /// Also sets variable for hoisting /// /// Builds the type of the class +#[must_use] pub(super) fn register_statement_class_with_members( class_type: TypeId, class: &ClassDeclaration, environment: &mut Environment, checking_data: &mut CheckingData, -) { +) -> TypeId { let class_type2 = checking_data.types.get_type_by_id(class_type); let Type::Class { name: _, type_parameters } = class_type2 else { @@ -516,15 +517,18 @@ pub(super) fn register_statement_class_with_members( sub_environment.named_types.insert(name.clone(), *parameter); } - register_extends_and_member(class, class_type, &mut sub_environment, checking_data); + + let result = + register_extends_and_member(class, class_type, &mut sub_environment, checking_data); { let crate::context::LocalInformation { current_properties, prototypes, .. } = sub_environment.info; environment.info.current_properties.extend(current_properties); environment.info.prototypes.extend(prototypes); } + result } else { - register_extends_and_member(class, class_type, environment, checking_data); + register_extends_and_member(class, class_type, environment, checking_data) } } @@ -533,7 +537,7 @@ fn register_extends_and_member( class_type: TypeId, environment: &mut Environment, checking_data: &mut CheckingData, -) { +) -> TypeId { if let Some(ref extends) = class.extends { let extends = get_extends_as_simple_type(extends, environment, checking_data); @@ -547,6 +551,9 @@ fn register_extends_and_member( // checking_data.local_type_mappings.types_to_types.push(class.position, class_type); let mut members_iter = class.members.iter().peekable(); + + let mut found_constructor = None::; + while let Some(member) = members_iter.next() { match &member.on { ClassMember::Method(initial_is_static, method) => { @@ -591,7 +598,7 @@ fn register_extends_and_member( .with_source(environment.get_source()), }, ); - return; + continue; } } else { let actual = synthesise_shape(method, environment, checking_data); @@ -716,14 +723,68 @@ fn register_extends_and_member( value, ); } - ClassMember::Constructor(c) => { - if !c.has_body() { - crate::utilities::notify!("TODO possible constructor overloading"); - } + ClassMember::Constructor(constructor) => { + let internal_effect = get_internal_function_effect_from_decorators( + &member.decorators, + "", + environment, + ); + + let mut actual = synthesise_shape(constructor, environment, checking_data); + actual.0 = class_generics_to_function_generics(class_type, &checking_data.types); + + let constructor = build_overloaded_function( + FunctionId(environment.get_source(), constructor.position.start), + crate::types::functions::FunctionBehavior::Constructor { + // The prototype of the base object + prototype: class_type, + // The id of the generic that needs to be pulled out + this_object_type: TypeId::ERROR_TYPE, + name: TypeId::ANY_TYPE, + }, + Vec::new(), + actual, + environment, + &mut checking_data.types, + &mut checking_data.diagnostics_container, + if let Some(ie) = internal_effect { + ie.into() + } else { + crate::types::functions::FunctionEffect::Unknown + }, + ); + + found_constructor = Some(constructor); } ClassMember::StaticBlock(_) | ClassMember::Comment(_, _, _) => {} } } + + if let Some(constructor) = found_constructor { + constructor + } else { + let return_type = ReturnType(class_type, class.position.with_source(environment.get_source())); + build_overloaded_function( + FunctionId(environment.get_source(), class.position.start), + crate::types::functions::FunctionBehavior::Constructor { + // The prototype of the base object + prototype: class_type, + // The id of the generic that needs to be pulled out + this_object_type: TypeId::ERROR_TYPE, + name: TypeId::ANY_TYPE, + }, + Vec::new(), + crate::features::functions::PartialFunction( + class_generics_to_function_generics(class_type, &checking_data.types), + SynthesisedParameters::default(), + Some(return_type), + ), + environment, + &mut checking_data.types, + &mut checking_data.diagnostics_container, + crate::types::functions::FunctionEffect::Unknown + ) + } } /// For hoisting using the class as a type annotation diff --git a/checker/src/synthesis/declarations.rs b/checker/src/synthesis/declarations.rs index 1911c885..771e754f 100644 --- a/checker/src/synthesis/declarations.rs +++ b/checker/src/synthesis/declarations.rs @@ -10,48 +10,6 @@ use super::{ variables::synthesise_variable_declaration_item, }; -pub(super) fn synthesise_variable_declaration( - declaration: &VariableDeclaration, - environment: &mut Environment, - checking_data: &mut CheckingData, - exported: bool, - infer_constraint: bool, -) { - match declaration { - VariableDeclaration::ConstDeclaration { declarations, .. } => { - for variable_declaration in declarations { - synthesise_variable_declaration_item( - variable_declaration, - environment, - checking_data, - exported.then_some(VariableMutability::Constant), - infer_constraint, - ); - } - } - VariableDeclaration::LetDeclaration { declarations, .. } => { - for variable_declaration in declarations { - let exported = exported.then(|| { - let restriction = checking_data - .local_type_mappings - .variable_restrictions - .get(&(environment.get_source(), variable_declaration.position.start)) - .map(|(first, _)| *first); - VariableMutability::Mutable { reassignment_constraint: restriction } - }); - - synthesise_variable_declaration_item( - variable_declaration, - environment, - checking_data, - exported, - infer_constraint, - ); - } - } - } -} - pub(crate) fn synthesise_declaration( declaration: &Declaration, environment: &mut Environment, @@ -84,7 +42,7 @@ pub(crate) fn synthesise_declaration( } } Declaration::Export(exported) => match &exported.on { - parser::declarations::ExportDeclaration::Variable { exported, position: _ } => { + parser::declarations::ExportDeclaration::Item { exported, position: _ } => { match exported { // Skipped as this is done earlier parser::declarations::export::Exportable::Class(class) => { @@ -93,6 +51,7 @@ pub(crate) fn synthesise_declaration( .types_to_types .get_exact(class.name.identifier.get_position()) .copied(); + // TODO mark as exported let _ = synthesise_class_declaration( class, @@ -137,6 +96,7 @@ pub(crate) fn synthesise_declaration( parser::declarations::export::Exportable::ImportAll { .. } | parser::declarations::export::Exportable::ImportParts { .. } | parser::declarations::export::Exportable::Function(_) + | parser::declarations::export::Exportable::EnumDeclaration(_) | parser::declarations::export::Exportable::Interface(_) | parser::declarations::export::Exportable::TypeAlias(_) => {} } @@ -172,12 +132,95 @@ pub(crate) fn synthesise_declaration( ); } }, + Declaration::Enum(r#enum) => { + use crate::types::{ + properties::{PropertyKey, PropertyValue, Publicity}, + Constant, + }; + + let mut basis = crate::features::objects::ObjectBuilder::new( + None, + &mut checking_data.types, + r#enum.get_position().with_source(environment.get_source()), + &mut environment.info, + ); + + // TODO remove enumerate, add add function and more + for (idx, member) in r#enum.on.members.iter().enumerate() { + match member { + parser::ast::EnumMember::Variant { name, value, position } => { + if let Some(ref _value) = value { + checking_data.raise_unimplemented_error( + "enum with value", + position.with_source(environment.get_source()), + ); + } + + let value = checking_data + .types + .new_constant_type(Constant::Number((idx as u8).into())); + + basis.append( + Publicity::Public, + PropertyKey::from(name.clone()), + PropertyValue::Value(value), + member.get_position().with_source(environment.get_source()), + &mut environment.info, + ); + } + } + } + + let variable = crate::VariableId(environment.get_source(), r#enum.get_position().start); + environment.info.variable_current_value.insert(variable, basis.build_object()); + } Declaration::DeclareVariable(_) | Declaration::Function(_) - | Declaration::Enum(_) | Declaration::Interface(_) | Declaration::TypeAlias(_) | Declaration::Namespace(_) | Declaration::Import(_) => {} } } + +pub(super) fn synthesise_variable_declaration( + declaration: &VariableDeclaration, + environment: &mut Environment, + checking_data: &mut CheckingData, + exported: bool, + infer_constraint: bool, +) { + match declaration { + VariableDeclaration::ConstDeclaration { declarations, .. } => { + for variable_declaration in declarations { + synthesise_variable_declaration_item( + variable_declaration, + environment, + checking_data, + exported.then_some(VariableMutability::Constant), + infer_constraint, + ); + } + } + VariableDeclaration::LetDeclaration { declarations, .. } => { + for variable_declaration in declarations { + let exported = exported.then(|| { + let restriction = checking_data + .local_type_mappings + .variable_restrictions + .get(&(environment.get_source(), variable_declaration.position.start)) + .map(|(first, _)| *first); + VariableMutability::Mutable { reassignment_constraint: restriction } + }); + + synthesise_variable_declaration_item( + variable_declaration, + environment, + checking_data, + exported, + infer_constraint, + ); + } + } + } +} diff --git a/checker/src/synthesis/definitions.rs b/checker/src/synthesis/definitions.rs index dcda810e..3b4381b5 100644 --- a/checker/src/synthesis/definitions.rs +++ b/checker/src/synthesis/definitions.rs @@ -27,7 +27,7 @@ pub(super) fn type_definition_file( if let StatementOrDeclaration::Declaration( Declaration::Class(Decorated { on: class, .. }) | Declaration::Export(Decorated { - on: ExportDeclaration::Variable { exported: Exportable::Class(class), position: _ }, + on: ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, .. }), ) = item diff --git a/checker/src/synthesis/expressions.rs b/checker/src/synthesis/expressions.rs index 837f99c5..08e95b32 100644 --- a/checker/src/synthesis/expressions.rs +++ b/checker/src/synthesis/expressions.rs @@ -114,14 +114,16 @@ pub(super) fn synthesise_expression( } Expression::NumberLiteral(value, ..) => { let not_nan = if let Ok(v) = f64::try_from(value.clone()) { - v.try_into().unwrap() + if let Ok(value) = v.try_into() { + value + } else { + crate::utilities::notify!("Returning zero here? {:?}", value); + return TypeId::ZERO; + } } else { crate::utilities::notify!("TODO big int"); return TypeId::UNIMPLEMENTED_ERROR_TYPE; }; - // if not_nan == 6. { - // crate::utilities::notify!("{:?}", environment.get_all_named_types()); - // } return checking_data.types.new_constant_type(Constant::Number(not_nan)); } Expression::BooleanLiteral(value, ..) => { diff --git a/checker/src/synthesis/hoisting.rs b/checker/src/synthesis/hoisting.rs index 12f4d047..fc06cca1 100644 --- a/checker/src/synthesis/hoisting.rs +++ b/checker/src/synthesis/hoisting.rs @@ -35,10 +35,6 @@ pub(crate) fn hoist_statements( for item in items { if let StatementOrDeclaration::Declaration(declaration) = item { match declaration { - Declaration::Enum(r#enum) => checking_data.raise_unimplemented_error( - "enum", - r#enum.on.position.with_source(environment.get_source()), - ), Declaration::Namespace(ns) => checking_data.raise_unimplemented_error( "namespace", ns.position.with_source(environment.get_source()), @@ -46,7 +42,7 @@ pub(crate) fn hoist_statements( Declaration::Interface(Decorated { on: interface, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::Interface(interface), position: _, }, @@ -103,7 +99,7 @@ pub(crate) fn hoist_statements( Declaration::Class(Decorated { on: class, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { exported: Exportable::Class(class), position: _ }, + ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, .. }) => { let result = environment.declare_class::( @@ -143,7 +139,7 @@ pub(crate) fn hoist_statements( Declaration::TypeAlias(alias) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::TypeAlias(alias), position: _, }, @@ -225,7 +221,7 @@ pub(crate) fn hoist_statements( } Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::ImportAll { r#as, from }, position, }, @@ -256,7 +252,7 @@ pub(crate) fn hoist_statements( } Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::ImportParts { parts, from, type_definitions_only, .. }, position, @@ -276,6 +272,47 @@ pub(crate) fn hoist_statements( *type_definitions_only, ); } + Declaration::Enum(Decorated { on: r#enum, .. }) | Declaration::Export(Decorated { + on: + ExportDeclaration::Item { + exported: Exportable::EnumDeclaration(r#enum), + position: _, + }, + .. + }) => { + if checking_data.options.extra_syntax { + checking_data.diagnostics_container.add_warning( + crate::diagnostics::TypeCheckWarning::ItemMustBeUsedWithFlag { + item: "enum", + position: r#enum.position.with_source(environment.get_source()), + }, + ); + } + + // TODO WIP implementation + let result = environment.declare_alias::( + &r#enum.name, + None, + r#enum.get_position(), + &mut checking_data.types, + ); + if let Ok(ty) = result { + checking_data + .local_type_mappings + .types_to_types + .push(r#enum.get_position(), ty); + + checking_data.types.update_alias(ty, TypeId::NUMBER_TYPE); + } else { + let position = r#enum.get_position().with_source(environment.get_source()); + checking_data.diagnostics_container.add_error( + crate::diagnostics::TypeCheckError::TypeAlreadyDeclared { + name: r#enum.name.clone(), + position, + }, + ); + } + } Declaration::DeclareVariable(_) | Declaration::Variable(_) | Declaration::Function(_) @@ -320,7 +357,7 @@ pub(crate) fn hoist_statements( Declaration::Variable(declaration) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::Variable(declaration), position: _, }, @@ -331,7 +368,7 @@ pub(crate) fn hoist_statements( Declaration::Class(Decorated { on: class, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { exported: Exportable::Class(class), position: _ }, + ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, .. }) => { let name_position = @@ -344,7 +381,7 @@ pub(crate) fn hoist_statements( .unwrap(); // Lift members - super::classes::register_statement_class_with_members( + let constructor = super::classes::register_statement_class_with_members( ty, class, environment, @@ -355,7 +392,7 @@ pub(crate) fn hoist_statements( let argument = VariableRegisterArguments { // TODO functions are constant references constant: true, - space: Some(ty), + space: Some(constructor), initial_value: None, allow_reregistration: false, }; @@ -384,7 +421,7 @@ pub(crate) fn hoist_statements( Declaration::TypeAlias(alias) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::TypeAlias(alias), position: _, }, @@ -407,7 +444,7 @@ pub(crate) fn hoist_statements( Declaration::Interface(Decorated { on: interface, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::Interface(interface), position: _, }, @@ -529,7 +566,7 @@ pub(crate) fn hoist_statements( Declaration::Function(Decorated { on: function, decorators, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::Function(function), position: _, }, @@ -663,11 +700,28 @@ pub(crate) fn hoist_statements( ); } } - // Declaration::Interface(Decorated { on: r#enum, .. }) - Declaration::Enum(r#enum) => { - checking_data.raise_unimplemented_error( - "enum", - r#enum.position.with_source(environment.get_source()), + Declaration::Enum(Decorated { on: r#enum, .. }) | Declaration::Export(Decorated { + on: + ExportDeclaration::Item { + exported: Exportable::EnumDeclaration(r#enum), + position: _, + }, + .. + }) => { + let argument = VariableRegisterArguments { + constant: true, + space: None, + initial_value: None, + allow_reregistration: false, + }; + + environment.register_variable_handle_error( + &r#enum.name, + argument, + r#enum.get_position().with_source(environment.get_source()), + &mut checking_data.diagnostics_container, + &mut checking_data.local_type_mappings, + checking_data.options.record_all_assignments_and_reads, ); } Declaration::DeclareVariable(DeclareVariableDeclaration { @@ -720,7 +774,7 @@ pub(crate) fn hoist_statements( Declaration::Function(Decorated { on: function, decorators, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Variable { + ExportDeclaration::Item { exported: Exportable::Function(function), position: _, }, diff --git a/checker/src/types/properties/mod.rs b/checker/src/types/properties/mod.rs index 18e34c69..dd608419 100644 --- a/checker/src/types/properties/mod.rs +++ b/checker/src/types/properties/mod.rs @@ -53,6 +53,12 @@ impl From<&'static str> for PropertyKey<'static> { } } +impl From for PropertyKey<'static> { + fn from(value: String) -> Self { + Self::String(Cow::Owned(value)) + } +} + // Cannot auto derive BinarySerializable because lifetime impl crate::BinarySerializable for PropertyKey<'static> { fn serialize(self, buf: &mut Vec) { diff --git a/parser/src/block.rs b/parser/src/block.rs index 590e0577..3070dde8 100644 --- a/parser/src/block.rs +++ b/parser/src/block.rs @@ -41,7 +41,7 @@ impl StatementOrDeclaration { Declaration::Variable(..) | Declaration::Export(Decorated { on: ExportDeclaration::Default { .. } - | ExportDeclaration::Variable { + | ExportDeclaration::Item { exported: Exportable::ImportAll { .. } | Exportable::ImportParts { .. } | Exportable::Parts { .. }, .. diff --git a/parser/src/declarations/export.rs b/parser/src/declarations/export.rs index bc3171c9..3809077f 100644 --- a/parser/src/declarations/export.rs +++ b/parser/src/declarations/export.rs @@ -2,12 +2,12 @@ use crate::{ derive_ASTNode, errors::parse_lexing_error, throw_unexpected_token, type_annotations::TypeAnnotationFunctionParameters, ASTNode, Expression, ParseError, ParseOptions, ParseResult, Span, StatementPosition, TSXKeyword, TSXToken, Token, - TypeAnnotation, VariableIdentifier, + TypeAnnotation, VariableIdentifier, types::enum_declaration::EnumDeclaration }; use super::{ variable::VariableDeclaration, ClassDeclaration, ImportExportPart, ImportLocation, - InterfaceDeclaration, StatementFunction, TypeAlias, + InterfaceDeclaration, StatementFunction, TypeAlias, }; use get_field_by_type::GetFieldByType; @@ -19,7 +19,7 @@ use visitable_derive::Visitable; #[derive(Debug, PartialEq, Clone, Visitable, get_field_by_type::GetFieldByType)] #[get_field_by_type_target(Span)] pub enum ExportDeclaration { - Variable { + Item { exported: Exportable, position: Span, }, @@ -47,6 +47,7 @@ pub enum Exportable { Variable(VariableDeclaration), Interface(InterfaceDeclaration), TypeAlias(TypeAlias), + EnumDeclaration(EnumDeclaration), Parts(Vec>), ImportAll { r#as: Option, @@ -137,7 +138,7 @@ impl ASTNode for ExportDeclaration { let (from, end) = ImportLocation::from_reader(reader, state, options, Some(start))?; - Ok(ExportDeclaration::Variable { + Ok(ExportDeclaration::Item { exported: Exportable::ImportAll { r#as, from }, position: start.union(end), }) @@ -148,13 +149,20 @@ impl ASTNode for ExportDeclaration { let class_declaration = ClassDeclaration::from_reader_sub_class_keyword(reader, state, options, start)?; let position = start.union(class_declaration.get_position()); - Ok(Self::Variable { exported: Exportable::Class(class_declaration), position }) + Ok(Self::Item { exported: Exportable::Class(class_declaration), position }) + } + Token(TSXToken::Keyword(TSXKeyword::Enum), _) => { + let Token(_, start) = reader.next().unwrap(); + let enum_declaration = + EnumDeclaration::from_reader(reader, state, options)?; + let position = start.union(enum_declaration.get_position()); + Ok(Self::Item { exported: Exportable::EnumDeclaration(enum_declaration), position }) } Token(TSXToken::Keyword(TSXKeyword::Const | TSXKeyword::Let), _) => { let variable_declaration = VariableDeclaration::from_reader(reader, state, options)?; let position = start.union(variable_declaration.get_position()); - Ok(Self::Variable { + Ok(Self::Item { exported: Exportable::Variable(variable_declaration), position, }) @@ -163,7 +171,7 @@ impl ASTNode for ExportDeclaration { let interface_declaration = InterfaceDeclaration::from_reader(reader, state, options)?; let position = start.union(interface_declaration.get_position()); - Ok(Self::Variable { + Ok(Self::Item { exported: Exportable::Interface(interface_declaration), position, }) @@ -188,7 +196,7 @@ impl ASTNode for ExportDeclaration { let (from, end) = ImportLocation::from_reader(reader, state, options, Some(from_pos))?; - Ok(Self::Variable { + Ok(Self::Item { exported: Exportable::ImportParts { parts, from, @@ -199,7 +207,7 @@ impl ASTNode for ExportDeclaration { } else { let type_alias = TypeAlias::from_reader(reader, state, options)?; let position = start.union(type_alias.get_position()); - Ok(Self::Variable { exported: Exportable::TypeAlias(type_alias), position }) + Ok(Self::Item { exported: Exportable::TypeAlias(type_alias), position }) } } Token(TSXToken::OpenBrace, _) => { @@ -230,7 +238,7 @@ impl ASTNode for ExportDeclaration { let (from, end) = ImportLocation::from_reader(reader, state, options, Some(start))?; - Ok(Self::Variable { + Ok(Self::Item { exported: Exportable::ImportParts { parts, from, @@ -246,7 +254,7 @@ impl ASTNode for ExportDeclaration { None, TSXToken::CloseBrace, )?; - Ok(Self::Variable { + Ok(Self::Item { exported: Exportable::Parts(parts), position: start.union(end), }) @@ -261,7 +269,7 @@ impl ASTNode for ExportDeclaration { Token(TSXToken::Keyword(kw), _) if kw.is_in_function_header() => { let function_declaration = StatementFunction::from_reader(reader, state, options)?; let position = start.union(function_declaration.get_position()); - Ok(Self::Variable { + Ok(Self::Item { exported: Exportable::Function(function_declaration), position, }) @@ -288,7 +296,7 @@ impl ASTNode for ExportDeclaration { local: crate::LocalToStringInformation, ) { match self { - ExportDeclaration::Variable { exported, .. } => { + ExportDeclaration::Item { exported, .. } => { buf.push_str("export "); match exported { Exportable::Class(class_declaration) => { @@ -306,6 +314,9 @@ impl ASTNode for ExportDeclaration { Exportable::TypeAlias(type_alias) => { type_alias.to_string_from_buffer(buf, options, local); } + Exportable::EnumDeclaration(enum_declaration) => { + enum_declaration.to_string_from_buffer(buf, options, local); + } Exportable::Parts(parts) => { super::import_export_parts_to_string_from_buffer( parts, buf, options, local, diff --git a/parser/src/expressions/mod.rs b/parser/src/expressions/mod.rs index 89f58fd3..de79368b 100644 --- a/parser/src/expressions/mod.rs +++ b/parser/src/expressions/mod.rs @@ -1074,7 +1074,7 @@ impl Expression { type_annotation: Box::new(reference), }, #[cfg(feature = "extras")] - TSXToken::Keyword(TSXKeyword::Is) => SpecialOperators::Is { + TSXToken::Keyword(TSXKeyword::Is) if options.is_expressions => SpecialOperators::Is { value: top.into(), type_annotation: Box::new(reference), }, @@ -1478,6 +1478,7 @@ impl Expression { #[cfg(feature = "extras")] SpecialOperators::Is { value, type_annotation, .. } => { value.to_string_from_buffer(buf, options, local); + buf.push_str(" is "); type_annotation.to_string_from_buffer(buf, options, local); } }, diff --git a/parser/src/options.rs b/parser/src/options.rs index 2b09a6e9..b3c4b712 100644 --- a/parser/src/options.rs +++ b/parser/src/options.rs @@ -50,7 +50,8 @@ impl ParseOptions { comments: self.comments, lex_jsx: self.jsx, allow_unsupported_characters_in_jsx_attribute_keys: self.special_jsx_attributes, - allow_expressions_in_jsx: !self.top_level_html, + allow_expressions_in_jsx: true, + // allow_expressions_in_jsx: !self.top_level_html, top_level_html: self.top_level_html, } } diff --git a/src/reporting.rs b/src/reporting.rs index 2747442b..3e97e332 100644 --- a/src/reporting.rs +++ b/src/reporting.rs @@ -123,11 +123,11 @@ where #[cfg(not(target_family = "wasm"))] emit(&mut writer, &config, &files, &diagnostic)?; } + + #[cfg(not(target_family = "wasm"))] + writer.flush().unwrap(); if count > maximum { - #[cfg(not(target_family = "wasm"))] - writer.flush().unwrap(); - crate::utilities::print_to_cli(format_args!( "... and {difference} other errors and warnings", difference = count - maximum From bdef19502f949a0a270d719f20a29f47827af462 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 29 Aug 2024 15:05:15 +0100 Subject: [PATCH 4/4] Formatting fixes --- checker/src/features/functions.rs | 7 +++++-- checker/src/synthesis/classes.rs | 12 +++++++----- checker/src/synthesis/hoisting.rs | 27 +++++++++------------------ parser/src/declarations/export.rs | 26 ++++++++------------------ src/reporting.rs | 2 +- 5 files changed, 30 insertions(+), 44 deletions(-) diff --git a/checker/src/features/functions.rs b/checker/src/features/functions.rs index 95dae547..849e5bf8 100644 --- a/checker/src/features/functions.rs +++ b/checker/src/features/functions.rs @@ -1137,7 +1137,10 @@ pub fn extract_name(expecting: TypeId, types: &TypeStore, environment: &Environm } } -pub fn class_generics_to_function_generics(prototype: TypeId, types: &TypeStore) -> Option { +pub fn class_generics_to_function_generics( + prototype: TypeId, + types: &TypeStore, +) -> Option { types.get_type_by_id(prototype).get_parameters().map(|parameters| { parameters .into_iter() @@ -1156,4 +1159,4 @@ pub fn class_generics_to_function_generics(prototype: TypeId, types: &TypeStore) }) .collect() }) -} \ No newline at end of file +} diff --git a/checker/src/synthesis/classes.rs b/checker/src/synthesis/classes.rs index 1d9047a5..294df65e 100644 --- a/checker/src/synthesis/classes.rs +++ b/checker/src/synthesis/classes.rs @@ -8,13 +8,14 @@ use crate::{ context::{Environment, InformationChain, LocalInformation}, diagnostics::TypeCheckError, features::functions::{ - function_to_property, synthesise_function, ClassPropertiesToRegister, - FunctionRegisterBehavior, GetterSetter, SynthesisableFunction, class_generics_to_function_generics, ReturnType + class_generics_to_function_generics, function_to_property, synthesise_function, + ClassPropertiesToRegister, FunctionRegisterBehavior, GetterSetter, ReturnType, + SynthesisableFunction, }, types::{ classes::ClassValue, properties::{PropertyKey, Publicity}, - FunctionType, PolyNature, SynthesisedParameters + FunctionType, PolyNature, SynthesisedParameters, }, CheckingData, FunctionId, PropertyValue, Scope, Type, TypeId, }; @@ -763,7 +764,8 @@ fn register_extends_and_member( if let Some(constructor) = found_constructor { constructor } else { - let return_type = ReturnType(class_type, class.position.with_source(environment.get_source())); + let return_type = + ReturnType(class_type, class.position.with_source(environment.get_source())); build_overloaded_function( FunctionId(environment.get_source(), class.position.start), crate::types::functions::FunctionBehavior::Constructor { @@ -782,7 +784,7 @@ fn register_extends_and_member( environment, &mut checking_data.types, &mut checking_data.diagnostics_container, - crate::types::functions::FunctionEffect::Unknown + crate::types::functions::FunctionEffect::Unknown, ) } } diff --git a/checker/src/synthesis/hoisting.rs b/checker/src/synthesis/hoisting.rs index fc06cca1..4f9a2ea3 100644 --- a/checker/src/synthesis/hoisting.rs +++ b/checker/src/synthesis/hoisting.rs @@ -98,8 +98,7 @@ pub(crate) fn hoist_statements( } Declaration::Class(Decorated { on: class, .. }) | Declaration::Export(Decorated { - on: - ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, + on: ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, .. }) => { let result = environment.declare_class::( @@ -139,10 +138,7 @@ pub(crate) fn hoist_statements( Declaration::TypeAlias(alias) | Declaration::Export(Decorated { on: - ExportDeclaration::Item { - exported: Exportable::TypeAlias(alias), - position: _, - }, + ExportDeclaration::Item { exported: Exportable::TypeAlias(alias), position: _ }, .. }) => { let result = environment.declare_alias::( @@ -272,7 +268,8 @@ pub(crate) fn hoist_statements( *type_definitions_only, ); } - Declaration::Enum(Decorated { on: r#enum, .. }) | Declaration::Export(Decorated { + Declaration::Enum(Decorated { on: r#enum, .. }) + | Declaration::Export(Decorated { on: ExportDeclaration::Item { exported: Exportable::EnumDeclaration(r#enum), @@ -367,8 +364,7 @@ pub(crate) fn hoist_statements( } Declaration::Class(Decorated { on: class, .. }) | Declaration::Export(Decorated { - on: - ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, + on: ExportDeclaration::Item { exported: Exportable::Class(class), position: _ }, .. }) => { let name_position = @@ -421,10 +417,7 @@ pub(crate) fn hoist_statements( Declaration::TypeAlias(alias) | Declaration::Export(Decorated { on: - ExportDeclaration::Item { - exported: Exportable::TypeAlias(alias), - position: _, - }, + ExportDeclaration::Item { exported: Exportable::TypeAlias(alias), position: _ }, .. }) => { let ty = checking_data @@ -700,7 +693,8 @@ pub(crate) fn hoist_statements( ); } } - Declaration::Enum(Decorated { on: r#enum, .. }) | Declaration::Export(Decorated { + Declaration::Enum(Decorated { on: r#enum, .. }) + | Declaration::Export(Decorated { on: ExportDeclaration::Item { exported: Exportable::EnumDeclaration(r#enum), @@ -774,10 +768,7 @@ pub(crate) fn hoist_statements( Declaration::Function(Decorated { on: function, decorators, .. }) | Declaration::Export(Decorated { on: - ExportDeclaration::Item { - exported: Exportable::Function(function), - position: _, - }, + ExportDeclaration::Item { exported: Exportable::Function(function), position: _ }, decorators, .. }), diff --git a/parser/src/declarations/export.rs b/parser/src/declarations/export.rs index 3809077f..0adbdd40 100644 --- a/parser/src/declarations/export.rs +++ b/parser/src/declarations/export.rs @@ -1,13 +1,13 @@ use crate::{ derive_ASTNode, errors::parse_lexing_error, throw_unexpected_token, - type_annotations::TypeAnnotationFunctionParameters, ASTNode, Expression, ParseError, - ParseOptions, ParseResult, Span, StatementPosition, TSXKeyword, TSXToken, Token, - TypeAnnotation, VariableIdentifier, types::enum_declaration::EnumDeclaration + type_annotations::TypeAnnotationFunctionParameters, types::enum_declaration::EnumDeclaration, + ASTNode, Expression, ParseError, ParseOptions, ParseResult, Span, StatementPosition, + TSXKeyword, TSXToken, Token, TypeAnnotation, VariableIdentifier, }; use super::{ variable::VariableDeclaration, ClassDeclaration, ImportExportPart, ImportLocation, - InterfaceDeclaration, StatementFunction, TypeAlias, + InterfaceDeclaration, StatementFunction, TypeAlias, }; use get_field_by_type::GetFieldByType; @@ -153,8 +153,7 @@ impl ASTNode for ExportDeclaration { } Token(TSXToken::Keyword(TSXKeyword::Enum), _) => { let Token(_, start) = reader.next().unwrap(); - let enum_declaration = - EnumDeclaration::from_reader(reader, state, options)?; + let enum_declaration = EnumDeclaration::from_reader(reader, state, options)?; let position = start.union(enum_declaration.get_position()); Ok(Self::Item { exported: Exportable::EnumDeclaration(enum_declaration), position }) } @@ -162,19 +161,13 @@ impl ASTNode for ExportDeclaration { let variable_declaration = VariableDeclaration::from_reader(reader, state, options)?; let position = start.union(variable_declaration.get_position()); - Ok(Self::Item { - exported: Exportable::Variable(variable_declaration), - position, - }) + Ok(Self::Item { exported: Exportable::Variable(variable_declaration), position }) } Token(TSXToken::Keyword(TSXKeyword::Interface), _) => { let interface_declaration = InterfaceDeclaration::from_reader(reader, state, options)?; let position = start.union(interface_declaration.get_position()); - Ok(Self::Item { - exported: Exportable::Interface(interface_declaration), - position, - }) + Ok(Self::Item { exported: Exportable::Interface(interface_declaration), position }) } Token(TSXToken::Keyword(TSXKeyword::Type), _) => { if let Token(TSXToken::OpenBrace, _) = @@ -269,10 +262,7 @@ impl ASTNode for ExportDeclaration { Token(TSXToken::Keyword(kw), _) if kw.is_in_function_header() => { let function_declaration = StatementFunction::from_reader(reader, state, options)?; let position = start.union(function_declaration.get_position()); - Ok(Self::Item { - exported: Exportable::Function(function_declaration), - position, - }) + Ok(Self::Item { exported: Exportable::Function(function_declaration), position }) } _ => throw_unexpected_token( reader, diff --git a/src/reporting.rs b/src/reporting.rs index 3e97e332..7a9ef81d 100644 --- a/src/reporting.rs +++ b/src/reporting.rs @@ -123,7 +123,7 @@ where #[cfg(not(target_family = "wasm"))] emit(&mut writer, &config, &files, &diagnostic)?; } - + #[cfg(not(target_family = "wasm"))] writer.flush().unwrap();