mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +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!('.') {
|
if eat!('.') {
|
||||||
let start_of_target = cur_pos!();
|
let start_of_target = cur_pos!();
|
||||||
if eat!("target") {
|
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),
|
meta: Ident::new(js_word!("new"), span_of_new),
|
||||||
prop: Ident::new(js_word!("target"), span!(start_of_target)),
|
prop: Ident::new(js_word!("target"), span!(start_of_target)),
|
||||||
})));
|
}));
|
||||||
|
|
||||||
|
return self.parse_subscripts(ExprOrSuper::Expr(expr), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
unexpected!()
|
unexpected!()
|
||||||
|
@ -418,6 +418,11 @@ fn issue_380() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_675() {
|
||||||
|
expr("Object.setPrototypeOf(this, new.target.prototype)");
|
||||||
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_new_expr_ts(b: &mut Bencher) {
|
fn bench_new_expr_ts(b: &mut Bencher) {
|
||||||
bench_parser(
|
bench_parser(
|
||||||
|
@ -21,7 +21,11 @@ use swc_ecma_utils::{
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn block_scoping() -> impl Pass {
|
pub fn block_scoping() -> impl Pass {
|
||||||
BlockScoping::default()
|
BlockScoping {
|
||||||
|
scope: Default::default(),
|
||||||
|
vars: vec![],
|
||||||
|
var_decl_kind: VarDeclKind::Var,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScopeStack = SmallVec<[ScopeKind; 8]>;
|
type ScopeStack = SmallVec<[ScopeKind; 8]>;
|
||||||
@ -39,10 +43,10 @@ enum ScopeKind {
|
|||||||
Block,
|
Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct BlockScoping {
|
struct BlockScoping {
|
||||||
scope: ScopeStack,
|
scope: ScopeStack,
|
||||||
vars: Vec<VarDeclarator>,
|
vars: Vec<VarDeclarator>,
|
||||||
|
var_decl_kind: VarDeclKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
noop_fold_type!(BlockScoping);
|
noop_fold_type!(BlockScoping);
|
||||||
@ -99,6 +103,14 @@ impl BlockScoping {
|
|||||||
|
|
||||||
fn handle_vars(&mut self, body: Box<Stmt>) -> Box<Stmt> {
|
fn handle_vars(&mut self, body: Box<Stmt>) -> Box<Stmt> {
|
||||||
body.map(|body| {
|
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 let Some(ScopeKind::ForLetLoop { args, used, .. }) = self.scope.pop() {
|
||||||
if used.is_empty() {
|
if used.is_empty() {
|
||||||
@ -330,8 +342,12 @@ impl Fold<SetterProp> for BlockScoping {
|
|||||||
|
|
||||||
impl Fold<VarDecl> for BlockScoping {
|
impl Fold<VarDecl> for BlockScoping {
|
||||||
fn fold(&mut self, var: VarDecl) -> VarDecl {
|
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);
|
let var = var.fold_children(self);
|
||||||
|
|
||||||
|
self.var_decl_kind = old;
|
||||||
|
|
||||||
VarDecl {
|
VarDecl {
|
||||||
kind: VarDeclKind::Var,
|
kind: VarDeclKind::Var,
|
||||||
..var
|
..var
|
||||||
@ -344,7 +360,11 @@ impl Fold<VarDeclarator> for BlockScoping {
|
|||||||
let var = var.fold_children(self);
|
let var = var.fold_children(self);
|
||||||
|
|
||||||
let init = if self.in_loop_body() && var.init.is_none() {
|
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 {
|
} else {
|
||||||
var.init
|
var.init
|
||||||
};
|
};
|
||||||
@ -419,6 +439,8 @@ struct InfectionFinder<'a> {
|
|||||||
found: bool,
|
found: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noop_visit_type!(InfectionFinder<'_>);
|
||||||
|
|
||||||
impl Visit<VarDeclarator> for InfectionFinder<'_> {
|
impl Visit<VarDeclarator> for InfectionFinder<'_> {
|
||||||
fn visit(&mut self, node: &VarDeclarator) {
|
fn visit(&mut self, node: &VarDeclarator) {
|
||||||
let old = self.found;
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::block_scoping;
|
use super::block_scoping;
|
||||||
@ -591,4 +626,52 @@ expect(functions[0]()).toBe(1);
|
|||||||
expect(functions[1]()).toBe(3);
|
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,
|
opts: &Options,
|
||||||
fm: &SourceFile,
|
fm: &SourceFile,
|
||||||
) -> Result<BuiltConfig<impl Pass>, Error> {
|
) -> Result<BuiltConfig<impl Pass>, Error> {
|
||||||
let Options {
|
self.run(|| {
|
||||||
ref root,
|
let Options {
|
||||||
root_mode,
|
ref root,
|
||||||
swcrc,
|
root_mode,
|
||||||
config_file,
|
swcrc,
|
||||||
is_module,
|
config_file,
|
||||||
..
|
is_module,
|
||||||
} = opts;
|
..
|
||||||
let root = root
|
} = opts;
|
||||||
.clone()
|
let root = root
|
||||||
.unwrap_or_else(|| ::std::env::current_dir().unwrap());
|
.clone()
|
||||||
|
.unwrap_or_else(|| ::std::env::current_dir().unwrap());
|
||||||
|
|
||||||
let config_file = match config_file {
|
let config_file = match config_file {
|
||||||
Some(ConfigFile::Str(ref s)) => {
|
Some(ConfigFile::Str(ref s)) => {
|
||||||
let path = Path::new(s);
|
let path = Path::new(s);
|
||||||
let r = File::open(&path).map_err(|err| Error::FailedToReadConfigFile { err })?;
|
let r =
|
||||||
let config: Rc = serde_json::from_reader(r)
|
File::open(&path).map_err(|err| Error::FailedToReadConfigFile { err })?;
|
||||||
.map_err(|err| Error::FailedToParseConfigFile { err })?;
|
let config: Rc = serde_json::from_reader(r)
|
||||||
Some(config)
|
.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let config_file = config_file.unwrap_or_else(|| Rc::default());
|
match fm.name {
|
||||||
let built = opts.build(
|
FileName::Real(ref path) => {
|
||||||
&self.cm,
|
if *swcrc {
|
||||||
&self.handler,
|
let mut parent = path.parent();
|
||||||
*is_module,
|
while let Some(dir) = parent {
|
||||||
Some(config_file.into_config(Some(path))?),
|
let swcrc = dir.join(".swcrc");
|
||||||
);
|
|
||||||
return Ok(built);
|
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(
|
let built = opts.build(
|
||||||
&self.cm,
|
&self.cm,
|
||||||
&self.handler,
|
&self.handler,
|
||||||
*is_module,
|
*is_module,
|
||||||
match config_file {
|
match config_file {
|
||||||
Some(config_file) => Some(config_file.into_config(None)?),
|
Some(config_file) => Some(config_file.into_config(None)?),
|
||||||
None => Some(Rc::default().into_config(None)?),
|
None => Some(Rc::default().into_config(None)?),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(built)
|
Ok(built)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_js_file(
|
pub fn process_js_file(
|
||||||
|
Loading…
Reference in New Issue
Block a user