Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5369041

Browse files
authoredAug 29, 2024··
Class generics pass down to constructor (#200)
- Also adds type check support for it - Emoji fix in CLI - Add Exportable::Enum - Add temp enum implementation - Add fix to reporting - Class hoisting fix
1 parent e69e2c5 commit 5369041

File tree

19 files changed

+380
-149
lines changed

19 files changed

+380
-149
lines changed
 

‎.github/workflows/examples.yml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,25 @@ jobs:
3232

3333
- name: Run checker on example files
3434
shell: bash
35+
continue-on-error: true
3536
run: |
3637
files=(
37-
"https://jsr.io/@yossydev/hello-world/1.0.0/index.ts"
38-
"https://jsr.io/@bengineering/shuffle-binary/0.0.1/index.ts"
39-
"https://jsr.io/@bengineering/mulberry32/0.0.1/mod.ts"
40-
"https://jsr.io/@luca/cases/1.0.0/mod.ts"
41-
"https://jsr.io/@std/assert/1.0.2/assertion_error.ts"
42-
"https://jsr.io/@std/text/1.0.3/levenshtein_distance.ts"
43-
"https://jsr.io/@gnome/monads/0.0.0/src/option.ts"
44-
"https://raw.githubusercontent.com/getify/deePool/master/src/deePool.js"
45-
"https://raw.githubusercontent.com/silen-z/fiveway/main/packages/fiveway/src/id.ts"
38+
https://jsr.io/@yossydev/hello-world/1.0.0/index.ts
39+
https://jsr.io/@bengineering/shuffle-binary/0.0.1/index.ts
40+
https://jsr.io/@bengineering/mulberry32/0.0.1/mod.ts
41+
https://jsr.io/@luca/cases/1.0.0/mod.ts
42+
https://jsr.io/@std/assert/1.0.2/assertion_error.ts
43+
https://jsr.io/@std/text/1.0.3/levenshtein_distance.ts
44+
https://jsr.io/@gnome/monads/0.0.0/src/option.ts
45+
https://raw.githubusercontent.com/getify/deePool/master/src/deePool.js
46+
https://raw.githubusercontent.com/silen-z/fiveway/main/packages/fiveway/src/id.ts
4647
)
4748
4849
for url in "${files[@]}"; do
4950
header="--- $url ---"
5051
echo $header
5152
curl -s $url > temp.ts
52-
./target/release/ezno check temp.ts --timings
53+
./target/release/ezno check temp.ts --timings || true
5354
echo "${header//?/-}"
5455
echo ""
5556
done

‎checker/specification/specification.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3263,6 +3263,22 @@ doThingWithX(new Y())
32633263

32643264
- Argument of type [Y] { a: 2 } is not assignable to parameter of type X
32653265

3266+
#### Generics to constructor
3267+
3268+
```ts
3269+
class Box<T> {
3270+
value: T;
3271+
3272+
constructor(value: T) {
3273+
this.value = value;
3274+
}
3275+
}
3276+
3277+
const myBox = new Box<number>("hi");
3278+
```
3279+
3280+
- Argument of type "hi" is not assignable to parameter of type number
3281+
32663282
### Types
32673283

32683284
#### Non existent type
@@ -3696,7 +3712,7 @@ type GetPrefix<S, End> = S extends `${infer T} ${End}` ? T : false;
36963712

36973713
- Expected "Hello", found 4
36983714

3699-
#### `infer ... extends ...`
3715+
#### Infer with extends clause
37003716

37013717
```ts
37023718
type X<T> = T extends { a: infer I extends string } ? I : string;

‎checker/src/diagnostics.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -932,8 +932,8 @@ pub enum TypeCheckWarning {
932932
},
933933
IgnoringAsExpression(SpanWithSource),
934934
Unimplemented {
935-
thing: &'static str,
936-
at: SpanWithSource,
935+
item: &'static str,
936+
position: SpanWithSource,
937937
},
938938
UselessExpression {
939939
expression_span: SpanWithSource,
@@ -960,6 +960,10 @@ pub enum TypeCheckWarning {
960960
rhs: TypeStringRepresentation,
961961
position: SpanWithSource,
962962
},
963+
ItemMustBeUsedWithFlag {
964+
item: &'static str,
965+
position: SpanWithSource,
966+
},
963967
}
964968

965969
impl From<TypeCheckWarning> for Diagnostic {
@@ -993,9 +997,14 @@ impl From<TypeCheckWarning> for Diagnostic {
993997
position,
994998
kind,
995999
},
996-
TypeCheckWarning::Unimplemented { thing, at } => {
997-
Diagnostic::Position { reason: format!("Unsupported: {thing}"), position: at, kind }
1000+
TypeCheckWarning::Unimplemented { item, position } => {
1001+
Diagnostic::Position { reason: format!("Unsupported: {item}"), position, kind }
9981002
}
1003+
TypeCheckWarning::ItemMustBeUsedWithFlag { item, position } => Diagnostic::Position {
1004+
reason: format!("{item} must be used with 'extras' option"),
1005+
position,
1006+
kind,
1007+
},
9991008
TypeCheckWarning::UselessExpression { expression_span } => Diagnostic::Position {
10001009
reason: "Expression is always true".to_owned(),
10011010
position: expression_span,

‎checker/src/features/functions.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,12 @@ where
649649
let mut function_environment = base_environment.new_lexical_environment(Scope::Function(scope));
650650

651651
if function.has_body() {
652-
let type_parameters = function.type_parameters(&mut function_environment, checking_data);
652+
let type_parameters = if let Some((ref prototype, _)) = constructor {
653+
// Class generics here
654+
class_generics_to_function_generics(*prototype, &checking_data.types)
655+
} else {
656+
function.type_parameters(&mut function_environment, checking_data)
657+
};
653658

654659
// TODO should be in function, but then requires mutable environment :(
655660
let this_constraint =
@@ -1131,3 +1136,27 @@ pub fn extract_name(expecting: TypeId, types: &TypeStore, environment: &Environm
11311136
TypeId::EMPTY_STRING
11321137
}
11331138
}
1139+
1140+
pub fn class_generics_to_function_generics(
1141+
prototype: TypeId,
1142+
types: &TypeStore,
1143+
) -> Option<GenericTypeParameters> {
1144+
types.get_type_by_id(prototype).get_parameters().map(|parameters| {
1145+
parameters
1146+
.into_iter()
1147+
.map(|ty| {
1148+
let Type::RootPolyType(PolyNature::StructureGeneric { name, .. }) =
1149+
types.get_type_by_id(ty)
1150+
else {
1151+
unreachable!()
1152+
};
1153+
crate::types::generics::GenericTypeParameter {
1154+
name: name.clone(),
1155+
// Using its associated [`Type`], its restriction can be found
1156+
type_id: ty,
1157+
default: None,
1158+
}
1159+
})
1160+
.collect()
1161+
})
1162+
}

‎checker/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,10 @@ where
369369
}
370370

371371
/// TODO temp, needs better place
372-
pub fn raise_unimplemented_error(&mut self, item: &'static str, span: SpanWithSource) {
372+
pub fn raise_unimplemented_error(&mut self, item: &'static str, position: SpanWithSource) {
373373
if self.unimplemented_items.insert(item) {
374374
self.diagnostics_container
375-
.add_warning(TypeCheckWarning::Unimplemented { thing: item, at: span });
375+
.add_warning(TypeCheckWarning::Unimplemented { item, position });
376376
}
377377
}
378378

‎checker/src/synthesis/block.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use parser::{ASTNode, Statement, StatementOrDeclaration};
1+
use parser::{ASTNode, Declaration, Statement, StatementOrDeclaration};
22

33
use crate::{context::Environment, diagnostics::TypeCheckWarning, CheckingData};
44

@@ -43,7 +43,7 @@ pub(super) fn synthesise_block<T: crate::ReadFromFS>(
4343
e,
4444
StatementOrDeclaration::Statement(
4545
Statement::Comment(..) | Statement::MultiLineComment(..) | Statement::Empty(..)
46-
)
46+
) | StatementOrDeclaration::Declaration(Declaration::Function(..))
4747
)
4848
}) {
4949
checking_data.diagnostics_container.add_warning(TypeCheckWarning::Unreachable(

‎checker/src/synthesis/classes.rs

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ use crate::{
88
context::{Environment, InformationChain, LocalInformation},
99
diagnostics::TypeCheckError,
1010
features::functions::{
11-
function_to_property, synthesise_function, ClassPropertiesToRegister,
12-
FunctionRegisterBehavior, GetterSetter, SynthesisableFunction,
11+
class_generics_to_function_generics, function_to_property, synthesise_function,
12+
ClassPropertiesToRegister, FunctionRegisterBehavior, GetterSetter, ReturnType,
13+
SynthesisableFunction,
1314
},
1415
types::{
1516
classes::ClassValue,
1617
properties::{PropertyKey, Publicity},
17-
FunctionType, PolyNature,
18+
FunctionType, PolyNature, SynthesisedParameters,
1819
},
1920
CheckingData, FunctionId, PropertyValue, Scope, Type, TypeId,
2021
};
@@ -492,12 +493,13 @@ fn synthesise_class_declaration_extends_and_members<
492493
/// Also sets variable for hoisting
493494
///
494495
/// Builds the type of the class
496+
#[must_use]
495497
pub(super) fn register_statement_class_with_members<T: crate::ReadFromFS>(
496498
class_type: TypeId,
497499
class: &ClassDeclaration<StatementPosition>,
498500
environment: &mut Environment,
499501
checking_data: &mut CheckingData<T, super::EznoParser>,
500-
) {
502+
) -> TypeId {
501503
let class_type2 = checking_data.types.get_type_by_id(class_type);
502504

503505
let Type::Class { name: _, type_parameters } = class_type2 else {
@@ -516,15 +518,18 @@ pub(super) fn register_statement_class_with_members<T: crate::ReadFromFS>(
516518

517519
sub_environment.named_types.insert(name.clone(), *parameter);
518520
}
519-
register_extends_and_member(class, class_type, &mut sub_environment, checking_data);
521+
522+
let result =
523+
register_extends_and_member(class, class_type, &mut sub_environment, checking_data);
520524
{
521525
let crate::context::LocalInformation { current_properties, prototypes, .. } =
522526
sub_environment.info;
523527
environment.info.current_properties.extend(current_properties);
524528
environment.info.prototypes.extend(prototypes);
525529
}
530+
result
526531
} else {
527-
register_extends_and_member(class, class_type, environment, checking_data);
532+
register_extends_and_member(class, class_type, environment, checking_data)
528533
}
529534
}
530535

@@ -533,7 +538,7 @@ fn register_extends_and_member<T: crate::ReadFromFS>(
533538
class_type: TypeId,
534539
environment: &mut Environment,
535540
checking_data: &mut CheckingData<T, super::EznoParser>,
536-
) {
541+
) -> TypeId {
537542
if let Some(ref extends) = class.extends {
538543
let extends = get_extends_as_simple_type(extends, environment, checking_data);
539544

@@ -547,6 +552,9 @@ fn register_extends_and_member<T: crate::ReadFromFS>(
547552
// checking_data.local_type_mappings.types_to_types.push(class.position, class_type);
548553

549554
let mut members_iter = class.members.iter().peekable();
555+
556+
let mut found_constructor = None::<TypeId>;
557+
550558
while let Some(member) = members_iter.next() {
551559
match &member.on {
552560
ClassMember::Method(initial_is_static, method) => {
@@ -591,7 +599,7 @@ fn register_extends_and_member<T: crate::ReadFromFS>(
591599
.with_source(environment.get_source()),
592600
},
593601
);
594-
return;
602+
continue;
595603
}
596604
} else {
597605
let actual = synthesise_shape(method, environment, checking_data);
@@ -716,14 +724,69 @@ fn register_extends_and_member<T: crate::ReadFromFS>(
716724
value,
717725
);
718726
}
719-
ClassMember::Constructor(c) => {
720-
if !c.has_body() {
721-
crate::utilities::notify!("TODO possible constructor overloading");
722-
}
727+
ClassMember::Constructor(constructor) => {
728+
let internal_effect = get_internal_function_effect_from_decorators(
729+
&member.decorators,
730+
"",
731+
environment,
732+
);
733+
734+
let mut actual = synthesise_shape(constructor, environment, checking_data);
735+
actual.0 = class_generics_to_function_generics(class_type, &checking_data.types);
736+
737+
let constructor = build_overloaded_function(
738+
FunctionId(environment.get_source(), constructor.position.start),
739+
crate::types::functions::FunctionBehavior::Constructor {
740+
// The prototype of the base object
741+
prototype: class_type,
742+
// The id of the generic that needs to be pulled out
743+
this_object_type: TypeId::ERROR_TYPE,
744+
name: TypeId::ANY_TYPE,
745+
},
746+
Vec::new(),
747+
actual,
748+
environment,
749+
&mut checking_data.types,
750+
&mut checking_data.diagnostics_container,
751+
if let Some(ie) = internal_effect {
752+
ie.into()
753+
} else {
754+
crate::types::functions::FunctionEffect::Unknown
755+
},
756+
);
757+
758+
found_constructor = Some(constructor);
723759
}
724760
ClassMember::StaticBlock(_) | ClassMember::Comment(_, _, _) => {}
725761
}
726762
}
763+
764+
if let Some(constructor) = found_constructor {
765+
constructor
766+
} else {
767+
let return_type =
768+
ReturnType(class_type, class.position.with_source(environment.get_source()));
769+
build_overloaded_function(
770+
FunctionId(environment.get_source(), class.position.start),
771+
crate::types::functions::FunctionBehavior::Constructor {
772+
// The prototype of the base object
773+
prototype: class_type,
774+
// The id of the generic that needs to be pulled out
775+
this_object_type: TypeId::ERROR_TYPE,
776+
name: TypeId::ANY_TYPE,
777+
},
778+
Vec::new(),
779+
crate::features::functions::PartialFunction(
780+
class_generics_to_function_generics(class_type, &checking_data.types),
781+
SynthesisedParameters::default(),
782+
Some(return_type),
783+
),
784+
environment,
785+
&mut checking_data.types,
786+
&mut checking_data.diagnostics_container,
787+
crate::types::functions::FunctionEffect::Unknown,
788+
)
789+
}
727790
}
728791

729792
/// For hoisting using the class as a type annotation

‎checker/src/synthesis/declarations.rs

Lines changed: 87 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,48 +10,6 @@ use super::{
1010
variables::synthesise_variable_declaration_item,
1111
};
1212

13-
pub(super) fn synthesise_variable_declaration<T: crate::ReadFromFS>(
14-
declaration: &VariableDeclaration,
15-
environment: &mut Environment,
16-
checking_data: &mut CheckingData<T, super::EznoParser>,
17-
exported: bool,
18-
infer_constraint: bool,
19-
) {
20-
match declaration {
21-
VariableDeclaration::ConstDeclaration { declarations, .. } => {
22-
for variable_declaration in declarations {
23-
synthesise_variable_declaration_item(
24-
variable_declaration,
25-
environment,
26-
checking_data,
27-
exported.then_some(VariableMutability::Constant),
28-
infer_constraint,
29-
);
30-
}
31-
}
32-
VariableDeclaration::LetDeclaration { declarations, .. } => {
33-
for variable_declaration in declarations {
34-
let exported = exported.then(|| {
35-
let restriction = checking_data
36-
.local_type_mappings
37-
.variable_restrictions
38-
.get(&(environment.get_source(), variable_declaration.position.start))
39-
.map(|(first, _)| *first);
40-
VariableMutability::Mutable { reassignment_constraint: restriction }
41-
});
42-
43-
synthesise_variable_declaration_item(
44-
variable_declaration,
45-
environment,
46-
checking_data,
47-
exported,
48-
infer_constraint,
49-
);
50-
}
51-
}
52-
}
53-
}
54-
5513
pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
5614
declaration: &Declaration,
5715
environment: &mut Environment,
@@ -84,7 +42,7 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
8442
}
8543
}
8644
Declaration::Export(exported) => match &exported.on {
87-
parser::declarations::ExportDeclaration::Variable { exported, position: _ } => {
45+
parser::declarations::ExportDeclaration::Item { exported, position: _ } => {
8846
match exported {
8947
// Skipped as this is done earlier
9048
parser::declarations::export::Exportable::Class(class) => {
@@ -93,6 +51,7 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
9351
.types_to_types
9452
.get_exact(class.name.identifier.get_position())
9553
.copied();
54+
9655
// TODO mark as exported
9756
let _ = synthesise_class_declaration(
9857
class,
@@ -137,6 +96,7 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
13796
parser::declarations::export::Exportable::ImportAll { .. }
13897
| parser::declarations::export::Exportable::ImportParts { .. }
13998
| parser::declarations::export::Exportable::Function(_)
99+
| parser::declarations::export::Exportable::EnumDeclaration(_)
140100
| parser::declarations::export::Exportable::Interface(_)
141101
| parser::declarations::export::Exportable::TypeAlias(_) => {}
142102
}
@@ -172,12 +132,95 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
172132
);
173133
}
174134
},
135+
Declaration::Enum(r#enum) => {
136+
use crate::types::{
137+
properties::{PropertyKey, PropertyValue, Publicity},
138+
Constant,
139+
};
140+
141+
let mut basis = crate::features::objects::ObjectBuilder::new(
142+
None,
143+
&mut checking_data.types,
144+
r#enum.get_position().with_source(environment.get_source()),
145+
&mut environment.info,
146+
);
147+
148+
// TODO remove enumerate, add add function and more
149+
for (idx, member) in r#enum.on.members.iter().enumerate() {
150+
match member {
151+
parser::ast::EnumMember::Variant { name, value, position } => {
152+
if let Some(ref _value) = value {
153+
checking_data.raise_unimplemented_error(
154+
"enum with value",
155+
position.with_source(environment.get_source()),
156+
);
157+
}
158+
159+
let value = checking_data
160+
.types
161+
.new_constant_type(Constant::Number((idx as u8).into()));
162+
163+
basis.append(
164+
Publicity::Public,
165+
PropertyKey::from(name.clone()),
166+
PropertyValue::Value(value),
167+
member.get_position().with_source(environment.get_source()),
168+
&mut environment.info,
169+
);
170+
}
171+
}
172+
}
173+
174+
let variable = crate::VariableId(environment.get_source(), r#enum.get_position().start);
175+
environment.info.variable_current_value.insert(variable, basis.build_object());
176+
}
175177
Declaration::DeclareVariable(_)
176178
| Declaration::Function(_)
177-
| Declaration::Enum(_)
178179
| Declaration::Interface(_)
179180
| Declaration::TypeAlias(_)
180181
| Declaration::Namespace(_)
181182
| Declaration::Import(_) => {}
182183
}
183184
}
185+
186+
pub(super) fn synthesise_variable_declaration<T: crate::ReadFromFS>(
187+
declaration: &VariableDeclaration,
188+
environment: &mut Environment,
189+
checking_data: &mut CheckingData<T, super::EznoParser>,
190+
exported: bool,
191+
infer_constraint: bool,
192+
) {
193+
match declaration {
194+
VariableDeclaration::ConstDeclaration { declarations, .. } => {
195+
for variable_declaration in declarations {
196+
synthesise_variable_declaration_item(
197+
variable_declaration,
198+
environment,
199+
checking_data,
200+
exported.then_some(VariableMutability::Constant),
201+
infer_constraint,
202+
);
203+
}
204+
}
205+
VariableDeclaration::LetDeclaration { declarations, .. } => {
206+
for variable_declaration in declarations {
207+
let exported = exported.then(|| {
208+
let restriction = checking_data
209+
.local_type_mappings
210+
.variable_restrictions
211+
.get(&(environment.get_source(), variable_declaration.position.start))
212+
.map(|(first, _)| *first);
213+
VariableMutability::Mutable { reassignment_constraint: restriction }
214+
});
215+
216+
synthesise_variable_declaration_item(
217+
variable_declaration,
218+
environment,
219+
checking_data,
220+
exported,
221+
infer_constraint,
222+
);
223+
}
224+
}
225+
}
226+
}

‎checker/src/synthesis/definitions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub(super) fn type_definition_file<T: crate::ReadFromFS>(
2727
if let StatementOrDeclaration::Declaration(
2828
Declaration::Class(Decorated { on: class, .. })
2929
| Declaration::Export(Decorated {
30-
on: ExportDeclaration::Variable { exported: Exportable::Class(class), position: _ },
30+
on: ExportDeclaration::Item { exported: Exportable::Class(class), position: _ },
3131
..
3232
}),
3333
) = item

‎checker/src/synthesis/expressions.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,16 @@ pub(super) fn synthesise_expression<T: crate::ReadFromFS>(
114114
}
115115
Expression::NumberLiteral(value, ..) => {
116116
let not_nan = if let Ok(v) = f64::try_from(value.clone()) {
117-
v.try_into().unwrap()
117+
if let Ok(value) = v.try_into() {
118+
value
119+
} else {
120+
crate::utilities::notify!("Returning zero here? {:?}", value);
121+
return TypeId::ZERO;
122+
}
118123
} else {
119124
crate::utilities::notify!("TODO big int");
120125
return TypeId::UNIMPLEMENTED_ERROR_TYPE;
121126
};
122-
// if not_nan == 6. {
123-
// crate::utilities::notify!("{:?}", environment.get_all_named_types());
124-
// }
125127
return checking_data.types.new_constant_type(Constant::Number(not_nan));
126128
}
127129
Expression::BooleanLiteral(value, ..) => {

‎checker/src/synthesis/hoisting.rs

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,14 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
3535
for item in items {
3636
if let StatementOrDeclaration::Declaration(declaration) = item {
3737
match declaration {
38-
Declaration::Enum(r#enum) => checking_data.raise_unimplemented_error(
39-
"enum",
40-
r#enum.on.position.with_source(environment.get_source()),
41-
),
4238
Declaration::Namespace(ns) => checking_data.raise_unimplemented_error(
4339
"namespace",
4440
ns.position.with_source(environment.get_source()),
4541
),
4642
Declaration::Interface(Decorated { on: interface, .. })
4743
| Declaration::Export(Decorated {
4844
on:
49-
ExportDeclaration::Variable {
45+
ExportDeclaration::Item {
5046
exported: Exportable::Interface(interface),
5147
position: _,
5248
},
@@ -102,8 +98,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
10298
}
10399
Declaration::Class(Decorated { on: class, .. })
104100
| Declaration::Export(Decorated {
105-
on:
106-
ExportDeclaration::Variable { exported: Exportable::Class(class), position: _ },
101+
on: ExportDeclaration::Item { exported: Exportable::Class(class), position: _ },
107102
..
108103
}) => {
109104
let result = environment.declare_class::<EznoParser>(
@@ -143,10 +138,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
143138
Declaration::TypeAlias(alias)
144139
| Declaration::Export(Decorated {
145140
on:
146-
ExportDeclaration::Variable {
147-
exported: Exportable::TypeAlias(alias),
148-
position: _,
149-
},
141+
ExportDeclaration::Item { exported: Exportable::TypeAlias(alias), position: _ },
150142
..
151143
}) => {
152144
let result = environment.declare_alias::<EznoParser>(
@@ -225,7 +217,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
225217
}
226218
Declaration::Export(Decorated {
227219
on:
228-
ExportDeclaration::Variable {
220+
ExportDeclaration::Item {
229221
exported: Exportable::ImportAll { r#as, from },
230222
position,
231223
},
@@ -256,7 +248,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
256248
}
257249
Declaration::Export(Decorated {
258250
on:
259-
ExportDeclaration::Variable {
251+
ExportDeclaration::Item {
260252
exported:
261253
Exportable::ImportParts { parts, from, type_definitions_only, .. },
262254
position,
@@ -276,6 +268,48 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
276268
*type_definitions_only,
277269
);
278270
}
271+
Declaration::Enum(Decorated { on: r#enum, .. })
272+
| Declaration::Export(Decorated {
273+
on:
274+
ExportDeclaration::Item {
275+
exported: Exportable::EnumDeclaration(r#enum),
276+
position: _,
277+
},
278+
..
279+
}) => {
280+
if checking_data.options.extra_syntax {
281+
checking_data.diagnostics_container.add_warning(
282+
crate::diagnostics::TypeCheckWarning::ItemMustBeUsedWithFlag {
283+
item: "enum",
284+
position: r#enum.position.with_source(environment.get_source()),
285+
},
286+
);
287+
}
288+
289+
// TODO WIP implementation
290+
let result = environment.declare_alias::<EznoParser>(
291+
&r#enum.name,
292+
None,
293+
r#enum.get_position(),
294+
&mut checking_data.types,
295+
);
296+
if let Ok(ty) = result {
297+
checking_data
298+
.local_type_mappings
299+
.types_to_types
300+
.push(r#enum.get_position(), ty);
301+
302+
checking_data.types.update_alias(ty, TypeId::NUMBER_TYPE);
303+
} else {
304+
let position = r#enum.get_position().with_source(environment.get_source());
305+
checking_data.diagnostics_container.add_error(
306+
crate::diagnostics::TypeCheckError::TypeAlreadyDeclared {
307+
name: r#enum.name.clone(),
308+
position,
309+
},
310+
);
311+
}
312+
}
279313
Declaration::DeclareVariable(_)
280314
| Declaration::Variable(_)
281315
| Declaration::Function(_)
@@ -320,7 +354,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
320354
Declaration::Variable(declaration)
321355
| Declaration::Export(Decorated {
322356
on:
323-
ExportDeclaration::Variable {
357+
ExportDeclaration::Item {
324358
exported: Exportable::Variable(declaration),
325359
position: _,
326360
},
@@ -330,8 +364,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
330364
}
331365
Declaration::Class(Decorated { on: class, .. })
332366
| Declaration::Export(Decorated {
333-
on:
334-
ExportDeclaration::Variable { exported: Exportable::Class(class), position: _ },
367+
on: ExportDeclaration::Item { exported: Exportable::Class(class), position: _ },
335368
..
336369
}) => {
337370
let name_position =
@@ -344,7 +377,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
344377
.unwrap();
345378

346379
// Lift members
347-
super::classes::register_statement_class_with_members(
380+
let constructor = super::classes::register_statement_class_with_members(
348381
ty,
349382
class,
350383
environment,
@@ -355,7 +388,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
355388
let argument = VariableRegisterArguments {
356389
// TODO functions are constant references
357390
constant: true,
358-
space: Some(ty),
391+
space: Some(constructor),
359392
initial_value: None,
360393
allow_reregistration: false,
361394
};
@@ -384,10 +417,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
384417
Declaration::TypeAlias(alias)
385418
| Declaration::Export(Decorated {
386419
on:
387-
ExportDeclaration::Variable {
388-
exported: Exportable::TypeAlias(alias),
389-
position: _,
390-
},
420+
ExportDeclaration::Item { exported: Exportable::TypeAlias(alias), position: _ },
391421
..
392422
}) => {
393423
let ty = checking_data
@@ -407,7 +437,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
407437
Declaration::Interface(Decorated { on: interface, .. })
408438
| Declaration::Export(Decorated {
409439
on:
410-
ExportDeclaration::Variable {
440+
ExportDeclaration::Item {
411441
exported: Exportable::Interface(interface),
412442
position: _,
413443
},
@@ -529,7 +559,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
529559
Declaration::Function(Decorated { on: function, decorators, .. })
530560
| Declaration::Export(Decorated {
531561
on:
532-
ExportDeclaration::Variable {
562+
ExportDeclaration::Item {
533563
exported: Exportable::Function(function),
534564
position: _,
535565
},
@@ -663,11 +693,29 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
663693
);
664694
}
665695
}
666-
// Declaration::Interface(Decorated { on: r#enum, .. })
667-
Declaration::Enum(r#enum) => {
668-
checking_data.raise_unimplemented_error(
669-
"enum",
670-
r#enum.position.with_source(environment.get_source()),
696+
Declaration::Enum(Decorated { on: r#enum, .. })
697+
| Declaration::Export(Decorated {
698+
on:
699+
ExportDeclaration::Item {
700+
exported: Exportable::EnumDeclaration(r#enum),
701+
position: _,
702+
},
703+
..
704+
}) => {
705+
let argument = VariableRegisterArguments {
706+
constant: true,
707+
space: None,
708+
initial_value: None,
709+
allow_reregistration: false,
710+
};
711+
712+
environment.register_variable_handle_error(
713+
&r#enum.name,
714+
argument,
715+
r#enum.get_position().with_source(environment.get_source()),
716+
&mut checking_data.diagnostics_container,
717+
&mut checking_data.local_type_mappings,
718+
checking_data.options.record_all_assignments_and_reads,
671719
);
672720
}
673721
Declaration::DeclareVariable(DeclareVariableDeclaration {
@@ -720,10 +768,7 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
720768
Declaration::Function(Decorated { on: function, decorators, .. })
721769
| Declaration::Export(Decorated {
722770
on:
723-
ExportDeclaration::Variable {
724-
exported: Exportable::Function(function),
725-
position: _,
726-
},
771+
ExportDeclaration::Item { exported: Exportable::Function(function), position: _ },
727772
decorators,
728773
..
729774
}),

‎checker/src/types/calling.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,8 +1859,11 @@ fn synthesise_argument_expressions_wrt_parameters<T: ReadFromFS, A: crate::ASTIm
18591859
.iter()
18601860
.zip(call_site_type_arguments)
18611861
.map(|(param, (ty, position))| {
1862-
if let Type::RootPolyType(PolyNature::FunctionGeneric { extends, .. }) =
1863-
types.get_type_by_id(param.type_id)
1862+
// StructureGeneric for classes
1863+
if let Type::RootPolyType(
1864+
PolyNature::FunctionGeneric { extends, .. }
1865+
| PolyNature::StructureGeneric { extends, .. },
1866+
) = types.get_type_by_id(param.type_id)
18641867
{
18651868
let mut state = State {
18661869
already_checked: Default::default(),

‎checker/src/types/properties/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ impl From<&'static str> for PropertyKey<'static> {
5353
}
5454
}
5555

56+
impl From<String> for PropertyKey<'static> {
57+
fn from(value: String) -> Self {
58+
Self::String(Cow::Owned(value))
59+
}
60+
}
61+
5662
// Cannot auto derive BinarySerializable because lifetime
5763
impl crate::BinarySerializable for PropertyKey<'static> {
5864
fn serialize(self, buf: &mut Vec<u8>) {

‎parser/src/block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl StatementOrDeclaration {
4141
Declaration::Variable(..)
4242
| Declaration::Export(Decorated {
4343
on: ExportDeclaration::Default { .. }
44-
| ExportDeclaration::Variable {
44+
| ExportDeclaration::Item {
4545
exported: Exportable::ImportAll { .. }
4646
| Exportable::ImportParts { .. } | Exportable::Parts { .. },
4747
..

‎parser/src/declarations/export.rs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{
22
derive_ASTNode, errors::parse_lexing_error, throw_unexpected_token,
3-
type_annotations::TypeAnnotationFunctionParameters, ASTNode, Expression, ParseError,
4-
ParseOptions, ParseResult, Span, StatementPosition, TSXKeyword, TSXToken, Token,
5-
TypeAnnotation, VariableIdentifier,
3+
type_annotations::TypeAnnotationFunctionParameters, types::enum_declaration::EnumDeclaration,
4+
ASTNode, Expression, ParseError, ParseOptions, ParseResult, Span, StatementPosition,
5+
TSXKeyword, TSXToken, Token, TypeAnnotation, VariableIdentifier,
66
};
77

88
use super::{
@@ -19,7 +19,7 @@ use visitable_derive::Visitable;
1919
#[derive(Debug, PartialEq, Clone, Visitable, get_field_by_type::GetFieldByType)]
2020
#[get_field_by_type_target(Span)]
2121
pub enum ExportDeclaration {
22-
Variable {
22+
Item {
2323
exported: Exportable,
2424
position: Span,
2525
},
@@ -47,6 +47,7 @@ pub enum Exportable {
4747
Variable(VariableDeclaration),
4848
Interface(InterfaceDeclaration),
4949
TypeAlias(TypeAlias),
50+
EnumDeclaration(EnumDeclaration),
5051
Parts(Vec<ImportExportPart<ExportDeclaration>>),
5152
ImportAll {
5253
r#as: Option<VariableIdentifier>,
@@ -137,7 +138,7 @@ impl ASTNode for ExportDeclaration {
137138

138139
let (from, end) = ImportLocation::from_reader(reader, state, options, Some(start))?;
139140

140-
Ok(ExportDeclaration::Variable {
141+
Ok(ExportDeclaration::Item {
141142
exported: Exportable::ImportAll { r#as, from },
142143
position: start.union(end),
143144
})
@@ -148,25 +149,25 @@ impl ASTNode for ExportDeclaration {
148149
let class_declaration =
149150
ClassDeclaration::from_reader_sub_class_keyword(reader, state, options, start)?;
150151
let position = start.union(class_declaration.get_position());
151-
Ok(Self::Variable { exported: Exportable::Class(class_declaration), position })
152+
Ok(Self::Item { exported: Exportable::Class(class_declaration), position })
153+
}
154+
Token(TSXToken::Keyword(TSXKeyword::Enum), _) => {
155+
let Token(_, start) = reader.next().unwrap();
156+
let enum_declaration = EnumDeclaration::from_reader(reader, state, options)?;
157+
let position = start.union(enum_declaration.get_position());
158+
Ok(Self::Item { exported: Exportable::EnumDeclaration(enum_declaration), position })
152159
}
153160
Token(TSXToken::Keyword(TSXKeyword::Const | TSXKeyword::Let), _) => {
154161
let variable_declaration =
155162
VariableDeclaration::from_reader(reader, state, options)?;
156163
let position = start.union(variable_declaration.get_position());
157-
Ok(Self::Variable {
158-
exported: Exportable::Variable(variable_declaration),
159-
position,
160-
})
164+
Ok(Self::Item { exported: Exportable::Variable(variable_declaration), position })
161165
}
162166
Token(TSXToken::Keyword(TSXKeyword::Interface), _) => {
163167
let interface_declaration =
164168
InterfaceDeclaration::from_reader(reader, state, options)?;
165169
let position = start.union(interface_declaration.get_position());
166-
Ok(Self::Variable {
167-
exported: Exportable::Interface(interface_declaration),
168-
position,
169-
})
170+
Ok(Self::Item { exported: Exportable::Interface(interface_declaration), position })
170171
}
171172
Token(TSXToken::Keyword(TSXKeyword::Type), _) => {
172173
if let Token(TSXToken::OpenBrace, _) =
@@ -188,7 +189,7 @@ impl ASTNode for ExportDeclaration {
188189
let (from, end) =
189190
ImportLocation::from_reader(reader, state, options, Some(from_pos))?;
190191

191-
Ok(Self::Variable {
192+
Ok(Self::Item {
192193
exported: Exportable::ImportParts {
193194
parts,
194195
from,
@@ -199,7 +200,7 @@ impl ASTNode for ExportDeclaration {
199200
} else {
200201
let type_alias = TypeAlias::from_reader(reader, state, options)?;
201202
let position = start.union(type_alias.get_position());
202-
Ok(Self::Variable { exported: Exportable::TypeAlias(type_alias), position })
203+
Ok(Self::Item { exported: Exportable::TypeAlias(type_alias), position })
203204
}
204205
}
205206
Token(TSXToken::OpenBrace, _) => {
@@ -230,7 +231,7 @@ impl ASTNode for ExportDeclaration {
230231

231232
let (from, end) =
232233
ImportLocation::from_reader(reader, state, options, Some(start))?;
233-
Ok(Self::Variable {
234+
Ok(Self::Item {
234235
exported: Exportable::ImportParts {
235236
parts,
236237
from,
@@ -246,7 +247,7 @@ impl ASTNode for ExportDeclaration {
246247
None,
247248
TSXToken::CloseBrace,
248249
)?;
249-
Ok(Self::Variable {
250+
Ok(Self::Item {
250251
exported: Exportable::Parts(parts),
251252
position: start.union(end),
252253
})
@@ -261,10 +262,7 @@ impl ASTNode for ExportDeclaration {
261262
Token(TSXToken::Keyword(kw), _) if kw.is_in_function_header() => {
262263
let function_declaration = StatementFunction::from_reader(reader, state, options)?;
263264
let position = start.union(function_declaration.get_position());
264-
Ok(Self::Variable {
265-
exported: Exportable::Function(function_declaration),
266-
position,
267-
})
265+
Ok(Self::Item { exported: Exportable::Function(function_declaration), position })
268266
}
269267
_ => throw_unexpected_token(
270268
reader,
@@ -288,7 +286,7 @@ impl ASTNode for ExportDeclaration {
288286
local: crate::LocalToStringInformation,
289287
) {
290288
match self {
291-
ExportDeclaration::Variable { exported, .. } => {
289+
ExportDeclaration::Item { exported, .. } => {
292290
buf.push_str("export ");
293291
match exported {
294292
Exportable::Class(class_declaration) => {
@@ -306,6 +304,9 @@ impl ASTNode for ExportDeclaration {
306304
Exportable::TypeAlias(type_alias) => {
307305
type_alias.to_string_from_buffer(buf, options, local);
308306
}
307+
Exportable::EnumDeclaration(enum_declaration) => {
308+
enum_declaration.to_string_from_buffer(buf, options, local);
309+
}
309310
Exportable::Parts(parts) => {
310311
super::import_export_parts_to_string_from_buffer(
311312
parts, buf, options, local,

‎parser/src/expressions/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ impl Expression {
10741074
type_annotation: Box::new(reference),
10751075
},
10761076
#[cfg(feature = "extras")]
1077-
TSXToken::Keyword(TSXKeyword::Is) => SpecialOperators::Is {
1077+
TSXToken::Keyword(TSXKeyword::Is) if options.is_expressions => SpecialOperators::Is {
10781078
value: top.into(),
10791079
type_annotation: Box::new(reference),
10801080
},
@@ -1141,6 +1141,11 @@ impl Expression {
11411141
// a mutable reader here
11421142
let token = if let TSXToken::OpenChevron = token {
11431143
if is_generic_arguments(reader) {
1144+
if AssociativityDirection::LeftToRight
1145+
.should_return(parent_precedence, FUNCTION_CALL_PRECEDENCE)
1146+
{
1147+
return Ok(top);
1148+
}
11441149
let _ = reader.next();
11451150
let (type_arguments, _) = generic_arguments_from_reader_sub_open_angle(
11461151
reader, state, options, None,
@@ -1473,6 +1478,7 @@ impl Expression {
14731478
#[cfg(feature = "extras")]
14741479
SpecialOperators::Is { value, type_annotation, .. } => {
14751480
value.to_string_from_buffer(buf, options, local);
1481+
buf.push_str(" is ");
14761482
type_annotation.to_string_from_buffer(buf, options, local);
14771483
}
14781484
},

‎parser/src/options.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ impl ParseOptions {
5050
comments: self.comments,
5151
lex_jsx: self.jsx,
5252
allow_unsupported_characters_in_jsx_attribute_keys: self.special_jsx_attributes,
53-
allow_expressions_in_jsx: !self.top_level_html,
53+
allow_expressions_in_jsx: true,
54+
// allow_expressions_in_jsx: !self.top_level_html,
5455
top_level_html: self.top_level_html,
5556
}
5657
}

‎src/cli.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,10 @@ pub fn run_cli<T: crate::ReadFromFS, U: crate::WriteToFS, V: crate::CLIInputReso
224224
let result = if diagnostics.has_error() {
225225
if let MaxDiagnostics::FixedTo(0) = max_diagnostics {
226226
let count = diagnostics.into_iter().count();
227-
print_to_cli(format_args!("Found {count} type errors and warnings 😬"))
227+
print_to_cli(format_args!(
228+
"Found {count} type errors and warnings {}",
229+
console::Emoji(" 😬", ":/")
230+
))
228231
} else {
229232
report_diagnostics_to_cli(
230233
diagnostics,
@@ -244,7 +247,7 @@ pub fn run_cli<T: crate::ReadFromFS, U: crate::WriteToFS, V: crate::CLIInputReso
244247
max_diagnostics,
245248
)
246249
.unwrap();
247-
print_to_cli(format_args!("No type errors found 🎉"));
250+
print_to_cli(format_args!("No type errors found {}", console::Emoji("🎉", ":)")));
248251
ExitCode::SUCCESS
249252
};
250253

@@ -320,7 +323,10 @@ pub fn run_cli<T: crate::ReadFromFS, U: crate::WriteToFS, V: crate::CLIInputReso
320323
build_config.max_diagnostics,
321324
)
322325
.unwrap();
323-
print_to_cli(format_args!("Project built successfully 🎉"));
326+
print_to_cli(format_args!(
327+
"Project built successfully {}",
328+
console::Emoji("🎉", ":)")
329+
));
324330
ExitCode::SUCCESS
325331
}
326332
Err(FailedBuildOutput { fs, diagnostics }) => {
@@ -374,7 +380,7 @@ pub fn run_cli<T: crate::ReadFromFS, U: crate::WriteToFS, V: crate::CLIInputReso
374380
}
375381
} else {
376382
let _ = fs::write(path.clone(), output);
377-
print_to_cli(format_args!("Formatted {} 🎉", path.display()));
383+
print_to_cli(format_args!("Formatted {}", path.display()));
378384
ExitCode::SUCCESS
379385
}
380386
}

‎src/reporting.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ where
124124
emit(&mut writer, &config, &files, &diagnostic)?;
125125
}
126126

127-
if count > maximum {
128-
#[cfg(not(target_family = "wasm"))]
129-
writer.flush().unwrap();
127+
#[cfg(not(target_family = "wasm"))]
128+
writer.flush().unwrap();
130129

130+
if count > maximum {
131131
crate::utilities::print_to_cli(format_args!(
132132
"... and {difference} other errors and warnings",
133133
difference = count - maximum

0 commit comments

Comments
 (0)
Please sign in to comment.