Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement more assignment rules #1030

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions crates/stc_ts_file_analyzer/src/analyzer/assign/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use fxhash::FxHashMap;
use itertools::Itertools;
use stc_ts_ast_rnode::{RBindingIdent, RIdent, RNumber, RPat, RTsLit};
use stc_ts_errors::{
debug::{dump_type_map, force_dump_type_as_string},
debug::{dump_type_map, force_dump_type_as_string, print_backtrace},
DebugExt, ErrorKind,
};
use stc_ts_types::{Constructor, FnParam, Function, IdCtx, Key, KeywordType, LitType, Type, TypeElement, TypeParamDecl};
Expand Down Expand Up @@ -382,10 +382,13 @@ impl Analyzer<'_, '_> {
r_params,
AssignOpts {
is_params_of_method_definition: false,
disallow_rest_pat_in_left: true,
..opts
},
)
.context("tried to assign parameters of a function to parameters of another function")?;

dbg!(&l_params, &r_params);
}

if let Some(l_ret_ty) = l_ret_ty {
Expand Down Expand Up @@ -834,6 +837,12 @@ impl Analyzer<'_, '_> {
let _tracing = dev_span!("assign_params");

let span = opts.span;
let disallow_rest_in_lhs = opts.disallow_rest_pat_in_left;

let opts = AssignOpts {
disallow_rest_pat_in_left: false,
..opts
};

let mut li = l.iter().filter(|p| {
!matches!(
Expand All @@ -854,6 +863,9 @@ impl Analyzer<'_, '_> {
)
});

let l_count = li.clone().count();
let r_count = ri.clone().count();

let l_has_rest = l.iter().any(|p| matches!(p.pat, RPat::Rest(..)));

// TODO(kdy1): Consider optional parameters.
Expand Down Expand Up @@ -917,29 +929,40 @@ impl Analyzer<'_, '_> {
..opts
},
) {
dbg!();
continue;
}
}

// A rest pattern is always the last
match (&l.pat, &r.pat) {
(RPat::Rest(..), RPat::Rest(..)) => {
dbg!();
self.assign_param(data, l, r, opts)
.with_context(|| "tried to assign a rest parameter to another rest parameter".to_string())?;
break;
}

(RPat::Rest(..), _) => {
// TODO(kdy1): Implement correct logic
if disallow_rest_in_lhs {
dbg!();
print_backtrace();
// TODO(kdy1): Implement correct logic
return Err(ErrorKind::SimpleAssignFailed { span, cause: None }.context("l is rest but r is not"));
}

return Ok(());
}

(_, RPat::Rest(..)) => {
dbg!();
// If r is an iterator, we should assign each element to l.
if let Ok(r_iter) = self.get_iterator(span, Cow::Borrowed(&r.ty), Default::default()) {
dbg!();
if let Ok(l_iter) = self.get_iterator(span, Cow::Borrowed(&l.ty), Default::default()) {
for idx in 0..max(li.clone().count(), ri.clone().count()) {
dbg!();
for idx in 0..max(l_count, r_count) {
dbg!();
let le = self.access_property(
span,
&l_iter,
Expand Down Expand Up @@ -979,30 +1002,34 @@ impl Analyzer<'_, '_> {
},
)?;

self.assign_param_type(data, &le, &re, opts).with_context(|| {
dbg!(self.assign_param_type(data, &le, &re, opts).with_context(|| {
format!(
"tried to assign a rest parameter to parameters; r_ty = {}",
force_dump_type_as_string(&r.ty)
)
})?;
}))?;
}
}

return Ok(());
continue;
}

dbg!();
self.assign_param(data, l, r, opts)
.context("tried to assign a rest parameter to parameters where r-ty is not a tuple")?;

for l in li {
dbg!();
self.assign_param(data, l, r, opts)
.context("tried to assign a rest parameter to parameters where r-ty is not a tuple (iter)")?;
}
dbg!();

return Ok(());
}

_ => {
dbg!();
self.assign_param(
data,
l,
Expand All @@ -1012,6 +1039,7 @@ impl Analyzer<'_, '_> {
..opts
},
)?;
dbg!();
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/stc_ts_file_analyzer/src/analyzer/assign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ pub(crate) struct AssignOpts {
/// If true, `assign` will fail if the params of the LHS is longer than the
/// RHS.
pub ensure_params_length: bool,

pub disallow_rest_pat_in_left: bool,
}

#[derive(Default)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
TS2322

x AssignFailed {
| span: Span {
| lo: BytePos(
| 199,
| ),
| hi: BytePos(
| 200,
| ),
| ctxt: #1,
| },
| cause: [
| SimpleAssignFailed {
| span: Span {
| lo: BytePos(
| 199,
| ),
| hi: BytePos(
| 200,
| ),
| ctxt: #1,
| },
| cause: None,
| },
| ],
| }
,-[$DIR/tests/errors/conformance/types/assignmentCompatibility/assignmentCompatWithCallSignaturesWithRestParameters/1.ts:3:1]
3 | declare var a: (...args: number[]) => number; // ok, same number of required params
4 | a = (x?: string) => 1; // error, incompatible type
: ^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// call signatures in derived types must have the same or fewer optional parameters as the target for assignment

declare var a: (...args: number[]) => number; // ok, same number of required params
a = (x?: string) => 1; // error, incompatible type

export { }