mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 05:32:09 +03:00
Fix bugs (#683)
- Fix block_scoping (Fix #682) - Handle new.target in susbscript position (Fix #675)
This commit is contained in:
parent
15bef97278
commit
e3ca8e5d13
@ -413,10 +413,12 @@ impl<'a, I: Tokens> Parser<'a, I> {
|
||||
if eat!('.') {
|
||||
let start_of_target = cur_pos!();
|
||||
if eat!("target") {
|
||||
return Ok(Box::new(Expr::MetaProp(MetaPropExpr {
|
||||
let expr = Box::new(Expr::MetaProp(MetaPropExpr {
|
||||
meta: Ident::new(js_word!("new"), span_of_new),
|
||||
prop: Ident::new(js_word!("target"), span!(start_of_target)),
|
||||
})));
|
||||
}));
|
||||
|
||||
return self.parse_subscripts(ExprOrSuper::Expr(expr), true);
|
||||
}
|
||||
|
||||
unexpected!()
|
||||
|
@ -418,6 +418,11 @@ fn issue_380() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_675() {
|
||||
expr("Object.setPrototypeOf(this, new.target.prototype)");
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_new_expr_ts(b: &mut Bencher) {
|
||||
bench_parser(
|
||||
|
@ -21,7 +21,11 @@ use swc_ecma_utils::{
|
||||
/// }
|
||||
/// ```
|
||||
pub fn block_scoping() -> impl Pass {
|
||||
BlockScoping::default()
|
||||
BlockScoping {
|
||||
scope: Default::default(),
|
||||
vars: vec![],
|
||||
var_decl_kind: VarDeclKind::Var,
|
||||
}
|
||||
}
|
||||
|
||||
type ScopeStack = SmallVec<[ScopeKind; 8]>;
|
||||
@ -39,10 +43,10 @@ enum ScopeKind {
|
||||
Block,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BlockScoping {
|
||||
scope: ScopeStack,
|
||||
vars: Vec<VarDeclarator>,
|
||||
var_decl_kind: VarDeclKind,
|
||||
}
|
||||
|
||||
noop_fold_type!(BlockScoping);
|
||||
@ -99,6 +103,14 @@ impl BlockScoping {
|
||||
|
||||
fn handle_vars(&mut self, body: Box<Stmt>) -> Box<Stmt> {
|
||||
body.map(|body| {
|
||||
{
|
||||
let mut v = FunctionFinder { found: false };
|
||||
body.visit_with(&mut v);
|
||||
if !v.found {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if let Some(ScopeKind::ForLetLoop { args, used, .. }) = self.scope.pop() {
|
||||
if used.is_empty() {
|
||||
@ -330,8 +342,12 @@ impl Fold<SetterProp> for BlockScoping {
|
||||
|
||||
impl Fold<VarDecl> for BlockScoping {
|
||||
fn fold(&mut self, var: VarDecl) -> VarDecl {
|
||||
let old = self.var_decl_kind;
|
||||
self.var_decl_kind = var.kind;
|
||||
let var = var.fold_children(self);
|
||||
|
||||
self.var_decl_kind = old;
|
||||
|
||||
VarDecl {
|
||||
kind: VarDeclKind::Var,
|
||||
..var
|
||||
@ -344,7 +360,11 @@ impl Fold<VarDeclarator> for BlockScoping {
|
||||
let var = var.fold_children(self);
|
||||
|
||||
let init = if self.in_loop_body() && var.init.is_none() {
|
||||
Some(undefined(var.span()))
|
||||
if self.var_decl_kind == VarDeclKind::Var {
|
||||
None
|
||||
} else {
|
||||
Some(undefined(var.span()))
|
||||
}
|
||||
} else {
|
||||
var.init
|
||||
};
|
||||
@ -419,6 +439,8 @@ struct InfectionFinder<'a> {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
noop_visit_type!(InfectionFinder<'_>);
|
||||
|
||||
impl Visit<VarDeclarator> for InfectionFinder<'_> {
|
||||
fn visit(&mut self, node: &VarDeclarator) {
|
||||
let old = self.found;
|
||||
@ -480,6 +502,19 @@ impl Visit<Ident> for InfectionFinder<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
noop_visit_type!(FunctionFinder);
|
||||
|
||||
impl Visit<Function> for FunctionFinder {
|
||||
fn visit(&mut self, node: &Function) {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::block_scoping;
|
||||
@ -591,4 +626,52 @@ expect(functions[0]()).toBe(1);
|
||||
expect(functions[1]()).toBe(3);
|
||||
"
|
||||
);
|
||||
|
||||
test!(
|
||||
::swc_ecma_parser::Syntax::default(),
|
||||
|_| block_scoping(),
|
||||
issue_662,
|
||||
"function foo(parts) {
|
||||
let match = null;
|
||||
|
||||
for (let i = 1; i >= 0; i--) {
|
||||
for (let j = 0; j >= 0; j--) {
|
||||
match = parts[i][j];
|
||||
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
foo();",
|
||||
"function foo(parts) {
|
||||
var match = null;
|
||||
|
||||
for (var i = 1; i >= 0; i--) {
|
||||
for (var j = 0; j >= 0; j--) {
|
||||
match = parts[i][j];
|
||||
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
foo();"
|
||||
);
|
||||
}
|
||||
|
141
src/lib.rs
141
src/lib.rs
@ -206,80 +206,83 @@ impl Compiler {
|
||||
opts: &Options,
|
||||
fm: &SourceFile,
|
||||
) -> Result<BuiltConfig<impl Pass>, Error> {
|
||||
let Options {
|
||||
ref root,
|
||||
root_mode,
|
||||
swcrc,
|
||||
config_file,
|
||||
is_module,
|
||||
..
|
||||
} = opts;
|
||||
let root = root
|
||||
.clone()
|
||||
.unwrap_or_else(|| ::std::env::current_dir().unwrap());
|
||||
self.run(|| {
|
||||
let Options {
|
||||
ref root,
|
||||
root_mode,
|
||||
swcrc,
|
||||
config_file,
|
||||
is_module,
|
||||
..
|
||||
} = opts;
|
||||
let root = root
|
||||
.clone()
|
||||
.unwrap_or_else(|| ::std::env::current_dir().unwrap());
|
||||
|
||||
let config_file = match config_file {
|
||||
Some(ConfigFile::Str(ref s)) => {
|
||||
let path = Path::new(s);
|
||||
let r = File::open(&path).map_err(|err| Error::FailedToReadConfigFile { err })?;
|
||||
let config: Rc = serde_json::from_reader(r)
|
||||
.map_err(|err| Error::FailedToParseConfigFile { err })?;
|
||||
Some(config)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
match fm.name {
|
||||
FileName::Real(ref path) => {
|
||||
if *swcrc {
|
||||
let mut parent = path.parent();
|
||||
while let Some(dir) = parent {
|
||||
let swcrc = dir.join(".swcrc");
|
||||
|
||||
if swcrc.exists() {
|
||||
let r = File::open(&swcrc)
|
||||
.map_err(|err| Error::FailedToReadConfigFile { err })?;
|
||||
let mut config = serde_json::from_reader(r)
|
||||
.map_err(|err| Error::FailedToParseConfigFile { err })
|
||||
.and_then(|rc: Rc| rc.into_config(Some(path)))?;
|
||||
|
||||
if let Some(config_file) = config_file {
|
||||
config.merge(&config_file.into_config(Some(path))?)
|
||||
}
|
||||
let built =
|
||||
opts.build(&self.cm, &self.handler, *is_module, Some(config));
|
||||
return Ok(built);
|
||||
}
|
||||
|
||||
if dir == root && *root_mode == RootMode::Root {
|
||||
break;
|
||||
}
|
||||
parent = dir.parent();
|
||||
}
|
||||
let config_file = match config_file {
|
||||
Some(ConfigFile::Str(ref s)) => {
|
||||
let path = Path::new(s);
|
||||
let r =
|
||||
File::open(&path).map_err(|err| Error::FailedToReadConfigFile { err })?;
|
||||
let config: Rc = serde_json::from_reader(r)
|
||||
.map_err(|err| Error::FailedToParseConfigFile { err })?;
|
||||
Some(config)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let config_file = config_file.unwrap_or_else(|| Rc::default());
|
||||
let built = opts.build(
|
||||
&self.cm,
|
||||
&self.handler,
|
||||
*is_module,
|
||||
Some(config_file.into_config(Some(path))?),
|
||||
);
|
||||
return Ok(built);
|
||||
match fm.name {
|
||||
FileName::Real(ref path) => {
|
||||
if *swcrc {
|
||||
let mut parent = path.parent();
|
||||
while let Some(dir) = parent {
|
||||
let swcrc = dir.join(".swcrc");
|
||||
|
||||
if swcrc.exists() {
|
||||
let r = File::open(&swcrc)
|
||||
.map_err(|err| Error::FailedToReadConfigFile { err })?;
|
||||
let mut config = serde_json::from_reader(r)
|
||||
.map_err(|err| Error::FailedToParseConfigFile { err })
|
||||
.and_then(|rc: Rc| rc.into_config(Some(path)))?;
|
||||
|
||||
if let Some(config_file) = config_file {
|
||||
config.merge(&config_file.into_config(Some(path))?)
|
||||
}
|
||||
let built =
|
||||
opts.build(&self.cm, &self.handler, *is_module, Some(config));
|
||||
return Ok(built);
|
||||
}
|
||||
|
||||
if dir == root && *root_mode == RootMode::Root {
|
||||
break;
|
||||
}
|
||||
parent = dir.parent();
|
||||
}
|
||||
}
|
||||
|
||||
let config_file = config_file.unwrap_or_else(|| Rc::default());
|
||||
let built = opts.build(
|
||||
&self.cm,
|
||||
&self.handler,
|
||||
*is_module,
|
||||
Some(config_file.into_config(Some(path))?),
|
||||
);
|
||||
return Ok(built);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let built = opts.build(
|
||||
&self.cm,
|
||||
&self.handler,
|
||||
*is_module,
|
||||
match config_file {
|
||||
Some(config_file) => Some(config_file.into_config(None)?),
|
||||
None => Some(Rc::default().into_config(None)?),
|
||||
},
|
||||
);
|
||||
Ok(built)
|
||||
let built = opts.build(
|
||||
&self.cm,
|
||||
&self.handler,
|
||||
*is_module,
|
||||
match config_file {
|
||||
Some(config_file) => Some(config_file.into_config(None)?),
|
||||
None => Some(Rc::default().into_config(None)?),
|
||||
},
|
||||
);
|
||||
Ok(built)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_js_file(
|
||||
|
Loading…
Reference in New Issue
Block a user