mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-28 18:43:01 +00:00
Merge pull request #20056 from ShoyuVanilla/fmt-args-new
Some checks failed
metrics / build_metrics (push) Has been cancelled
rustdoc / rustdoc (push) Has been cancelled
metrics / generate_final_metrics (push) Has been cancelled
metrics / other_metrics (diesel-1.4.8) (push) Has been cancelled
metrics / other_metrics (hyper-0.14.18) (push) Has been cancelled
metrics / other_metrics (ripgrep-13.0.0) (push) Has been cancelled
metrics / other_metrics (self) (push) Has been cancelled
metrics / other_metrics (webrender-2022) (push) Has been cancelled
release / dist (x86_64-unknown-linux-gnu) (push) Has been cancelled
release / dist (aarch64-pc-windows-msvc) (push) Has been cancelled
release / dist (x86_64-pc-windows-msvc) (push) Has been cancelled
release / dist (i686-pc-windows-msvc) (push) Has been cancelled
autopublish / publish (push) Has been cancelled
release / dist (aarch64-apple-darwin) (push) Has been cancelled
release / dist (x86_64-apple-darwin) (push) Has been cancelled
release / dist (aarch64-unknown-linux-gnu) (push) Has been cancelled
release / dist (arm-unknown-linux-gnueabihf) (push) Has been cancelled
release / dist (x86_64-unknown-linux-musl) (push) Has been cancelled
release / publish (push) Has been cancelled
Some checks failed
metrics / build_metrics (push) Has been cancelled
rustdoc / rustdoc (push) Has been cancelled
metrics / generate_final_metrics (push) Has been cancelled
metrics / other_metrics (diesel-1.4.8) (push) Has been cancelled
metrics / other_metrics (hyper-0.14.18) (push) Has been cancelled
metrics / other_metrics (ripgrep-13.0.0) (push) Has been cancelled
metrics / other_metrics (self) (push) Has been cancelled
metrics / other_metrics (webrender-2022) (push) Has been cancelled
release / dist (x86_64-unknown-linux-gnu) (push) Has been cancelled
release / dist (aarch64-pc-windows-msvc) (push) Has been cancelled
release / dist (x86_64-pc-windows-msvc) (push) Has been cancelled
release / dist (i686-pc-windows-msvc) (push) Has been cancelled
autopublish / publish (push) Has been cancelled
release / dist (aarch64-apple-darwin) (push) Has been cancelled
release / dist (x86_64-apple-darwin) (push) Has been cancelled
release / dist (aarch64-unknown-linux-gnu) (push) Has been cancelled
release / dist (arm-unknown-linux-gnueabihf) (push) Has been cancelled
release / dist (x86_64-unknown-linux-musl) (push) Has been cancelled
release / publish (push) Has been cancelled
Minic rustc's new `format_args!` expansion
This commit is contained in:
commit
0100bc7373
8 changed files with 412 additions and 46 deletions
|
|
@ -2815,6 +2815,51 @@ impl ExprCollector<'_> {
|
||||||
mutability: Mutability::Shared,
|
mutability: Mutability::Shared,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
|
||||||
|
// but `format_unsafe_arg` does not
|
||||||
|
let fmt_args =
|
||||||
|
|| crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatArguments);
|
||||||
|
let fmt_unsafe_arg =
|
||||||
|
|| crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatUnsafeArg);
|
||||||
|
let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none();
|
||||||
|
|
||||||
|
let idx = if use_format_args_since_1_89_0 {
|
||||||
|
self.collect_format_args_impl(
|
||||||
|
syntax_ptr,
|
||||||
|
fmt,
|
||||||
|
hygiene,
|
||||||
|
argmap,
|
||||||
|
lit_pieces,
|
||||||
|
format_options,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.collect_format_args_before_1_89_0_impl(
|
||||||
|
syntax_ptr,
|
||||||
|
fmt,
|
||||||
|
argmap,
|
||||||
|
lit_pieces,
|
||||||
|
format_options,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.source_map
|
||||||
|
.template_map
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
|
.format_args_to_captures
|
||||||
|
.insert(idx, (hygiene, mappings));
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `format_args!` expansion implementation for rustc versions < `1.89.0`
|
||||||
|
fn collect_format_args_before_1_89_0_impl(
|
||||||
|
&mut self,
|
||||||
|
syntax_ptr: AstPtr<ast::Expr>,
|
||||||
|
fmt: FormatArgs,
|
||||||
|
argmap: FxIndexSet<(usize, ArgumentType)>,
|
||||||
|
lit_pieces: ExprId,
|
||||||
|
format_options: ExprId,
|
||||||
|
) -> ExprId {
|
||||||
let arguments = &*fmt.arguments.arguments;
|
let arguments = &*fmt.arguments.arguments;
|
||||||
|
|
||||||
let args = if arguments.is_empty() {
|
let args = if arguments.is_empty() {
|
||||||
|
|
@ -2902,19 +2947,181 @@ impl ExprCollector<'_> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let idx = self.alloc_expr(
|
self.alloc_expr(
|
||||||
Expr::Call {
|
Expr::Call {
|
||||||
callee: new_v1_formatted,
|
callee: new_v1_formatted,
|
||||||
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
|
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
|
||||||
},
|
},
|
||||||
syntax_ptr,
|
syntax_ptr,
|
||||||
);
|
)
|
||||||
self.source_map
|
}
|
||||||
.template_map
|
|
||||||
.get_or_insert_with(Default::default)
|
/// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
|
||||||
.format_args_to_captures
|
/// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
|
||||||
.insert(idx, (hygiene, mappings));
|
fn collect_format_args_impl(
|
||||||
idx
|
&mut self,
|
||||||
|
syntax_ptr: AstPtr<ast::Expr>,
|
||||||
|
fmt: FormatArgs,
|
||||||
|
hygiene: HygieneId,
|
||||||
|
argmap: FxIndexSet<(usize, ArgumentType)>,
|
||||||
|
lit_pieces: ExprId,
|
||||||
|
format_options: ExprId,
|
||||||
|
) -> ExprId {
|
||||||
|
let arguments = &*fmt.arguments.arguments;
|
||||||
|
|
||||||
|
let (let_stmts, args) = if arguments.is_empty() {
|
||||||
|
(
|
||||||
|
// Generate:
|
||||||
|
// []
|
||||||
|
vec![],
|
||||||
|
self.alloc_expr_desugared(Expr::Array(Array::ElementList {
|
||||||
|
elements: Box::default(),
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
} else if argmap.len() == 1 && arguments.len() == 1 {
|
||||||
|
// Only one argument, so we don't need to make the `args` tuple.
|
||||||
|
//
|
||||||
|
// Generate:
|
||||||
|
// super let args = [<core::fmt::Arguments>::new_display(&arg)];
|
||||||
|
let args = argmap
|
||||||
|
.iter()
|
||||||
|
.map(|&(arg_index, ty)| {
|
||||||
|
let ref_arg = self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: arguments[arg_index].expr,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
});
|
||||||
|
self.make_argument(ref_arg, ty)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let args =
|
||||||
|
self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
|
||||||
|
let args_name = Name::new_symbol_root(sym::args);
|
||||||
|
let args_binding =
|
||||||
|
self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
|
||||||
|
let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
|
||||||
|
self.add_definition_to_binding(args_binding, args_pat);
|
||||||
|
// TODO: We don't have `super let` yet.
|
||||||
|
let let_stmt = Statement::Let {
|
||||||
|
pat: args_pat,
|
||||||
|
type_ref: None,
|
||||||
|
initializer: Some(args),
|
||||||
|
else_branch: None,
|
||||||
|
};
|
||||||
|
(vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name))))
|
||||||
|
} else {
|
||||||
|
// Generate:
|
||||||
|
// super let args = (&arg0, &arg1, &...);
|
||||||
|
let args_name = Name::new_symbol_root(sym::args);
|
||||||
|
let args_binding =
|
||||||
|
self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
|
||||||
|
let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
|
||||||
|
self.add_definition_to_binding(args_binding, args_pat);
|
||||||
|
let elements = arguments
|
||||||
|
.iter()
|
||||||
|
.map(|arg| {
|
||||||
|
self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: arg.expr,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
|
||||||
|
// TODO: We don't have `super let` yet
|
||||||
|
let let_stmt1 = Statement::Let {
|
||||||
|
pat: args_pat,
|
||||||
|
type_ref: None,
|
||||||
|
initializer: Some(args_tuple),
|
||||||
|
else_branch: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate:
|
||||||
|
// super let args = [
|
||||||
|
// <core::fmt::Argument>::new_display(args.0),
|
||||||
|
// <core::fmt::Argument>::new_lower_hex(args.1),
|
||||||
|
// <core::fmt::Argument>::new_debug(args.0),
|
||||||
|
// …
|
||||||
|
// ];
|
||||||
|
let args = argmap
|
||||||
|
.iter()
|
||||||
|
.map(|&(arg_index, ty)| {
|
||||||
|
let args_ident_expr =
|
||||||
|
self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
|
||||||
|
let arg = self.alloc_expr_desugared(Expr::Field {
|
||||||
|
expr: args_ident_expr,
|
||||||
|
name: Name::new_tuple_field(arg_index),
|
||||||
|
});
|
||||||
|
self.make_argument(arg, ty)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let array =
|
||||||
|
self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
|
||||||
|
let args_binding =
|
||||||
|
self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
|
||||||
|
let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
|
||||||
|
self.add_definition_to_binding(args_binding, args_pat);
|
||||||
|
let let_stmt2 = Statement::Let {
|
||||||
|
pat: args_pat,
|
||||||
|
type_ref: None,
|
||||||
|
initializer: Some(array),
|
||||||
|
else_branch: None,
|
||||||
|
};
|
||||||
|
(vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate:
|
||||||
|
// &args
|
||||||
|
let args = self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: args,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
});
|
||||||
|
|
||||||
|
let call_block = {
|
||||||
|
// Generate:
|
||||||
|
// unsafe {
|
||||||
|
// <core::fmt::Arguments>::new_v1_formatted(
|
||||||
|
// lit_pieces,
|
||||||
|
// args,
|
||||||
|
// format_options,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
let new_v1_formatted = LangItem::FormatArguments.ty_rel_path(
|
||||||
|
self.db,
|
||||||
|
self.module.krate(),
|
||||||
|
Name::new_symbol_root(sym::new_v1_formatted),
|
||||||
|
);
|
||||||
|
let new_v1_formatted =
|
||||||
|
self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
|
||||||
|
let args = [lit_pieces, args, format_options];
|
||||||
|
let call = self
|
||||||
|
.alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
|
||||||
|
|
||||||
|
Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if !let_stmts.is_empty() {
|
||||||
|
// Generate:
|
||||||
|
// {
|
||||||
|
// super let …
|
||||||
|
// super let …
|
||||||
|
// <core::fmt::Arguments>::new_…(…)
|
||||||
|
// }
|
||||||
|
let call = self.alloc_expr_desugared(call_block);
|
||||||
|
self.alloc_expr(
|
||||||
|
Expr::Block {
|
||||||
|
id: None,
|
||||||
|
statements: let_stmts.into(),
|
||||||
|
tail: Some(call),
|
||||||
|
label: None,
|
||||||
|
},
|
||||||
|
syntax_ptr,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.alloc_expr(call_block, syntax_ptr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a hir expression for a format_args placeholder specification.
|
/// Generate a hir expression for a format_args placeholder specification.
|
||||||
|
|
|
||||||
|
|
@ -178,14 +178,14 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn desugar_builtin_format_args() {
|
fn desugar_builtin_format_args_before_1_89_0() {
|
||||||
let (db, body, def) = lower(
|
let (db, body, def) = lower(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt_before_1_89_0
|
||||||
fn main() {
|
fn main() {
|
||||||
let are = "are";
|
let are = "are";
|
||||||
let count = 10;
|
let count = 10;
|
||||||
builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
|
builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
@ -249,14 +249,100 @@ fn main() {
|
||||||
builtin#lang(Count::Implied),
|
builtin#lang(Count::Implied),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
unsafe {
|
{
|
||||||
builtin#lang(UnsafeArg::new)()
|
();
|
||||||
|
unsafe {
|
||||||
|
builtin#lang(UnsafeArg::new)()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}"#]]
|
}"#]]
|
||||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn desugar_builtin_format_args() {
|
||||||
|
let (db, body, def) = lower(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
|
fn main() {
|
||||||
|
let are = "are";
|
||||||
|
let count = 10;
|
||||||
|
builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect![[r#"
|
||||||
|
fn main() {
|
||||||
|
let are = "are";
|
||||||
|
let count = 10;
|
||||||
|
{
|
||||||
|
let args = (&"fancy", &(), &"!", &count, &are, );
|
||||||
|
let args = [
|
||||||
|
builtin#lang(Argument::new_display)(
|
||||||
|
args.3,
|
||||||
|
), builtin#lang(Argument::new_display)(
|
||||||
|
args.0,
|
||||||
|
), builtin#lang(Argument::new_debug)(
|
||||||
|
args.4,
|
||||||
|
), builtin#lang(Argument::new_display)(
|
||||||
|
args.2,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
unsafe {
|
||||||
|
builtin#lang(Arguments::new_v1_formatted)(
|
||||||
|
&[
|
||||||
|
"\u{1b}hello ", " ", " friends, we ", " ", "",
|
||||||
|
],
|
||||||
|
&args,
|
||||||
|
&[
|
||||||
|
builtin#lang(Placeholder::new)(
|
||||||
|
0usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
8u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Is)(
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
1usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
2usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
1usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
3usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}"#]]
|
||||||
|
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_macro_hygiene() {
|
fn test_macro_hygiene() {
|
||||||
let (db, body, def) = lower(
|
let (db, body, def) = lower(
|
||||||
|
|
@ -295,29 +381,31 @@ impl SsrError {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
_ = ra_test_fixture::error::SsrError::new(
|
_ = ra_test_fixture::error::SsrError::new(
|
||||||
builtin#lang(Arguments::new_v1_formatted)(
|
{
|
||||||
&[
|
let args = [
|
||||||
"Failed to resolve path `", "`",
|
|
||||||
],
|
|
||||||
&[
|
|
||||||
builtin#lang(Argument::new_display)(
|
builtin#lang(Argument::new_display)(
|
||||||
&node.text(),
|
&node.text(),
|
||||||
),
|
),
|
||||||
],
|
];
|
||||||
&[
|
|
||||||
builtin#lang(Placeholder::new)(
|
|
||||||
0usize,
|
|
||||||
' ',
|
|
||||||
builtin#lang(Alignment::Unknown),
|
|
||||||
0u32,
|
|
||||||
builtin#lang(Count::Implied),
|
|
||||||
builtin#lang(Count::Implied),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
unsafe {
|
unsafe {
|
||||||
builtin#lang(UnsafeArg::new)()
|
builtin#lang(Arguments::new_v1_formatted)(
|
||||||
},
|
&[
|
||||||
),
|
"Failed to resolve path `", "`",
|
||||||
|
],
|
||||||
|
&args,
|
||||||
|
&[
|
||||||
|
builtin#lang(Placeholder::new)(
|
||||||
|
0usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}"#]]
|
}"#]]
|
||||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||||
|
|
@ -327,7 +415,7 @@ impl SsrError {
|
||||||
fn regression_10300() {
|
fn regression_10300() {
|
||||||
let (db, body, def) = lower(
|
let (db, body, def) = lower(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: concat, panic
|
//- minicore: concat, panic, fmt_before_1_89_0
|
||||||
mod private {
|
mod private {
|
||||||
pub use core::concat;
|
pub use core::concat;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#,
|
||||||
fn test_complete_todo_with_msg() {
|
fn test_complete_todo_with_msg() {
|
||||||
check_assist(
|
check_assist(
|
||||||
term_search,
|
term_search,
|
||||||
r#"//- minicore: todo, unimplemented
|
// FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
|
||||||
|
// Should implement super let and remove `fmt_before_1_89_0`
|
||||||
|
r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
|
||||||
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||||
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
||||||
)
|
)
|
||||||
|
|
@ -110,7 +112,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||||
fn test_complete_unimplemented_with_msg() {
|
fn test_complete_unimplemented_with_msg() {
|
||||||
check_assist(
|
check_assist(
|
||||||
term_search,
|
term_search,
|
||||||
r#"//- minicore: todo, unimplemented
|
// FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
|
||||||
|
// Should implement super let and remove `fmt_before_1_89_0`
|
||||||
|
r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
|
||||||
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||||
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
||||||
)
|
)
|
||||||
|
|
@ -120,7 +124,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||||
fn test_complete_unimplemented() {
|
fn test_complete_unimplemented() {
|
||||||
check_assist(
|
check_assist(
|
||||||
term_search,
|
term_search,
|
||||||
r#"//- minicore: todo, unimplemented
|
// FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
|
||||||
|
// Should implement super let and remove `fmt_before_1_89_0`
|
||||||
|
r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
|
||||||
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||||
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1474,20 +1474,18 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
me foo() fn(&self)
|
||||||
sn box Box::new(expr)
|
sn box Box::new(expr)
|
||||||
sn call function(expr)
|
sn call function(expr)
|
||||||
sn const const {}
|
sn const const {}
|
||||||
sn dbg dbg!(expr)
|
sn dbg dbg!(expr)
|
||||||
sn dbgr dbg!(&expr)
|
sn dbgr dbg!(&expr)
|
||||||
sn deref *expr
|
sn deref *expr
|
||||||
sn if if expr {}
|
|
||||||
sn match match expr {}
|
sn match match expr {}
|
||||||
sn not !expr
|
|
||||||
sn ref &expr
|
sn ref &expr
|
||||||
sn refm &mut expr
|
sn refm &mut expr
|
||||||
sn return return expr
|
sn return return expr
|
||||||
sn unsafe unsafe {}
|
sn unsafe unsafe {}
|
||||||
sn while while expr {}
|
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -628,6 +628,17 @@ fn main() {
|
||||||
#[test]
|
#[test]
|
||||||
fn orphan_unsafe_format_args() {
|
fn orphan_unsafe_format_args() {
|
||||||
// Checks that we don't place orphan arguments for formatting under an unsafe block.
|
// Checks that we don't place orphan arguments for formatting under an unsafe block.
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt_before_1_89_0
|
||||||
|
fn foo() {
|
||||||
|
let p = 0xDEADBEEF as *const i32;
|
||||||
|
format_args!("", *p);
|
||||||
|
// ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt
|
||||||
|
|
@ -958,4 +969,18 @@ impl FooTrait for S2 {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_false_positive_on_format_args_since_1_89_0() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
|
fn test() {
|
||||||
|
let foo = 10;
|
||||||
|
let bar = true;
|
||||||
|
let _x = format_args!("{} {0} {} {last}", foo, bar, last = "!");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,7 @@ define_symbols! {
|
||||||
vectorcall,
|
vectorcall,
|
||||||
wasm,
|
wasm,
|
||||||
win64,
|
win64,
|
||||||
|
args,
|
||||||
array,
|
array,
|
||||||
boxed_slice,
|
boxed_slice,
|
||||||
completions,
|
completions,
|
||||||
|
|
|
||||||
|
|
@ -412,22 +412,36 @@ impl MiniCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut active_regions = Vec::new();
|
let mut active_regions = Vec::new();
|
||||||
|
let mut inactive_regions = Vec::new();
|
||||||
let mut seen_regions = Vec::new();
|
let mut seen_regions = Vec::new();
|
||||||
for line in lines {
|
for line in lines {
|
||||||
let trimmed = line.trim();
|
let trimmed = line.trim();
|
||||||
if let Some(region) = trimmed.strip_prefix("// region:") {
|
if let Some(region) = trimmed.strip_prefix("// region:") {
|
||||||
active_regions.push(region);
|
if let Some(region) = region.strip_prefix('!') {
|
||||||
continue;
|
inactive_regions.push(region);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
active_regions.push(region);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(region) = trimmed.strip_prefix("// endregion:") {
|
if let Some(region) = trimmed.strip_prefix("// endregion:") {
|
||||||
let prev = active_regions.pop().unwrap();
|
let (prev, region) = if let Some(region) = region.strip_prefix('!') {
|
||||||
|
(inactive_regions.pop().unwrap(), region)
|
||||||
|
} else {
|
||||||
|
(active_regions.pop().unwrap(), region)
|
||||||
|
};
|
||||||
assert_eq!(prev, region, "unbalanced region pairs");
|
assert_eq!(prev, region, "unbalanced region pairs");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut line_region = false;
|
let mut active_line_region = false;
|
||||||
if let Some(idx) = trimmed.find("// :") {
|
let mut inactive_line_region = false;
|
||||||
line_region = true;
|
if let Some(idx) = trimmed.find("// :!") {
|
||||||
|
inactive_line_region = true;
|
||||||
|
inactive_regions.push(&trimmed[idx + "// :!".len()..]);
|
||||||
|
} else if let Some(idx) = trimmed.find("// :") {
|
||||||
|
active_line_region = true;
|
||||||
active_regions.push(&trimmed[idx + "// :".len()..]);
|
active_regions.push(&trimmed[idx + "// :".len()..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,18 +452,30 @@ impl MiniCore {
|
||||||
seen_regions.push(region);
|
seen_regions.push(region);
|
||||||
keep &= self.has_flag(region);
|
keep &= self.has_flag(region);
|
||||||
}
|
}
|
||||||
|
for ®ion in &inactive_regions {
|
||||||
|
assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}");
|
||||||
|
self.assert_valid_flag(region);
|
||||||
|
seen_regions.push(region);
|
||||||
|
keep &= !self.has_flag(region);
|
||||||
|
}
|
||||||
|
|
||||||
if keep {
|
if keep {
|
||||||
buf.push_str(line);
|
buf.push_str(line);
|
||||||
}
|
}
|
||||||
if line_region {
|
if active_line_region {
|
||||||
active_regions.pop().unwrap();
|
active_regions.pop().unwrap();
|
||||||
}
|
}
|
||||||
|
if inactive_line_region {
|
||||||
|
inactive_regions.pop().unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !active_regions.is_empty() {
|
if !active_regions.is_empty() {
|
||||||
panic!("unclosed regions: {active_regions:?} Add an `endregion` comment");
|
panic!("unclosed regions: {active_regions:?} Add an `endregion` comment");
|
||||||
}
|
}
|
||||||
|
if !inactive_regions.is_empty() {
|
||||||
|
panic!("unclosed regions: {inactive_regions:?} Add an `endregion` comment");
|
||||||
|
}
|
||||||
|
|
||||||
for flag in &self.valid_flags {
|
for flag in &self.valid_flags {
|
||||||
if !seen_regions.iter().any(|it| it == flag) {
|
if !seen_regions.iter().any(|it| it == flag) {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
//! eq: sized
|
//! eq: sized
|
||||||
//! error: fmt
|
//! error: fmt
|
||||||
//! fmt: option, result, transmute, coerce_unsized, copy, clone, derive
|
//! fmt: option, result, transmute, coerce_unsized, copy, clone, derive
|
||||||
|
//! fmt_before_1_89_0: fmt
|
||||||
//! fn: tuple
|
//! fn: tuple
|
||||||
//! from: sized, result
|
//! from: sized, result
|
||||||
//! future: pin
|
//! future: pin
|
||||||
|
|
@ -1175,6 +1176,7 @@ pub mod fmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region:fmt_before_1_89_0
|
||||||
#[lang = "format_unsafe_arg"]
|
#[lang = "format_unsafe_arg"]
|
||||||
pub struct UnsafeArg {
|
pub struct UnsafeArg {
|
||||||
_private: (),
|
_private: (),
|
||||||
|
|
@ -1185,6 +1187,7 @@ pub mod fmt {
|
||||||
UnsafeArg { _private: () }
|
UnsafeArg { _private: () }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// endregion:fmt_before_1_89_0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
@ -1204,6 +1207,7 @@ pub mod fmt {
|
||||||
Arguments { pieces, fmt: None, args: &[] }
|
Arguments { pieces, fmt: None, args: &[] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region:fmt_before_1_89_0
|
||||||
pub fn new_v1_formatted(
|
pub fn new_v1_formatted(
|
||||||
pieces: &'a [&'static str],
|
pieces: &'a [&'static str],
|
||||||
args: &'a [rt::Argument<'a>],
|
args: &'a [rt::Argument<'a>],
|
||||||
|
|
@ -1212,6 +1216,17 @@ pub mod fmt {
|
||||||
) -> Arguments<'a> {
|
) -> Arguments<'a> {
|
||||||
Arguments { pieces, fmt: Some(fmt), args }
|
Arguments { pieces, fmt: Some(fmt), args }
|
||||||
}
|
}
|
||||||
|
// endregion:fmt_before_1_89_0
|
||||||
|
|
||||||
|
// region:!fmt_before_1_89_0
|
||||||
|
pub unsafe fn new_v1_formatted(
|
||||||
|
pieces: &'a [&'static str],
|
||||||
|
args: &'a [rt::Argument<'a>],
|
||||||
|
fmt: &'a [rt::Placeholder],
|
||||||
|
) -> Arguments<'a> {
|
||||||
|
Arguments { pieces, fmt: Some(fmt), args }
|
||||||
|
}
|
||||||
|
// endregion:!fmt_before_1_89_0
|
||||||
|
|
||||||
pub const fn as_str(&self) -> Option<&'static str> {
|
pub const fn as_str(&self) -> Option<&'static str> {
|
||||||
match (self.pieces, self.args) {
|
match (self.pieces, self.args) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue