- Fix block_scoping (Fix #682)
 - Handle new.target in susbscript position (Fix #675)
This commit is contained in:
강동윤 2020-02-20 13:06:28 +09:00 committed by GitHub
parent 15bef97278
commit e3ca8e5d13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 74 deletions

View File

@ -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!()

View File

@ -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(

View File

@ -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();"
);
}

View File

@ -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(