Auto merge of #82263 - Dylan-DPC:rollup-cypm2uw, r=Dylan-DPC
Rollup of 10 pull requests Successful merges: - #81546 ([libtest] Run the test synchronously when hitting thread limit) - #82066 (Ensure valid TraitRefs are created for GATs) - #82112 (const_generics: Dont evaluate array length const when handling yet another error ) - #82194 (In some limited cases, suggest `where` bounds for non-type params) - #82215 (Replace if-let and while-let with `if let` and `while let`) - #82218 (Make sure pdbs are copied along with exe and dlls when bootstrapping) - #82236 (avoid converting types into themselves (clippy::useless_conversion)) - #82246 (Add long explanation for E0549) - #82248 (Optimize counting digits in line numbers during error reporting) - #82256 (Print -Ztime-passes (and misc stats/logs) on stderr, not stdout.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0148b971c9
89 changed files with 877 additions and 391 deletions
|
@ -914,6 +914,7 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
|
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
|
||||||
self.print_ident(constraint.ident);
|
self.print_ident(constraint.ident);
|
||||||
|
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
|
||||||
self.s.space();
|
self.s.space();
|
||||||
match &constraint.kind {
|
match &constraint.kind {
|
||||||
ast::AssocTyConstraintKind::Equality { ty } => {
|
ast::AssocTyConstraintKind::Equality { ty } => {
|
||||||
|
|
|
@ -608,7 +608,7 @@ pub fn print_time_passes_entry(
|
||||||
(None, None) => String::new(),
|
(None, None) => String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
|
eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack up our own formatting for the duration to make it easier for scripts
|
// Hack up our own formatting for the duration to make it easier for scripts
|
||||||
|
|
|
@ -290,6 +290,7 @@ E0543: include_str!("./error_codes/E0543.md"),
|
||||||
E0545: include_str!("./error_codes/E0545.md"),
|
E0545: include_str!("./error_codes/E0545.md"),
|
||||||
E0546: include_str!("./error_codes/E0546.md"),
|
E0546: include_str!("./error_codes/E0546.md"),
|
||||||
E0547: include_str!("./error_codes/E0547.md"),
|
E0547: include_str!("./error_codes/E0547.md"),
|
||||||
|
E0549: include_str!("./error_codes/E0549.md"),
|
||||||
E0550: include_str!("./error_codes/E0550.md"),
|
E0550: include_str!("./error_codes/E0550.md"),
|
||||||
E0551: include_str!("./error_codes/E0551.md"),
|
E0551: include_str!("./error_codes/E0551.md"),
|
||||||
E0552: include_str!("./error_codes/E0552.md"),
|
E0552: include_str!("./error_codes/E0552.md"),
|
||||||
|
@ -608,9 +609,6 @@ E0781: include_str!("./error_codes/E0781.md"),
|
||||||
// E0540, // multiple rustc_deprecated attributes
|
// E0540, // multiple rustc_deprecated attributes
|
||||||
E0544, // multiple stability levels
|
E0544, // multiple stability levels
|
||||||
// E0548, // replaced with a generic attribute input check
|
// E0548, // replaced with a generic attribute input check
|
||||||
// rustc_deprecated attribute must be paired with either stable or unstable
|
|
||||||
// attribute
|
|
||||||
E0549,
|
|
||||||
E0553, // multiple rustc_const_unstable attributes
|
E0553, // multiple rustc_const_unstable attributes
|
||||||
// E0555, // replaced with a generic attribute input check
|
// E0555, // replaced with a generic attribute input check
|
||||||
// E0558, // replaced with a generic attribute input check
|
// E0558, // replaced with a generic attribute input check
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#### Note: this error code is no longer emitted by the compiler.
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
An if-let pattern attempts to match the pattern, and enters the body if the
|
An `if let` pattern attempts to match the pattern, and enters the body if the
|
||||||
match was successful. If the match is irrefutable (when it cannot fail to
|
match was successful. If the match is irrefutable (when it cannot fail to
|
||||||
match), use a regular `let`-binding instead. For instance:
|
match), use a regular `let`-binding instead. For instance:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#### Note: this error code is no longer emitted by the compiler.
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
A while-let pattern attempts to match the pattern, and enters the body if the
|
A `while let` pattern attempts to match the pattern, and enters the body if the
|
||||||
match was successful. If the match is irrefutable (when it cannot fail to
|
match was successful. If the match is irrefutable (when it cannot fail to
|
||||||
match), use a regular `let`-binding inside a `loop` instead. For instance:
|
match), use a regular `let`-binding inside a `loop` instead. For instance:
|
||||||
|
|
||||||
|
|
37
compiler/rustc_error_codes/src/error_codes/E0549.md
Normal file
37
compiler/rustc_error_codes/src/error_codes/E0549.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
|
||||||
|
attribute.
|
||||||
|
|
||||||
|
Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,E0549
|
||||||
|
#![feature(staged_api)]
|
||||||
|
#![stable(since = "1.0.0", feature = "test")]
|
||||||
|
|
||||||
|
#[rustc_deprecated(
|
||||||
|
since = "1.0.1",
|
||||||
|
reason = "explanation for deprecation"
|
||||||
|
)] // invalid
|
||||||
|
fn _deprecated_fn() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this issue, you need to add also an attribute `stable` or `unstable`.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
#![feature(staged_api)]
|
||||||
|
#![stable(since = "1.0.0", feature = "test")]
|
||||||
|
|
||||||
|
#[stable(since = "1.0.0", feature = "test")]
|
||||||
|
#[rustc_deprecated(
|
||||||
|
since = "1.0.1",
|
||||||
|
reason = "explanation for deprecation"
|
||||||
|
)] // ok!
|
||||||
|
fn _deprecated_fn() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
|
||||||
|
of the Book and the [Stability attributes][stability-attributes] section of the
|
||||||
|
Rustc Dev Guide for more details.
|
||||||
|
|
||||||
|
[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
|
||||||
|
[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
|
|
@ -1713,7 +1713,18 @@ impl EmitterWriter {
|
||||||
let max_line_num_len = if self.ui_testing {
|
let max_line_num_len = if self.ui_testing {
|
||||||
ANONYMIZED_LINE_NUM.len()
|
ANONYMIZED_LINE_NUM.len()
|
||||||
} else {
|
} else {
|
||||||
self.get_max_line_num(span, children).to_string().len()
|
// Instead of using .to_string().len(), we iteratively count the
|
||||||
|
// number of digits to avoid allocation. This strategy has sizable
|
||||||
|
// performance gains over the old string strategy.
|
||||||
|
let mut n = self.get_max_line_num(span, children);
|
||||||
|
let mut num_digits = 0;
|
||||||
|
loop {
|
||||||
|
num_digits += 1;
|
||||||
|
n /= 10;
|
||||||
|
if n == 0 {
|
||||||
|
break num_digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
|
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
|
||||||
|
|
|
@ -242,6 +242,7 @@ language_item_table! {
|
||||||
|
|
||||||
Deref, sym::deref, deref_trait, Target::Trait;
|
Deref, sym::deref, deref_trait, Target::Trait;
|
||||||
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
|
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
|
||||||
|
DerefTarget, sym::deref_target, deref_target, Target::AssocTy;
|
||||||
Receiver, sym::receiver, receiver_trait, Target::Trait;
|
Receiver, sym::receiver, receiver_trait, Target::Trait;
|
||||||
|
|
||||||
Fn, kw::Fn, fn_trait, Target::Trait;
|
Fn, kw::Fn, fn_trait, Target::Trait;
|
||||||
|
|
|
@ -109,7 +109,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
|
||||||
debug!("read_file: {}", message);
|
debug!("read_file: {}", message);
|
||||||
|
|
||||||
if report_incremental_info {
|
if report_incremental_info {
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] ignoring cache artifact `{}`: {}",
|
"[incremental] ignoring cache artifact `{}`: {}",
|
||||||
file.file_name().unwrap().to_string_lossy(),
|
file.file_name().unwrap().to_string_lossy(),
|
||||||
message
|
message
|
||||||
|
|
|
@ -440,12 +440,12 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
|
||||||
}
|
}
|
||||||
|
|
||||||
if sess.opts.debugging_opts.incremental_info {
|
if sess.opts.debugging_opts.incremental_info {
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] session directory: \
|
"[incremental] session directory: \
|
||||||
{} files hard-linked",
|
{} files hard-linked",
|
||||||
files_linked
|
files_linked
|
||||||
);
|
);
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] session directory: \
|
"[incremental] session directory: \
|
||||||
{} files copied",
|
{} files copied",
|
||||||
files_copied
|
files_copied
|
||||||
|
|
|
@ -170,7 +170,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
||||||
|
|
||||||
if prev_commandline_args_hash != expected_hash {
|
if prev_commandline_args_hash != expected_hash {
|
||||||
if report_incremental_info {
|
if report_incremental_info {
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] completely ignoring cache because of \
|
"[incremental] completely ignoring cache because of \
|
||||||
differing commandline arguments"
|
differing commandline arguments"
|
||||||
);
|
);
|
||||||
|
|
|
@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
|
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
|
||||||
fn to_trace(
|
fn to_trace(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
a: Self,
|
a: Self,
|
||||||
|
@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||||
where
|
where
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
|
let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
|
||||||
Trace { at: self, trace, a_is_expected }
|
Trace { at: self, trace, a_is_expected }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(
|
||||||
|
_: TyCtxt<'tcx>,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
a: Self,
|
a: Self,
|
||||||
|
@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(
|
||||||
|
_: TyCtxt<'tcx>,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
a: Self,
|
a: Self,
|
||||||
|
@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(
|
||||||
|
_: TyCtxt<'tcx>,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
a: Self,
|
a: Self,
|
||||||
|
@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(
|
||||||
|
_: TyCtxt<'tcx>,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
a: Self,
|
a: Self,
|
||||||
|
@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
|
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
|
||||||
fn to_trace(
|
fn to_trace(
|
||||||
|
_: TyCtxt<'tcx>,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
a: Self,
|
a: Self,
|
||||||
|
@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
|
||||||
|
fn to_trace(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
|
a_is_expected: bool,
|
||||||
|
a: Self,
|
||||||
|
b: Self,
|
||||||
|
) -> TypeTrace<'tcx> {
|
||||||
|
let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
|
||||||
|
let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
|
||||||
|
TypeTrace {
|
||||||
|
cause: cause.clone(),
|
||||||
|
values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -64,8 +64,8 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if sess.opts.debugging_opts.input_stats {
|
if sess.opts.debugging_opts.input_stats {
|
||||||
println!("Lines of code: {}", sess.source_map().count_lines());
|
eprintln!("Lines of code: {}", sess.source_map().count_lines());
|
||||||
println!("Pre-expansion node count: {}", count_nodes(&krate));
|
eprintln!("Pre-expansion node count: {}", count_nodes(&krate));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref s) = sess.opts.debugging_opts.show_span {
|
if let Some(ref s) = sess.opts.debugging_opts.show_span {
|
||||||
|
@ -394,7 +394,7 @@ fn configure_and_expand_inner<'a>(
|
||||||
// Done with macro expansion!
|
// Done with macro expansion!
|
||||||
|
|
||||||
if sess.opts.debugging_opts.input_stats {
|
if sess.opts.debugging_opts.input_stats {
|
||||||
println!("Post-expansion node count: {}", count_nodes(&krate));
|
eprintln!("Post-expansion node count: {}", count_nodes(&krate));
|
||||||
}
|
}
|
||||||
|
|
||||||
if sess.opts.debugging_opts.hir_stats {
|
if sess.opts.debugging_opts.hir_stats {
|
||||||
|
|
|
@ -1815,7 +1815,7 @@ declare_lint! {
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `irrefutable_let_patterns` lint detects detects [irrefutable
|
/// The `irrefutable_let_patterns` lint detects detects [irrefutable
|
||||||
/// patterns] in [if-let] and [while-let] statements.
|
/// patterns] in [`if let`] and [`while let`] statements.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -1832,7 +1832,7 @@ declare_lint! {
|
||||||
/// ### Explanation
|
/// ### Explanation
|
||||||
///
|
///
|
||||||
/// There usually isn't a reason to have an irrefutable pattern in an
|
/// There usually isn't a reason to have an irrefutable pattern in an
|
||||||
/// if-let or while-let statement, because the pattern will always match
|
/// `if let` or `while let` statement, because the pattern will always match
|
||||||
/// successfully. A [`let`] or [`loop`] statement will suffice. However,
|
/// successfully. A [`let`] or [`loop`] statement will suffice. However,
|
||||||
/// when generating code with a macro, forbidding irrefutable patterns
|
/// when generating code with a macro, forbidding irrefutable patterns
|
||||||
/// would require awkward workarounds in situations where the macro
|
/// would require awkward workarounds in situations where the macro
|
||||||
|
@ -1843,14 +1843,14 @@ declare_lint! {
|
||||||
/// See [RFC 2086] for more details.
|
/// See [RFC 2086] for more details.
|
||||||
///
|
///
|
||||||
/// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
|
/// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
|
||||||
/// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
|
/// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
|
||||||
/// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
|
/// [`while let`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
|
||||||
/// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
|
/// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
|
||||||
/// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
|
/// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
|
||||||
/// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
|
/// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
|
||||||
pub IRREFUTABLE_LET_PATTERNS,
|
pub IRREFUTABLE_LET_PATTERNS,
|
||||||
Warn,
|
Warn,
|
||||||
"detects irrefutable patterns in if-let and while-let statements"
|
"detects irrefutable patterns in `if let` and `while let` statements"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
|
|
@ -695,23 +695,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("metadata stats:");
|
eprintln!("metadata stats:");
|
||||||
println!(" dep bytes: {}", dep_bytes);
|
eprintln!(" dep bytes: {}", dep_bytes);
|
||||||
println!(" lib feature bytes: {}", lib_feature_bytes);
|
eprintln!(" lib feature bytes: {}", lib_feature_bytes);
|
||||||
println!(" lang item bytes: {}", lang_item_bytes);
|
eprintln!(" lang item bytes: {}", lang_item_bytes);
|
||||||
println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
|
eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
|
||||||
println!(" native bytes: {}", native_lib_bytes);
|
eprintln!(" native bytes: {}", native_lib_bytes);
|
||||||
println!(" source_map bytes: {}", source_map_bytes);
|
eprintln!(" source_map bytes: {}", source_map_bytes);
|
||||||
println!(" impl bytes: {}", impl_bytes);
|
eprintln!(" impl bytes: {}", impl_bytes);
|
||||||
println!(" exp. symbols bytes: {}", exported_symbols_bytes);
|
eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes);
|
||||||
println!(" def-path table bytes: {}", def_path_table_bytes);
|
eprintln!(" def-path table bytes: {}", def_path_table_bytes);
|
||||||
println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
|
eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
|
||||||
println!(" mir bytes: {}", mir_bytes);
|
eprintln!(" mir bytes: {}", mir_bytes);
|
||||||
println!(" item bytes: {}", item_bytes);
|
eprintln!(" item bytes: {}", item_bytes);
|
||||||
println!(" table bytes: {}", tables_bytes);
|
eprintln!(" table bytes: {}", tables_bytes);
|
||||||
println!(" hygiene bytes: {}", hygiene_bytes);
|
eprintln!(" hygiene bytes: {}", hygiene_bytes);
|
||||||
println!(" zero bytes: {}", zero_bytes);
|
eprintln!(" zero bytes: {}", zero_bytes);
|
||||||
println!(" total bytes: {}", total_bytes);
|
eprintln!(" total bytes: {}", total_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
root
|
root
|
||||||
|
|
|
@ -75,6 +75,36 @@ impl<'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn suggest_arbitrary_trait_bound(
|
||||||
|
generics: &hir::Generics<'_>,
|
||||||
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
param_name: &str,
|
||||||
|
constraint: &str,
|
||||||
|
) -> bool {
|
||||||
|
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
|
||||||
|
match (param, param_name) {
|
||||||
|
(Some(_), "Self") => return false,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
// Suggest a where clause bound for a non-type paremeter.
|
||||||
|
let (action, prefix) = if generics.where_clause.predicates.is_empty() {
|
||||||
|
("introducing a", " where ")
|
||||||
|
} else {
|
||||||
|
("extending the", ", ")
|
||||||
|
};
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
generics.where_clause.tail_span_for_suggestion(),
|
||||||
|
&format!(
|
||||||
|
"consider {} `where` bound, but there might be an alternative better way to express \
|
||||||
|
this requirement",
|
||||||
|
action,
|
||||||
|
),
|
||||||
|
format!("{}{}: {}", prefix, param_name, constraint),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Suggest restricting a type param with a new bound.
|
/// Suggest restricting a type param with a new bound.
|
||||||
pub fn suggest_constraining_type_param(
|
pub fn suggest_constraining_type_param(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use crate::ty::diagnostics::suggest_constraining_type_param;
|
use crate::ty::diagnostics::suggest_constraining_type_param;
|
||||||
|
use crate::ty::print::{FmtPrinter, Printer};
|
||||||
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
|
||||||
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
|
||||||
use rustc_errors::{pluralize, DiagnosticBuilder};
|
use rustc_errors::{pluralize, DiagnosticBuilder};
|
||||||
|
@ -405,14 +406,22 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
{
|
{
|
||||||
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
||||||
// FIXME: extract this logic for use in other diagnostics.
|
// FIXME: extract this logic for use in other diagnostics.
|
||||||
let trait_ref = proj.trait_ref(self);
|
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
|
||||||
let path =
|
let path =
|
||||||
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
|
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
|
||||||
let item_name = self.item_name(proj.item_def_id);
|
let item_name = self.item_name(proj.item_def_id);
|
||||||
|
let item_args = self.format_generic_args(assoc_substs);
|
||||||
|
|
||||||
let path = if path.ends_with('>') {
|
let path = if path.ends_with('>') {
|
||||||
format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
|
format!(
|
||||||
|
"{}, {}{} = {}>",
|
||||||
|
&path[..path.len() - 1],
|
||||||
|
item_name,
|
||||||
|
item_args,
|
||||||
|
p
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{}<{} = {}>", path, item_name, p)
|
format!("{}<{}{} = {}>", path, item_name, item_args, p)
|
||||||
};
|
};
|
||||||
note = !suggest_constraining_type_param(
|
note = !suggest_constraining_type_param(
|
||||||
self,
|
self,
|
||||||
|
@ -561,7 +570,7 @@ impl<T> Trait<T> for X {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let assoc = self.associated_item(proj_ty.item_def_id);
|
let assoc = self.associated_item(proj_ty.item_def_id);
|
||||||
let trait_ref = proj_ty.trait_ref(self);
|
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
|
||||||
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
|
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
|
||||||
if let Some(hir_generics) = item.generics() {
|
if let Some(hir_generics) = item.generics() {
|
||||||
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
||||||
|
@ -595,6 +604,7 @@ impl<T> Trait<T> for X {
|
||||||
&trait_ref,
|
&trait_ref,
|
||||||
pred.bounds,
|
pred.bounds,
|
||||||
&assoc,
|
&assoc,
|
||||||
|
assoc_substs,
|
||||||
ty,
|
ty,
|
||||||
msg,
|
msg,
|
||||||
) {
|
) {
|
||||||
|
@ -612,6 +622,7 @@ impl<T> Trait<T> for X {
|
||||||
&trait_ref,
|
&trait_ref,
|
||||||
param.bounds,
|
param.bounds,
|
||||||
&assoc,
|
&assoc,
|
||||||
|
assoc_substs,
|
||||||
ty,
|
ty,
|
||||||
msg,
|
msg,
|
||||||
);
|
);
|
||||||
|
@ -697,6 +708,7 @@ impl<T> Trait<T> for X {
|
||||||
db,
|
db,
|
||||||
self.def_span(def_id),
|
self.def_span(def_id),
|
||||||
&assoc,
|
&assoc,
|
||||||
|
proj_ty.trait_ref_and_own_substs(self).1,
|
||||||
values.found,
|
values.found,
|
||||||
&msg,
|
&msg,
|
||||||
) {
|
) {
|
||||||
|
@ -861,6 +873,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
trait_ref: &ty::TraitRef<'tcx>,
|
trait_ref: &ty::TraitRef<'tcx>,
|
||||||
bounds: hir::GenericBounds<'_>,
|
bounds: hir::GenericBounds<'_>,
|
||||||
assoc: &ty::AssocItem,
|
assoc: &ty::AssocItem,
|
||||||
|
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -870,7 +883,12 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
// Relate the type param against `T` in `<A as T>::Foo`.
|
// Relate the type param against `T` in `<A as T>::Foo`.
|
||||||
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
|
ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
|
||||||
&& self.constrain_associated_type_structured_suggestion(
|
&& self.constrain_associated_type_structured_suggestion(
|
||||||
db, ptr.span, assoc, ty, msg,
|
db,
|
||||||
|
ptr.span,
|
||||||
|
assoc,
|
||||||
|
assoc_substs,
|
||||||
|
ty,
|
||||||
|
msg,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -884,6 +902,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
db: &mut DiagnosticBuilder<'_>,
|
db: &mut DiagnosticBuilder<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
assoc: &ty::AssocItem,
|
assoc: &ty::AssocItem,
|
||||||
|
assoc_substs: &[ty::GenericArg<'tcx>],
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -895,11 +914,20 @@ fn foo(&self) -> Self::T { String::new() }
|
||||||
let span = Span::new(pos, pos, span.ctxt());
|
let span = Span::new(pos, pos, span.ctxt());
|
||||||
(span, format!(", {} = {}", assoc.ident, ty))
|
(span, format!(", {} = {}", assoc.ident, ty))
|
||||||
} else {
|
} else {
|
||||||
(span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
|
let item_args = self.format_generic_args(assoc_substs);
|
||||||
|
(span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
|
||||||
};
|
};
|
||||||
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
|
||||||
|
let mut item_args = String::new();
|
||||||
|
FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
|
||||||
|
.path_generic_args(Ok, args)
|
||||||
|
.expect("could not write to `String`.");
|
||||||
|
item_args
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
|
||||||
self.skip_binder().projection_ty.item_def_id
|
self.skip_binder().projection_ty.item_def_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `DefId` of the trait of the associated item being projected.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
|
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
|
self.skip_binder().projection_ty.trait_def_id(tcx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
|
||||||
|
self.map_bound(|predicate| predicate.projection_ty.self_ty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [PolyTraitRef] required for this projection to be well formed.
|
||||||
|
/// Note that for generic associated types the predicates of the associated
|
||||||
|
/// type also need to be checked.
|
||||||
|
#[inline]
|
||||||
|
pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
|
||||||
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
// Note: unlike with `TraitRef::to_poly_trait_ref()`,
|
||||||
// `self.0.trait_ref` is permitted to have escaping regions.
|
// `self.0.trait_ref` is permitted to have escaping regions.
|
||||||
// This is because here `self` has a `Binder` and so does our
|
// This is because here `self` has a `Binder` and so does our
|
||||||
|
|
|
@ -67,29 +67,29 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
|
let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
|
||||||
let results: usize = queries.iter().map(|s| s.entry_count).sum();
|
let results: usize = queries.iter().map(|s| s.entry_count).sum();
|
||||||
println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
|
eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query_key_sizes = queries.clone();
|
let mut query_key_sizes = queries.clone();
|
||||||
query_key_sizes.sort_by_key(|q| q.key_size);
|
query_key_sizes.sort_by_key(|q| q.key_size);
|
||||||
println!("\nLarge query keys:");
|
eprintln!("\nLarge query keys:");
|
||||||
for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
|
for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
|
||||||
println!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
|
eprintln!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query_value_sizes = queries.clone();
|
let mut query_value_sizes = queries.clone();
|
||||||
query_value_sizes.sort_by_key(|q| q.value_size);
|
query_value_sizes.sort_by_key(|q| q.value_size);
|
||||||
println!("\nLarge query values:");
|
eprintln!("\nLarge query values:");
|
||||||
for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
|
for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
|
||||||
println!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
|
eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let mut query_cache_hits = queries.clone();
|
let mut query_cache_hits = queries.clone();
|
||||||
query_cache_hits.sort_by_key(|q| q.cache_hits);
|
query_cache_hits.sort_by_key(|q| q.cache_hits);
|
||||||
println!("\nQuery cache hits:");
|
eprintln!("\nQuery cache hits:");
|
||||||
for q in query_cache_hits.iter().rev() {
|
for q in query_cache_hits.iter().rev() {
|
||||||
println!(
|
eprintln!(
|
||||||
" {} - {} ({}%)",
|
" {} - {} ({}%)",
|
||||||
q.name,
|
q.name,
|
||||||
q.cache_hits,
|
q.cache_hits,
|
||||||
|
@ -100,19 +100,19 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
|
||||||
|
|
||||||
let mut query_value_count = queries.clone();
|
let mut query_value_count = queries.clone();
|
||||||
query_value_count.sort_by_key(|q| q.entry_count);
|
query_value_count.sort_by_key(|q| q.entry_count);
|
||||||
println!("\nQuery value count:");
|
eprintln!("\nQuery value count:");
|
||||||
for q in query_value_count.iter().rev() {
|
for q in query_value_count.iter().rev() {
|
||||||
println!(" {} - {}", q.name, q.entry_count);
|
eprintln!(" {} - {}", q.name, q.entry_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut def_id_density: Vec<_> =
|
let mut def_id_density: Vec<_> =
|
||||||
queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
|
queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
|
||||||
def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
|
def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
|
||||||
println!("\nLocal DefId density:");
|
eprintln!("\nLocal DefId density:");
|
||||||
let total = tcx.hir().definitions().def_index_count() as f64;
|
let total = tcx.hir().definitions().def_index_count() as f64;
|
||||||
for q in def_id_density.iter().rev() {
|
for q in def_id_density.iter().rev() {
|
||||||
let local = q.local_def_id_keys.unwrap();
|
let local = q.local_def_id_keys.unwrap();
|
||||||
println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
|
eprintln!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -1112,36 +1112,35 @@ pub struct ProjectionTy<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ProjectionTy<'tcx> {
|
impl<'tcx> ProjectionTy<'tcx> {
|
||||||
/// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
|
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
/// associated item named `item_name`.
|
tcx.associated_item(self.item_def_id).container.id()
|
||||||
pub fn from_ref_and_name(
|
}
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
|
||||||
item_name: Ident,
|
|
||||||
) -> ProjectionTy<'tcx> {
|
|
||||||
let item_def_id = tcx
|
|
||||||
.associated_items(trait_ref.def_id)
|
|
||||||
.find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
|
|
||||||
.unwrap()
|
|
||||||
.def_id;
|
|
||||||
|
|
||||||
ProjectionTy { substs: trait_ref.substs, item_def_id }
|
/// Extracts the underlying trait reference and own substs from this projection.
|
||||||
|
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||||
|
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
|
||||||
|
pub fn trait_ref_and_own_substs(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
||||||
|
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
||||||
|
let trait_generics = tcx.generics_of(def_id);
|
||||||
|
(
|
||||||
|
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
|
||||||
|
&self.substs[trait_generics.count()..],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts the underlying trait reference from this projection.
|
/// Extracts the underlying trait reference from this projection.
|
||||||
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
||||||
/// then this function would return a `T: Iterator` trait reference.
|
/// then this function would return a `T: Iterator` trait reference.
|
||||||
|
///
|
||||||
|
/// WARNING: This will drop the substs for generic associated types
|
||||||
|
/// consider calling [Self::trait_ref_and_own_substs] to get those
|
||||||
|
/// as well.
|
||||||
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
||||||
// FIXME: This method probably shouldn't exist at all, since it's not
|
let def_id = self.trait_def_id(tcx);
|
||||||
// clear what this method really intends to do. Be careful when
|
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
|
||||||
// using this method since the resulting TraitRef additionally
|
|
||||||
// contains the substs for the assoc_item, which strictly speaking
|
|
||||||
// is not correct
|
|
||||||
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
|
||||||
// Include substitutions for generic arguments of associated types
|
|
||||||
let assoc_item = tcx.associated_item(self.item_def_id);
|
|
||||||
let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
|
|
||||||
ty::TraitRef { def_id, substs: substs_assoc_item }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||||
|
@ -1493,12 +1492,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
|
||||||
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
||||||
/// then this function would return a `exists T. T: Iterator` existential trait
|
/// then this function would return a `exists T. T: Iterator` existential trait
|
||||||
/// reference.
|
/// reference.
|
||||||
pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
|
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
|
||||||
// FIXME(generic_associated_types): substs is the substs of the
|
|
||||||
// associated type, which should be truncated to get the correct substs
|
|
||||||
// for the trait.
|
|
||||||
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
let def_id = tcx.associated_item(self.item_def_id).container.id();
|
||||||
ty::ExistentialTraitRef { def_id, substs: self.substs }
|
let subst_count = tcx.generics_of(def_id).count() - 1;
|
||||||
|
let substs = tcx.intern_substs(&self.substs[..subst_count]);
|
||||||
|
ty::ExistentialTraitRef { def_id, substs }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_self_ty(
|
pub fn with_self_ty(
|
||||||
|
@ -1517,6 +1515,20 @@ impl<'tcx> ExistentialProjection<'tcx> {
|
||||||
ty: self.ty,
|
ty: self.ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn erase_self_ty(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
projection_predicate: ty::ProjectionPredicate<'tcx>,
|
||||||
|
) -> Self {
|
||||||
|
// Assert there is a Self.
|
||||||
|
projection_predicate.projection_ty.substs.type_at(0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
item_def_id: projection_predicate.projection_ty.item_def_id,
|
||||||
|
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
|
||||||
|
ty: projection_predicate.ty,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> PolyExistentialProjection<'tcx> {
|
impl<'tcx> PolyExistentialProjection<'tcx> {
|
||||||
|
|
|
@ -327,7 +327,7 @@ macro_rules! assert_successors {
|
||||||
fn test_covgraph_goto_switchint() {
|
fn test_covgraph_goto_switchint() {
|
||||||
let mir_body = goto_switchint();
|
let mir_body = goto_switchint();
|
||||||
if false {
|
if false {
|
||||||
println!("basic_blocks = {}", debug_basic_blocks(&mir_body));
|
eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
|
||||||
}
|
}
|
||||||
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||||
print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
|
print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
|
||||||
|
@ -583,11 +583,11 @@ fn test_find_loop_backedges_none() {
|
||||||
let mir_body = goto_switchint();
|
let mir_body = goto_switchint();
|
||||||
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||||
if false {
|
if false {
|
||||||
println!(
|
eprintln!(
|
||||||
"basic_coverage_blocks = {:?}",
|
"basic_coverage_blocks = {:?}",
|
||||||
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
|
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
println!("successors = {:?}", basic_coverage_blocks.successors);
|
eprintln!("successors = {:?}", basic_coverage_blocks.successors);
|
||||||
}
|
}
|
||||||
let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
|
let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -368,9 +368,9 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
|
||||||
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
|
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
|
||||||
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
|
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
|
||||||
let msg = match source {
|
let msg = match source {
|
||||||
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
|
hir::MatchSource::IfLetDesugar { .. } => "irrefutable `if let` pattern",
|
||||||
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
|
hir::MatchSource::WhileLetDesugar => "irrefutable `while let` pattern",
|
||||||
hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard",
|
hir::MatchSource::IfLetGuardDesugar => "irrefutable `if let` guard",
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
lint.build(msg).emit()
|
lint.build(msg).emit()
|
||||||
|
|
|
@ -513,7 +513,7 @@ impl<'a> Parser<'a> {
|
||||||
token::Ident(..) if this.is_mistaken_not_ident_negation() => {
|
token::Ident(..) if this.is_mistaken_not_ident_negation() => {
|
||||||
make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
|
make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
|
||||||
}
|
}
|
||||||
_ => return this.parse_dot_or_call_expr(Some(attrs.into())),
|
_ => return this.parse_dot_or_call_expr(Some(attrs)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ impl<'a> Parser<'a> {
|
||||||
self.mk_stmt(lo, StmtKind::Empty)
|
self.mk_stmt(lo, StmtKind::Empty)
|
||||||
} else if self.token != token::CloseDelim(token::Brace) {
|
} else if self.token != token::CloseDelim(token::Brace) {
|
||||||
// Remainder are line-expr stmts.
|
// Remainder are line-expr stmts.
|
||||||
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
|
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
|
||||||
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
|
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
|
||||||
} else {
|
} else {
|
||||||
self.error_outer_attrs(&attrs.take_for_recovery());
|
self.error_outer_attrs(&attrs.take_for_recovery());
|
||||||
|
@ -131,7 +131,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
|
let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
|
||||||
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
|
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?;
|
||||||
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
|
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
|
||||||
})?;
|
})?;
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -213,7 +213,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
|
fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
|
||||||
let local = self.parse_local(attrs.into())?;
|
let local = self.parse_local(attrs)?;
|
||||||
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
|
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl NonConstExpr {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"),
|
Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
|
||||||
|
|
||||||
// All other expressions are allowed.
|
// All other expressions are allowed.
|
||||||
Self::Loop(Loop | While | WhileLet)
|
Self::Loop(Loop | While | WhileLet)
|
||||||
|
|
|
@ -66,13 +66,13 @@ impl<'k> StatCollector<'k> {
|
||||||
|
|
||||||
let mut total_size = 0;
|
let mut total_size = 0;
|
||||||
|
|
||||||
println!("\n{}\n", title);
|
eprintln!("\n{}\n", title);
|
||||||
|
|
||||||
println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
|
eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
|
||||||
println!("----------------------------------------------------------------");
|
eprintln!("----------------------------------------------------------------");
|
||||||
|
|
||||||
for (label, data) in stats {
|
for (label, data) in stats {
|
||||||
println!(
|
eprintln!(
|
||||||
"{:<18}{:>18}{:>14}{:>14}",
|
"{:<18}{:>18}{:>14}{:>14}",
|
||||||
label,
|
label,
|
||||||
to_readable_str(data.count * data.size),
|
to_readable_str(data.count * data.size),
|
||||||
|
@ -82,8 +82,8 @@ impl<'k> StatCollector<'k> {
|
||||||
|
|
||||||
total_size += data.count * data.size;
|
total_size += data.count * data.size;
|
||||||
}
|
}
|
||||||
println!("----------------------------------------------------------------");
|
eprintln!("----------------------------------------------------------------");
|
||||||
println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
|
eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,12 @@ trait DefIdVisitor<'tcx> {
|
||||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
self.skeleton().visit_trait(trait_ref)
|
self.skeleton().visit_trait(trait_ref)
|
||||||
}
|
}
|
||||||
|
fn visit_projection_ty(
|
||||||
|
&mut self,
|
||||||
|
projection: ty::ProjectionTy<'tcx>,
|
||||||
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
self.skeleton().visit_projection_ty(projection)
|
||||||
|
}
|
||||||
fn visit_predicates(
|
fn visit_predicates(
|
||||||
&mut self,
|
&mut self,
|
||||||
predicates: ty::GenericPredicates<'tcx>,
|
predicates: ty::GenericPredicates<'tcx>,
|
||||||
|
@ -101,6 +107,20 @@ where
|
||||||
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
|
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_projection_ty(
|
||||||
|
&mut self,
|
||||||
|
projection: ty::ProjectionTy<'tcx>,
|
||||||
|
) -> ControlFlow<V::BreakTy> {
|
||||||
|
let (trait_ref, assoc_substs) =
|
||||||
|
projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
|
||||||
|
self.visit_trait(trait_ref)?;
|
||||||
|
if self.def_id_visitor.shallow() {
|
||||||
|
ControlFlow::CONTINUE
|
||||||
|
} else {
|
||||||
|
assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
|
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
|
||||||
match predicate.kind().skip_binder() {
|
match predicate.kind().skip_binder() {
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
|
ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
|
||||||
|
@ -108,7 +128,7 @@ where
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
||||||
ty.visit_with(self)?;
|
ty.visit_with(self)?;
|
||||||
self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
|
self.visit_projection_ty(projection_ty)
|
||||||
}
|
}
|
||||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
|
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
|
||||||
ty.visit_with(self)
|
ty.visit_with(self)
|
||||||
|
@ -197,7 +217,7 @@ where
|
||||||
return ControlFlow::CONTINUE;
|
return ControlFlow::CONTINUE;
|
||||||
}
|
}
|
||||||
// This will also visit substs if necessary, so we don't need to recurse.
|
// This will also visit substs if necessary, so we don't need to recurse.
|
||||||
return self.visit_trait(proj.trait_ref(tcx));
|
return self.visit_projection_ty(proj);
|
||||||
}
|
}
|
||||||
ty::Dynamic(predicates, ..) => {
|
ty::Dynamic(predicates, ..) => {
|
||||||
// All traits in the list are considered the "primary" part of the type
|
// All traits in the list are considered the "primary" part of the type
|
||||||
|
@ -1203,10 +1223,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (poly_predicate, _) in bounds.projection_bounds {
|
for (poly_predicate, _) in bounds.projection_bounds {
|
||||||
let tcx = self.tcx;
|
|
||||||
if self.visit(poly_predicate.skip_binder().ty).is_break()
|
if self.visit(poly_predicate.skip_binder().ty).is_break()
|
||||||
|| self
|
|| self
|
||||||
.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
|
.visit_projection_ty(poly_predicate.skip_binder().projection_ty)
|
||||||
.is_break()
|
.is_break()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -964,29 +964,29 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
----------------------------------------------\
|
----------------------------------------------\
|
||||||
------------";
|
------------";
|
||||||
|
|
||||||
println!("[incremental]");
|
eprintln!("[incremental]");
|
||||||
println!("[incremental] DepGraph Statistics");
|
eprintln!("[incremental] DepGraph Statistics");
|
||||||
println!("{}", SEPARATOR);
|
eprintln!("{}", SEPARATOR);
|
||||||
println!("[incremental]");
|
eprintln!("[incremental]");
|
||||||
println!("[incremental] Total Node Count: {}", total_node_count);
|
eprintln!("[incremental] Total Node Count: {}", total_node_count);
|
||||||
println!("[incremental] Total Edge Count: {}", total_edge_count);
|
eprintln!("[incremental] Total Edge Count: {}", total_edge_count);
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let total_edge_reads = current.total_read_count.load(Relaxed);
|
let total_edge_reads = current.total_read_count.load(Relaxed);
|
||||||
let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
|
let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
|
||||||
|
|
||||||
println!("[incremental] Total Edge Reads: {}", total_edge_reads);
|
eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads);
|
||||||
println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
|
eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("[incremental]");
|
eprintln!("[incremental]");
|
||||||
|
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] {:<36}| {:<17}| {:<12}| {:<17}|",
|
"[incremental] {:<36}| {:<17}| {:<12}| {:<17}|",
|
||||||
"Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
|
"Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
|
||||||
);
|
);
|
||||||
|
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] -------------------------------------\
|
"[incremental] -------------------------------------\
|
||||||
|------------------\
|
|------------------\
|
||||||
|-------------\
|
|-------------\
|
||||||
|
@ -997,7 +997,7 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
|
let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
|
||||||
let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
|
let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
|
||||||
|
|
||||||
println!(
|
eprintln!(
|
||||||
"[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
|
"[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
|
||||||
format!("{:?}", stat.kind),
|
format!("{:?}", stat.kind),
|
||||||
node_kind_ratio,
|
node_kind_ratio,
|
||||||
|
@ -1006,8 +1006,8 @@ impl<K: DepKind> DepGraph<K> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", SEPARATOR);
|
eprintln!("{}", SEPARATOR);
|
||||||
println!("[incremental]");
|
eprintln!("[incremental]");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_virtual_depnode_index(&self) -> DepNodeIndex {
|
fn next_virtual_depnode_index(&self) -> DepNodeIndex {
|
||||||
|
|
|
@ -959,19 +959,19 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_perf_stats(&self) {
|
pub fn print_perf_stats(&self) {
|
||||||
println!(
|
eprintln!(
|
||||||
"Total time spent computing symbol hashes: {}",
|
"Total time spent computing symbol hashes: {}",
|
||||||
duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
|
duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
|
||||||
);
|
);
|
||||||
println!(
|
eprintln!(
|
||||||
"Total queries canonicalized: {}",
|
"Total queries canonicalized: {}",
|
||||||
self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
|
self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
|
||||||
);
|
);
|
||||||
println!(
|
eprintln!(
|
||||||
"normalize_generic_arg_after_erasing_regions: {}",
|
"normalize_generic_arg_after_erasing_regions: {}",
|
||||||
self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
|
self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
|
||||||
);
|
);
|
||||||
println!(
|
eprintln!(
|
||||||
"normalize_projection_ty: {}",
|
"normalize_projection_ty: {}",
|
||||||
self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
|
self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
|
||||||
);
|
);
|
||||||
|
|
|
@ -243,7 +243,7 @@ impl SourceMapExtension for SourceMap {
|
||||||
substring: &str,
|
substring: &str,
|
||||||
n: usize,
|
n: usize,
|
||||||
) -> Span {
|
) -> Span {
|
||||||
println!(
|
eprintln!(
|
||||||
"span_substr(file={:?}/{:?}, substring={:?}, n={})",
|
"span_substr(file={:?}/{:?}, substring={:?}, n={})",
|
||||||
file.name, file.start_pos, substring, n
|
file.name, file.start_pos, substring, n
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,7 +6,6 @@ use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
|
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
|
||||||
use rustc_middle::ty::{ToPredicate, TypeFoldable};
|
use rustc_middle::ty::{ToPredicate, TypeFoldable};
|
||||||
use rustc_session::DiagnosticMessageId;
|
use rustc_session::DiagnosticMessageId;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -146,11 +145,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
||||||
let normalized_ty = fulfillcx.normalize_projection_type(
|
let normalized_ty = fulfillcx.normalize_projection_type(
|
||||||
&self.infcx,
|
&self.infcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
ty::ProjectionTy::from_ref_and_name(
|
ty::ProjectionTy {
|
||||||
tcx,
|
item_def_id: tcx.lang_items().deref_target()?,
|
||||||
trait_ref,
|
substs: trait_ref.substs,
|
||||||
Ident::with_dummy_span(sym::Target),
|
},
|
||||||
),
|
|
||||||
cause,
|
cause,
|
||||||
);
|
);
|
||||||
if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
|
if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
|
||||||
|
|
|
@ -72,17 +72,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
||||||
// We were unable to unify the abstract constant with
|
// We were unable to unify the abstract constant with
|
||||||
// a constant found in the caller bounds, there are
|
// a constant found in the caller bounds, there are
|
||||||
// now three possible cases here.
|
// now three possible cases here.
|
||||||
//
|
|
||||||
// - The substs are concrete enough that we can simply
|
|
||||||
// try and evaluate the given constant.
|
|
||||||
// - The abstract const still references an inference
|
|
||||||
// variable, in this case we return `TooGeneric`.
|
|
||||||
// - The abstract const references a generic parameter,
|
|
||||||
// this means that we emit an error here.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum FailureKind {
|
enum FailureKind {
|
||||||
|
/// The abstract const still references an inference
|
||||||
|
/// variable, in this case we return `TooGeneric`.
|
||||||
MentionsInfer,
|
MentionsInfer,
|
||||||
|
/// The abstract const references a generic parameter,
|
||||||
|
/// this means that we emit an error here.
|
||||||
MentionsParam,
|
MentionsParam,
|
||||||
|
/// The substs are concrete enough that we can simply
|
||||||
|
/// try and evaluate the given constant.
|
||||||
Concrete,
|
Concrete,
|
||||||
}
|
}
|
||||||
let mut failure_kind = FailureKind::Concrete;
|
let mut failure_kind = FailureKind::Concrete;
|
||||||
|
|
|
@ -1589,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
|
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Projection(data) => {
|
ty::PredicateKind::Projection(data) => {
|
||||||
let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
|
let self_ty = data.projection_ty.self_ty();
|
||||||
let self_ty = trait_ref.skip_binder().self_ty();
|
|
||||||
let ty = data.ty;
|
let ty = data.ty;
|
||||||
if predicate.references_error() {
|
if predicate.references_error() {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -200,22 +200,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
if let Some(def) = aty.ty_adt_def() {
|
if let Some(def) = aty.ty_adt_def() {
|
||||||
// We also want to be able to select the array's type's original
|
// We also want to be able to select the array's type's original
|
||||||
// signature with no type arguments resolved
|
// signature with no type arguments resolved
|
||||||
flags.push((
|
let type_string = self.tcx.type_of(def.did).to_string();
|
||||||
sym::_Self,
|
flags.push((sym::_Self, Some(format!("[{}]", type_string))));
|
||||||
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
|
|
||||||
));
|
let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
|
||||||
let tcx = self.tcx;
|
let string = match len {
|
||||||
if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
|
Some(n) => format!("[{}; {}]", type_string, n),
|
||||||
flags.push((
|
None => format!("[{}; _]", type_string),
|
||||||
sym::_Self,
|
};
|
||||||
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
|
flags.push((sym::_Self, Some(string)));
|
||||||
));
|
|
||||||
} else {
|
|
||||||
flags.push((
|
|
||||||
sym::_Self,
|
|
||||||
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let ty::Dynamic(traits, _) = self_ty.kind() {
|
if let ty::Dynamic(traits, _) = self_ty.kind() {
|
||||||
|
|
|
@ -17,8 +17,8 @@ use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
|
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
|
||||||
TyCtxt, TypeFoldable, WithConstness,
|
Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
|
@ -334,7 +334,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
let (param_ty, projection) = match self_ty.kind() {
|
let (param_ty, projection) = match self_ty.kind() {
|
||||||
ty::Param(_) => (true, None),
|
ty::Param(_) => (true, None),
|
||||||
ty::Projection(projection) => (false, Some(projection)),
|
ty::Projection(projection) => (false, Some(projection)),
|
||||||
_ => return,
|
_ => (false, None),
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
|
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
|
||||||
|
@ -453,6 +453,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hir::Node::Item(hir::Item {
|
||||||
|
kind:
|
||||||
|
hir::ItemKind::Struct(_, generics)
|
||||||
|
| hir::ItemKind::Enum(_, generics)
|
||||||
|
| hir::ItemKind::Union(_, generics)
|
||||||
|
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||||
|
| hir::ItemKind::Impl(hir::Impl { generics, .. })
|
||||||
|
| hir::ItemKind::Fn(_, generics, _)
|
||||||
|
| hir::ItemKind::TyAlias(_, generics)
|
||||||
|
| hir::ItemKind::TraitAlias(generics, _)
|
||||||
|
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
|
||||||
|
..
|
||||||
|
}) if !param_ty => {
|
||||||
|
// Missing generic type parameter bound.
|
||||||
|
let param_name = self_ty.to_string();
|
||||||
|
let constraint = trait_ref.print_only_trait_path().to_string();
|
||||||
|
if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
hir::Node::Crate(..) => return,
|
hir::Node::Crate(..) => return,
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use rustc_errors::ErrorReported;
|
||||||
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
|
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::ToPredicate;
|
use rustc_middle::ty::ToPredicate;
|
||||||
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
|
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -633,9 +634,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||||
// only reason we can fail to make progress on
|
// only reason we can fail to make progress on
|
||||||
// trait selection is because we don't have enough
|
// trait selection is because we don't have enough
|
||||||
// information about the types in the trait.
|
// information about the types in the trait.
|
||||||
*stalled_on = trait_ref_infer_vars(
|
*stalled_on = substs_infer_vars(
|
||||||
self.selcx,
|
self.selcx,
|
||||||
trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
|
trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
|
||||||
);
|
);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -663,9 +664,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||||
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
|
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
|
||||||
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
|
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
|
||||||
Ok(Ok(None)) => {
|
Ok(Ok(None)) => {
|
||||||
*stalled_on = trait_ref_infer_vars(
|
*stalled_on = substs_infer_vars(
|
||||||
self.selcx,
|
self.selcx,
|
||||||
project_obligation.predicate.to_poly_trait_ref(tcx),
|
project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
|
||||||
);
|
);
|
||||||
ProcessResult::Unchanged
|
ProcessResult::Unchanged
|
||||||
}
|
}
|
||||||
|
@ -678,16 +679,15 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the set of inference variables contained in a trait ref.
|
/// Returns the set of inference variables contained in `substs`.
|
||||||
fn trait_ref_infer_vars<'a, 'tcx>(
|
fn substs_infer_vars<'a, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'a, 'tcx>,
|
selcx: &mut SelectionContext<'a, 'tcx>,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
substs: ty::Binder<SubstsRef<'tcx>>,
|
||||||
) -> Vec<TyOrConstInferVar<'tcx>> {
|
) -> Vec<TyOrConstInferVar<'tcx>> {
|
||||||
selcx
|
selcx
|
||||||
.infcx()
|
.infcx()
|
||||||
.resolve_vars_if_possible(trait_ref)
|
.resolve_vars_if_possible(substs)
|
||||||
.skip_binder()
|
.skip_binder() // ok because this check doesn't care about regions
|
||||||
.substs
|
|
||||||
.iter()
|
.iter()
|
||||||
// FIXME(eddyb) try using `skip_current_subtree` to skip everything that
|
// FIXME(eddyb) try using `skip_current_subtree` to skip everything that
|
||||||
// doesn't contain inference variables, not just the outermost level.
|
// doesn't contain inference variables, not just the outermost level.
|
||||||
|
|
|
@ -292,11 +292,7 @@ fn predicate_references_self(
|
||||||
//
|
//
|
||||||
// This is ALT2 in issue #56288, see that for discussion of the
|
// This is ALT2 in issue #56288, see that for discussion of the
|
||||||
// possible alternatives.
|
// possible alternatives.
|
||||||
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
|
if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
|
||||||
Some(sp)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::PredicateKind::WellFormed(..)
|
ty::PredicateKind::WellFormed(..)
|
||||||
| ty::PredicateKind::ObjectSafe(..)
|
| ty::PredicateKind::ObjectSafe(..)
|
||||||
|
|
|
@ -741,11 +741,7 @@ fn project_type<'cx, 'tcx>(
|
||||||
return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
|
return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
|
||||||
}
|
}
|
||||||
|
|
||||||
let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
|
if obligation.predicate.references_error() {
|
||||||
|
|
||||||
debug!(?obligation_trait_ref);
|
|
||||||
|
|
||||||
if obligation_trait_ref.references_error() {
|
|
||||||
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
|
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,19 +750,19 @@ fn project_type<'cx, 'tcx>(
|
||||||
// Make sure that the following procedures are kept in order. ParamEnv
|
// Make sure that the following procedures are kept in order. ParamEnv
|
||||||
// needs to be first because it has highest priority, and Select checks
|
// needs to be first because it has highest priority, and Select checks
|
||||||
// the return value of push_candidate which assumes it's ran at last.
|
// the return value of push_candidate which assumes it's ran at last.
|
||||||
assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
assemble_candidates_from_param_env(selcx, obligation, &mut candidates);
|
||||||
|
|
||||||
assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
assemble_candidates_from_trait_def(selcx, obligation, &mut candidates);
|
||||||
|
|
||||||
assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
|
||||||
|
|
||||||
if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
|
if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
|
||||||
// Avoid normalization cycle from selection (see
|
// Avoid normalization cycle from selection (see
|
||||||
// `assemble_candidates_from_object_ty`).
|
// `assemble_candidates_from_object_ty`).
|
||||||
// FIXME(lazy_normalization): Lazy normalization should save us from
|
// FIXME(lazy_normalization): Lazy normalization should save us from
|
||||||
// having to do special case this.
|
// having to special case this.
|
||||||
} else {
|
} else {
|
||||||
assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
assemble_candidates_from_impls(selcx, obligation, &mut candidates);
|
||||||
};
|
};
|
||||||
|
|
||||||
match candidates {
|
match candidates {
|
||||||
|
@ -792,14 +788,12 @@ fn project_type<'cx, 'tcx>(
|
||||||
fn assemble_candidates_from_param_env<'cx, 'tcx>(
|
fn assemble_candidates_from_param_env<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("assemble_candidates_from_param_env(..)");
|
debug!("assemble_candidates_from_param_env(..)");
|
||||||
assemble_candidates_from_predicates(
|
assemble_candidates_from_predicates(
|
||||||
selcx,
|
selcx,
|
||||||
obligation,
|
obligation,
|
||||||
obligation_trait_ref,
|
|
||||||
candidate_set,
|
candidate_set,
|
||||||
ProjectionTyCandidate::ParamEnv,
|
ProjectionTyCandidate::ParamEnv,
|
||||||
obligation.param_env.caller_bounds().iter(),
|
obligation.param_env.caller_bounds().iter(),
|
||||||
|
@ -820,7 +814,6 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
|
||||||
fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("assemble_candidates_from_trait_def(..)");
|
debug!("assemble_candidates_from_trait_def(..)");
|
||||||
|
@ -828,7 +821,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||||
let tcx = selcx.tcx();
|
let tcx = selcx.tcx();
|
||||||
// Check whether the self-type is itself a projection.
|
// Check whether the self-type is itself a projection.
|
||||||
// If so, extract what we know from the trait and try to come up with a good answer.
|
// If so, extract what we know from the trait and try to come up with a good answer.
|
||||||
let bounds = match *obligation_trait_ref.self_ty().kind() {
|
let bounds = match *obligation.predicate.self_ty().kind() {
|
||||||
ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
|
ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
|
||||||
ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
|
ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
|
||||||
ty::Infer(ty::TyVar(_)) => {
|
ty::Infer(ty::TyVar(_)) => {
|
||||||
|
@ -843,7 +836,6 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||||
assemble_candidates_from_predicates(
|
assemble_candidates_from_predicates(
|
||||||
selcx,
|
selcx,
|
||||||
obligation,
|
obligation,
|
||||||
obligation_trait_ref,
|
|
||||||
candidate_set,
|
candidate_set,
|
||||||
ProjectionTyCandidate::TraitDef,
|
ProjectionTyCandidate::TraitDef,
|
||||||
bounds.iter(),
|
bounds.iter(),
|
||||||
|
@ -863,14 +855,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||||
fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("assemble_candidates_from_object_ty(..)");
|
debug!("assemble_candidates_from_object_ty(..)");
|
||||||
|
|
||||||
let tcx = selcx.tcx();
|
let tcx = selcx.tcx();
|
||||||
|
|
||||||
let self_ty = obligation_trait_ref.self_ty();
|
let self_ty = obligation.predicate.self_ty();
|
||||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||||
let data = match object_ty.kind() {
|
let data = match object_ty.kind() {
|
||||||
ty::Dynamic(data, ..) => data,
|
ty::Dynamic(data, ..) => data,
|
||||||
|
@ -890,7 +881,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||||
assemble_candidates_from_predicates(
|
assemble_candidates_from_predicates(
|
||||||
selcx,
|
selcx,
|
||||||
obligation,
|
obligation,
|
||||||
obligation_trait_ref,
|
|
||||||
candidate_set,
|
candidate_set,
|
||||||
ProjectionTyCandidate::Object,
|
ProjectionTyCandidate::Object,
|
||||||
env_predicates,
|
env_predicates,
|
||||||
|
@ -901,7 +891,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||||
fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
||||||
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||||
|
@ -921,8 +910,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
&& infcx.probe(|_| {
|
&& infcx.probe(|_| {
|
||||||
selcx.match_projection_projections(
|
selcx.match_projection_projections(
|
||||||
obligation,
|
obligation,
|
||||||
obligation_trait_ref,
|
data,
|
||||||
&data,
|
|
||||||
potentially_unnormalized_candidates,
|
potentially_unnormalized_candidates,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -948,14 +936,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
fn assemble_candidates_from_impls<'cx, 'tcx>(
|
fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("assemble_candidates_from_impls");
|
debug!("assemble_candidates_from_impls");
|
||||||
|
|
||||||
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
||||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||||
let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
|
let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
|
||||||
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
||||||
let _ = selcx.infcx().commit_if_ok(|_| {
|
let _ = selcx.infcx().commit_if_ok(|_| {
|
||||||
let impl_source = match selcx.select(&trait_obligation) {
|
let impl_source = match selcx.select(&trait_obligation) {
|
||||||
|
@ -1410,25 +1397,25 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||||
poly_cache_entry,
|
poly_cache_entry,
|
||||||
);
|
);
|
||||||
|
|
||||||
let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
|
let cache_projection = cache_entry.projection_ty;
|
||||||
let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
let obligation_projection = obligation.predicate;
|
||||||
let mut nested_obligations = Vec::new();
|
let mut nested_obligations = Vec::new();
|
||||||
let cache_trait_ref = if potentially_unnormalized_candidate {
|
let cache_projection = if potentially_unnormalized_candidate {
|
||||||
ensure_sufficient_stack(|| {
|
ensure_sufficient_stack(|| {
|
||||||
normalize_with_depth_to(
|
normalize_with_depth_to(
|
||||||
selcx,
|
selcx,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
obligation.cause.clone(),
|
obligation.cause.clone(),
|
||||||
obligation.recursion_depth + 1,
|
obligation.recursion_depth + 1,
|
||||||
cache_trait_ref,
|
cache_projection,
|
||||||
&mut nested_obligations,
|
&mut nested_obligations,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
cache_trait_ref
|
cache_projection
|
||||||
};
|
};
|
||||||
|
|
||||||
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
|
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
|
||||||
Ok(InferOk { value: _, obligations }) => {
|
Ok(InferOk { value: _, obligations }) => {
|
||||||
nested_obligations.extend(obligations);
|
nested_obligations.extend(obligations);
|
||||||
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
|
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
|
||||||
|
|
|
@ -32,6 +32,7 @@ use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::Constness;
|
use rustc_hir::Constness;
|
||||||
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::ty::fast_reject;
|
use rustc_middle::ty::fast_reject;
|
||||||
|
@ -1254,32 +1255,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
pub(super) fn match_projection_projections(
|
pub(super) fn match_projection_projections(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
env_predicate: PolyProjectionPredicate<'tcx>,
|
||||||
data: &PolyProjectionPredicate<'tcx>,
|
|
||||||
potentially_unnormalized_candidates: bool,
|
potentially_unnormalized_candidates: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut nested_obligations = Vec::new();
|
let mut nested_obligations = Vec::new();
|
||||||
let projection_ty = if potentially_unnormalized_candidates {
|
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||||
|
obligation.cause.span,
|
||||||
|
LateBoundRegionConversionTime::HigherRankedType,
|
||||||
|
env_predicate,
|
||||||
|
);
|
||||||
|
let infer_projection = if potentially_unnormalized_candidates {
|
||||||
ensure_sufficient_stack(|| {
|
ensure_sufficient_stack(|| {
|
||||||
project::normalize_with_depth_to(
|
project::normalize_with_depth_to(
|
||||||
self,
|
self,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
obligation.cause.clone(),
|
obligation.cause.clone(),
|
||||||
obligation.recursion_depth + 1,
|
obligation.recursion_depth + 1,
|
||||||
data.map_bound(|data| data.projection_ty),
|
infer_predicate.projection_ty,
|
||||||
&mut nested_obligations,
|
&mut nested_obligations,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
data.map_bound(|data| data.projection_ty)
|
infer_predicate.projection_ty
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME(generic_associated_types): Compare the whole projections
|
|
||||||
let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
|
|
||||||
let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
|
|
||||||
self.infcx
|
self.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
.sup(obligation.predicate, infer_projection)
|
||||||
.map_or(false, |InferOk { obligations, value: () }| {
|
.map_or(false, |InferOk { obligations, value: () }| {
|
||||||
self.evaluate_predicates_recursively(
|
self.evaluate_predicates_recursively(
|
||||||
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
||||||
|
|
|
@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
|
||||||
self,
|
self,
|
||||||
interner: &RustInterner<'tcx>,
|
interner: &RustInterner<'tcx>,
|
||||||
) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
|
) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
|
||||||
let trait_ref = self.projection_ty.trait_ref(interner.tcx);
|
let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
|
||||||
chalk_solve::rust_ir::AliasEqBound {
|
chalk_solve::rust_ir::AliasEqBound {
|
||||||
trait_bound: trait_ref.lower_into(interner),
|
trait_bound: trait_ref.lower_into(interner),
|
||||||
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
|
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
|
||||||
parameters: self.projection_ty.substs[trait_ref.substs.len()..]
|
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
|
||||||
.iter()
|
|
||||||
.map(|arg| arg.lower_into(interner))
|
|
||||||
.collect(),
|
|
||||||
value: self.ty.lower_into(interner),
|
value: self.ty.lower_into(interner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -985,10 +985,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
//
|
//
|
||||||
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
|
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
|
||||||
|
|
||||||
debug!(
|
debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
|
||||||
"add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
|
|
||||||
hir_ref_id, trait_ref, binding, bounds
|
|
||||||
);
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let candidate =
|
let candidate =
|
||||||
|
@ -1326,9 +1323,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
debug!("regular_traits: {:?}", regular_traits);
|
debug!("regular_traits: {:?}", regular_traits);
|
||||||
debug!("auto_traits: {:?}", auto_traits);
|
debug!("auto_traits: {:?}", auto_traits);
|
||||||
|
|
||||||
// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
|
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
|
||||||
// removing the dummy `Self` type (`trait_object_dummy_self`).
|
let existential_trait_refs = regular_traits.iter().map(|i| {
|
||||||
let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
|
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
|
||||||
if trait_ref.self_ty() != dummy_self {
|
if trait_ref.self_ty() != dummy_self {
|
||||||
// FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
|
// FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
|
||||||
// which picks up non-supertraits where clauses - but also, the object safety
|
// which picks up non-supertraits where clauses - but also, the object safety
|
||||||
|
@ -1344,19 +1341,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||||
};
|
})
|
||||||
|
});
|
||||||
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
|
|
||||||
let existential_trait_refs =
|
|
||||||
regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
|
|
||||||
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
|
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
|
||||||
bound.map_bound(|b| {
|
bound.map_bound(|b| {
|
||||||
let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
|
if b.projection_ty.self_ty() != dummy_self {
|
||||||
ty::ExistentialProjection {
|
tcx.sess.delay_span_bug(
|
||||||
ty: b.ty,
|
DUMMY_SP,
|
||||||
item_def_id: b.projection_ty.item_def_id,
|
&format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
|
||||||
substs: trait_ref.substs,
|
);
|
||||||
}
|
}
|
||||||
|
ty::ExistentialProjection::erase_self_ty(tcx, b)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1473,7 +1468,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
}),
|
}),
|
||||||
assoc_name,
|
assoc_name,
|
||||||
)
|
)
|
||||||
.into_iter()
|
|
||||||
},
|
},
|
||||||
|| param_name.to_string(),
|
|| param_name.to_string(),
|
||||||
assoc_name,
|
assoc_name,
|
||||||
|
|
|
@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Even if we can't infer the full signature, we may be able to
|
// Even if we can't infer the full signature, we may be able to
|
||||||
// infer the kind. This can occur if there is a trait-reference
|
// infer the kind. This can occur when we elaborate a predicate
|
||||||
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
||||||
// many viable options, so pick the most restrictive.
|
// many viable options, so pick the most restrictive.
|
||||||
let expected_kind = self
|
let expected_kind = self
|
||||||
|
@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
debug!("deduce_sig_from_projection({:?})", projection);
|
debug!("deduce_sig_from_projection({:?})", projection);
|
||||||
|
|
||||||
let trait_ref = projection.to_poly_trait_ref(tcx);
|
let trait_def_id = projection.trait_def_id(tcx);
|
||||||
|
|
||||||
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
|
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
|
||||||
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
|
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
|
||||||
let is_gen = gen_trait == trait_ref.def_id();
|
let is_gen = gen_trait == trait_def_id;
|
||||||
if !is_fn && !is_gen {
|
if !is_fn && !is_gen {
|
||||||
debug!("deduce_sig_from_projection: not fn or generator");
|
debug!("deduce_sig_from_projection: not fn or generator");
|
||||||
return None;
|
return None;
|
||||||
|
@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_tys = if is_fn {
|
let input_tys = if is_fn {
|
||||||
let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
|
let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
|
||||||
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
||||||
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
|
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
|
||||||
|
|
||||||
|
@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that this is a projection from the `Future` trait.
|
// Check that this is a projection from the `Future` trait.
|
||||||
let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
|
let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
|
||||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
|
||||||
if trait_ref.def_id != future_trait {
|
if trait_def_id != future_trait {
|
||||||
debug!("deduce_future_output_from_projection: not a future");
|
debug!("deduce_future_output_from_projection: not a future");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.filter_map(move |obligation| {
|
.filter_map(move |obligation| {
|
||||||
let bound_predicate = obligation.predicate.kind();
|
let bound_predicate = obligation.predicate.kind();
|
||||||
match bound_predicate.skip_binder() {
|
match bound_predicate.skip_binder() {
|
||||||
ty::PredicateKind::Projection(data) => {
|
ty::PredicateKind::Projection(data) => Some((
|
||||||
Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
|
bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
|
||||||
}
|
obligation,
|
||||||
|
)),
|
||||||
ty::PredicateKind::Trait(data, _) => {
|
ty::PredicateKind::Trait(data, _) => {
|
||||||
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
|
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::Obligation;
|
use rustc_trait_selection::traits::Obligation;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use super::probe::Mode;
|
use super::probe::Mode;
|
||||||
use super::{CandidateSource, MethodError, NoMatchData};
|
use super::{CandidateSource, MethodError, NoMatchData};
|
||||||
|
@ -648,21 +649,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ty::PredicateKind::Projection(pred) => {
|
ty::PredicateKind::Projection(pred) => {
|
||||||
let pred = bound_predicate.rebind(pred);
|
let pred = bound_predicate.rebind(pred);
|
||||||
// `<Foo as Iterator>::Item = String`.
|
// `<Foo as Iterator>::Item = String`.
|
||||||
let trait_ref =
|
let projection_ty = pred.skip_binder().projection_ty;
|
||||||
pred.skip_binder().projection_ty.trait_ref(self.tcx);
|
|
||||||
let assoc = self
|
let substs_with_infer_self = tcx.mk_substs(
|
||||||
.tcx
|
iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
|
||||||
.associated_item(pred.skip_binder().projection_ty.item_def_id);
|
.chain(projection_ty.substs.iter().skip(1)),
|
||||||
let ty = pred.skip_binder().ty;
|
|
||||||
let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
|
|
||||||
let quiet = format!(
|
|
||||||
"<_ as {}>::{} = {}",
|
|
||||||
trait_ref.print_only_trait_path(),
|
|
||||||
assoc.ident,
|
|
||||||
ty
|
|
||||||
);
|
);
|
||||||
bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
|
|
||||||
Some((obligation, trait_ref.self_ty()))
|
let quiet_projection_ty = ty::ProjectionTy {
|
||||||
|
substs: substs_with_infer_self,
|
||||||
|
item_def_id: projection_ty.item_def_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty = pred.skip_binder().ty;
|
||||||
|
|
||||||
|
let obligation = format!("{} = {}", projection_ty, ty);
|
||||||
|
let quiet = format!("{} = {}", quiet_projection_ty, ty);
|
||||||
|
|
||||||
|
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
|
||||||
|
Some((obligation, projection_ty.self_ty()))
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Trait(poly_trait_ref, _) => {
|
ty::PredicateKind::Trait(poly_trait_ref, _) => {
|
||||||
let p = poly_trait_ref.trait_ref;
|
let p = poly_trait_ref.trait_ref;
|
||||||
|
|
|
@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>(
|
||||||
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
||||||
// Then the projection only applies if `T` is known, but it still
|
// Then the projection only applies if `T` is known, but it still
|
||||||
// does not determine `U`.
|
// does not determine `U`.
|
||||||
let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
|
let inputs = parameters_for(&projection.projection_ty, true);
|
||||||
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
|
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
|
||||||
if !relies_only_on_inputs {
|
if !relies_only_on_inputs {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -64,6 +64,7 @@ pub trait Deref {
|
||||||
/// The resulting type after dereferencing.
|
/// The resulting type after dereferencing.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_diagnostic_item = "deref_target"]
|
#[rustc_diagnostic_item = "deref_target"]
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "deref_target")]
|
||||||
type Target: ?Sized;
|
type Target: ?Sized;
|
||||||
|
|
||||||
/// Dereferences the value.
|
/// Dereferences the value.
|
||||||
|
|
|
@ -506,7 +506,18 @@ pub fn run_test(
|
||||||
let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
|
let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
|
||||||
if concurrency == Concurrent::Yes && supports_threads {
|
if concurrency == Concurrent::Yes && supports_threads {
|
||||||
let cfg = thread::Builder::new().name(name.as_slice().to_owned());
|
let cfg = thread::Builder::new().name(name.as_slice().to_owned());
|
||||||
Some(cfg.spawn(runtest).unwrap())
|
let mut runtest = Arc::new(Mutex::new(Some(runtest)));
|
||||||
|
let runtest2 = runtest.clone();
|
||||||
|
match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) {
|
||||||
|
Ok(handle) => Some(handle),
|
||||||
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
|
// `ErrorKind::WouldBlock` means hitting the thread limit on some
|
||||||
|
// platforms, so run the test synchronously here instead.
|
||||||
|
Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to spawn thread to run test: {}", e),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
runtest();
|
runtest();
|
||||||
None
|
None
|
||||||
|
|
|
@ -27,7 +27,7 @@ use crate::config::TargetSelection;
|
||||||
use crate::dist;
|
use crate::dist;
|
||||||
use crate::native;
|
use crate::native;
|
||||||
use crate::tool::SourceType;
|
use crate::tool::SourceType;
|
||||||
use crate::util::{exe, is_dylib, symlink_dir};
|
use crate::util::{exe, is_debug_info, is_dylib, symlink_dir};
|
||||||
use crate::{Compiler, DependencyType, GitRepo, Mode};
|
use crate::{Compiler, DependencyType, GitRepo, Mode};
|
||||||
|
|
||||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -1049,7 +1049,8 @@ impl Step for Assemble {
|
||||||
let src_libdir = builder.sysroot_libdir(build_compiler, host);
|
let src_libdir = builder.sysroot_libdir(build_compiler, host);
|
||||||
for f in builder.read_dir(&src_libdir) {
|
for f in builder.read_dir(&src_libdir) {
|
||||||
let filename = f.file_name().into_string().unwrap();
|
let filename = f.file_name().into_string().unwrap();
|
||||||
if is_dylib(&filename) && !proc_macros.contains(&filename) {
|
if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
|
||||||
|
{
|
||||||
builder.copy(&f.path(), &rustc_libdir.join(&filename));
|
builder.copy(&f.path(), &rustc_libdir.join(&filename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1166,6 +1167,7 @@ pub fn run_cargo(
|
||||||
if !(filename.ends_with(".rlib")
|
if !(filename.ends_with(".rlib")
|
||||||
|| filename.ends_with(".lib")
|
|| filename.ends_with(".lib")
|
||||||
|| filename.ends_with(".a")
|
|| filename.ends_with(".a")
|
||||||
|
|| is_debug_info(&filename)
|
||||||
|| is_dylib(&filename)
|
|| is_dylib(&filename)
|
||||||
|| (is_check && filename.ends_with(".rmeta")))
|
|| (is_check && filename.ends_with(".rmeta")))
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,7 @@ fn install_sh(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
|
fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
|
||||||
PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)))
|
config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_dir(mut path: PathBuf) -> String {
|
fn prepare_dir(mut path: PathBuf) -> String {
|
||||||
|
|
|
@ -32,6 +32,12 @@ pub fn is_dylib(name: &str) -> bool {
|
||||||
name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
|
name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the file name given looks like a debug info file
|
||||||
|
pub fn is_debug_info(name: &str) -> bool {
|
||||||
|
// FIXME: consider split debug info on other platforms (e.g., Linux, macOS)
|
||||||
|
name.ends_with(".pdb")
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the corresponding relative library directory that the compiler's
|
/// Returns the corresponding relative library directory that the compiler's
|
||||||
/// dylibs will be found in.
|
/// dylibs will be found in.
|
||||||
pub fn libdir(target: TargetSelection) -> &'static str {
|
pub fn libdir(target: TargetSelection) -> &'static str {
|
||||||
|
|
|
@ -161,7 +161,7 @@ impl<'tcx> DocContext<'tcx> {
|
||||||
}
|
}
|
||||||
Entry::Occupied(e) => e.into_mut(),
|
Entry::Occupied(e) => e.into_mut(),
|
||||||
};
|
};
|
||||||
*def_index = DefIndex::from(*def_index + 1);
|
*def_index = *def_index + 1;
|
||||||
|
|
||||||
DefId { krate: crate_num, index: *def_index }
|
DefId { krate: crate_num, index: *def_index }
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>) -> ItemEnum {
|
||||||
bounds: g.into_iter().map(Into::into).collect(),
|
bounds: g.into_iter().map(Into::into).collect(),
|
||||||
default: t.map(Into::into),
|
default: t.map(Into::into),
|
||||||
},
|
},
|
||||||
StrippedItem(inner) => from_clean_item_kind(*inner, tcx).into(),
|
StrippedItem(inner) => from_clean_item_kind(*inner, tcx),
|
||||||
PrimitiveItem(_) | KeywordItem(_) => {
|
PrimitiveItem(_) | KeywordItem(_) => {
|
||||||
panic!("{:?} is not supported for JSON output", item)
|
panic!("{:?} is not supported for JSON output", item)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,6 @@ impl X for () {
|
||||||
type Y<T> where Self: Sized = u32;
|
type Y<T> where Self: Sized = u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn f<T: X<Y<()> = i32>>() {}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
7
src/test/run-make/libtest-thread-limit/Makefile
Normal file
7
src/test/run-make/libtest-thread-limit/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
-include ../../run-make-fulldeps/tools.mk
|
||||||
|
|
||||||
|
# only-linux
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) test.rs --test --target $(TARGET)
|
||||||
|
$(shell ulimit -p 0 && $(call RUN,test))
|
16
src/test/run-make/libtest-thread-limit/test.rs
Normal file
16
src/test/run-make/libtest-thread-limit/test.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#![feature(once_cell)]
|
||||||
|
|
||||||
|
use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}};
|
||||||
|
|
||||||
|
static THREAD_ID: SyncOnceCell<ThreadId> = SyncOnceCell::new();
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spawn_thread_would_block() {
|
||||||
|
assert_eq!(Builder::new().spawn(|| unreachable!()).unwrap_err().kind(), ErrorKind::WouldBlock);
|
||||||
|
THREAD_ID.set(thread::current().id()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_in_same_thread() {
|
||||||
|
assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id());
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ pub fn main() {
|
||||||
if let Some(y) = x {
|
if let Some(y) = x {
|
||||||
assert_eq!(y, 3);
|
assert_eq!(y, 3);
|
||||||
} else {
|
} else {
|
||||||
panic!("if-let panicked");
|
panic!("`if let` panicked");
|
||||||
}
|
}
|
||||||
let mut worked = false;
|
let mut worked = false;
|
||||||
if let Some(_) = x {
|
if let Some(_) = x {
|
||||||
|
@ -54,7 +54,7 @@ pub fn main() {
|
||||||
if let Foo::Two(b) = a {
|
if let Foo::Two(b) = a {
|
||||||
assert_eq!(b, 42_usize);
|
assert_eq!(b, 42_usize);
|
||||||
} else {
|
} else {
|
||||||
panic!("panic in nested if-let");
|
panic!("panic in nested `if let`");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
||||||
// FIXME(project-rfc-2229#24): Change this to be a destructure pattern
|
// FIXME(project-rfc-2229#24): Change this to be a destructure pattern
|
||||||
// once this is fixed, to remove the warning.
|
// once this is fixed, to remove the warning.
|
||||||
if let SingleVariant::Point(ref mut x, _) = point {
|
if let SingleVariant::Point(ref mut x, _) = point {
|
||||||
//~^ WARNING: irrefutable if-let pattern
|
//~^ WARNING: irrefutable `if let` pattern
|
||||||
*x += 1;
|
*x += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)]
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||||
|
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
|
--> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
|
||||||
|
|
|
|
||||||
LL | / if let SingleVariant::Point(ref mut x, _) = point {
|
LL | / if let SingleVariant::Point(ref mut x, _) = point {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#![feature(const_generics, const_evaluatable_checked)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// This tests that during error handling for the "trait not implemented" error
|
||||||
|
// we dont try to evaluate std::mem::size_of::<Self::Assoc> causing an ICE
|
||||||
|
|
||||||
|
struct Adt;
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
type Assoc;
|
||||||
|
fn foo()
|
||||||
|
where
|
||||||
|
[Adt; std::mem::size_of::<Self::Assoc>()]: ,
|
||||||
|
{
|
||||||
|
<[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
|
||||||
|
//~^ Error: the trait bound
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied
|
||||||
|
--> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9
|
||||||
|
|
|
||||||
|
LL | <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]`
|
||||||
|
...
|
||||||
|
LL | fn bar() {}
|
||||||
|
| -------- required by `Foo::bar`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -4,8 +4,8 @@ fn macros() {
|
||||||
macro_rules! foo{
|
macro_rules! foo{
|
||||||
($p:pat, $e:expr, $b:block) => {{
|
($p:pat, $e:expr, $b:block) => {{
|
||||||
if let $p = $e $b
|
if let $p = $e $b
|
||||||
//~^ WARN irrefutable if-let
|
//~^ WARN irrefutable `if let`
|
||||||
//~| WARN irrefutable if-let
|
//~| WARN irrefutable `if let`
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
macro_rules! bar{
|
macro_rules! bar{
|
||||||
|
@ -23,27 +23,27 @@ fn macros() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
if let a = 1 { //~ WARN irrefutable if-let
|
if let a = 1 { //~ WARN irrefutable `if let`
|
||||||
println!("irrefutable pattern");
|
println!("irrefutable pattern");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let a = 1 { //~ WARN irrefutable if-let
|
if let a = 1 { //~ WARN irrefutable `if let`
|
||||||
println!("irrefutable pattern");
|
println!("irrefutable pattern");
|
||||||
} else if true {
|
} else if true {
|
||||||
println!("else-if in irrefutable if-let");
|
println!("else-if in irrefutable `if let`");
|
||||||
} else {
|
} else {
|
||||||
println!("else in irrefutable if-let");
|
println!("else in irrefutable `if let`");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let 1 = 2 {
|
if let 1 = 2 {
|
||||||
println!("refutable pattern");
|
println!("refutable pattern");
|
||||||
} else if let a = 1 { //~ WARN irrefutable if-let
|
} else if let a = 1 { //~ WARN irrefutable `if let`
|
||||||
println!("irrefutable pattern");
|
println!("irrefutable pattern");
|
||||||
}
|
}
|
||||||
|
|
||||||
if true {
|
if true {
|
||||||
println!("if");
|
println!("if");
|
||||||
} else if let a = 1 { //~ WARN irrefutable if-let
|
} else if let a = 1 { //~ WARN irrefutable `if let`
|
||||||
println!("irrefutable pattern");
|
println!("irrefutable pattern");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/if-let.rs:6:13
|
--> $DIR/if-let.rs:6:13
|
||||||
|
|
|
|
||||||
LL | if let $p = $e $b
|
LL | if let $p = $e $b
|
||||||
|
@ -12,7 +12,7 @@ LL | | });
|
||||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/if-let.rs:6:13
|
--> $DIR/if-let.rs:6:13
|
||||||
|
|
|
|
||||||
LL | if let $p = $e $b
|
LL | if let $p = $e $b
|
||||||
|
@ -25,7 +25,7 @@ LL | | });
|
||||||
|
|
|
|
||||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/if-let.rs:26:5
|
--> $DIR/if-let.rs:26:5
|
||||||
|
|
|
|
||||||
LL | / if let a = 1 {
|
LL | / if let a = 1 {
|
||||||
|
@ -33,19 +33,19 @@ LL | | println!("irrefutable pattern");
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/if-let.rs:30:5
|
--> $DIR/if-let.rs:30:5
|
||||||
|
|
|
|
||||||
LL | / if let a = 1 {
|
LL | / if let a = 1 {
|
||||||
LL | | println!("irrefutable pattern");
|
LL | | println!("irrefutable pattern");
|
||||||
LL | | } else if true {
|
LL | | } else if true {
|
||||||
LL | | println!("else-if in irrefutable if-let");
|
LL | | println!("else-if in irrefutable `if let`");
|
||||||
LL | | } else {
|
LL | | } else {
|
||||||
LL | | println!("else in irrefutable if-let");
|
LL | | println!("else in irrefutable `if let`");
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/if-let.rs:40:12
|
--> $DIR/if-let.rs:40:12
|
||||||
|
|
|
|
||||||
LL | } else if let a = 1 {
|
LL | } else if let a = 1 {
|
||||||
|
@ -54,7 +54,7 @@ LL | | println!("irrefutable pattern");
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
warning: irrefutable if-let pattern
|
warning: irrefutable `if let` pattern
|
||||||
--> $DIR/if-let.rs:46:12
|
--> $DIR/if-let.rs:46:12
|
||||||
|
|
|
|
||||||
LL | } else if let a = 1 {
|
LL | } else if let a = 1 {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Test that correct syntax is used in suggestion to constrain associated type
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
//~^ WARNING the feature `generic_associated_types` is incomplete
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
type Y<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f<T: X>(a: T::Y<i32>) {
|
||||||
|
//~^ HELP consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
|
||||||
|
//~| SUGGESTION Y<i32> = Vec<i32>>
|
||||||
|
let b: Vec<i32> = a;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,27 @@
|
||||||
|
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/constraint-assoc-type-suggestion.rs:3:12
|
||||||
|
|
|
||||||
|
LL | #![feature(generic_associated_types)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/constraint-assoc-type-suggestion.rs:13:23
|
||||||
|
|
|
||||||
|
LL | let b: Vec<i32> = a;
|
||||||
|
| -------- ^ expected struct `Vec`, found associated type
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected struct `Vec<i32>`
|
||||||
|
found associated type `<T as X>::Y<i32>`
|
||||||
|
help: consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
|
||||||
|
|
|
||||||
|
LL | fn f<T: X<Y<i32> = Vec<i32>>>(a: T::Y<i32>) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,35 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
pub trait X {
|
||||||
|
type Y<'a>;
|
||||||
|
fn m(&self) -> Self::Y<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X for () {
|
||||||
|
type Y<'a> = &'a ();
|
||||||
|
|
||||||
|
fn m(&self) -> Self::Y<'_> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &() {
|
||||||
|
x.m()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &() {
|
||||||
|
x.m()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h(x: &()) -> &() {
|
||||||
|
x.m()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
f(&());
|
||||||
|
g(&());
|
||||||
|
h(&());
|
||||||
|
}
|
|
@ -36,6 +36,4 @@ impl SuperTrait for SuperStruct {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
|
let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
|
||||||
//~^ ERROR the trait
|
|
||||||
//~| ERROR the trait
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,41 +23,6 @@ help: use angle brackets to add missing lifetime argument
|
||||||
LL | type SubType<'a><'a>: SubTrait;
|
LL | type SubType<'a><'a>: SubTrait;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error[E0038]: the trait `SuperTrait` cannot be made into an object
|
error: aborting due to previous error; 1 warning emitted
|
||||||
--> $DIR/issue-76535.rs:38:14
|
|
||||||
|
|
|
||||||
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
|
|
||||||
|
|
|
||||||
= help: consider moving `get_sub` to another trait
|
|
||||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
|
||||||
--> $DIR/issue-76535.rs:10:37
|
|
||||||
|
|
|
||||||
LL | pub trait SuperTrait {
|
|
||||||
| ---------- this trait cannot be made into an object...
|
|
||||||
...
|
|
||||||
LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
|
|
||||||
|
|
||||||
error[E0038]: the trait `SuperTrait` cannot be made into an object
|
For more information about this error, try `rustc --explain E0107`.
|
||||||
--> $DIR/issue-76535.rs:38:57
|
|
||||||
|
|
|
||||||
LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0));
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
|
|
||||||
|
|
|
||||||
= help: consider moving `get_sub` to another trait
|
|
||||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
|
||||||
--> $DIR/issue-76535.rs:10:37
|
|
||||||
|
|
|
||||||
LL | pub trait SuperTrait {
|
|
||||||
| ---------- this trait cannot be made into an object...
|
|
||||||
...
|
|
||||||
LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type
|
|
||||||
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
|
|
||||||
= note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors; 1 warning emitted
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0038, E0107.
|
|
||||||
For more information about an error, try `rustc --explain E0038`.
|
|
||||||
|
|
|
@ -42,6 +42,5 @@ impl<K, V: Default> MapLike<K, V> for Source {
|
||||||
fn main() {
|
fn main() {
|
||||||
let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
|
let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
|
||||||
as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
|
as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
|
||||||
//~^ ERROR the trait
|
//~^^ ERROR type mismatch resolving
|
||||||
//~^^^ ERROR the trait
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,41 +14,17 @@ help: use angle brackets to add missing lifetime argument
|
||||||
LL | type VRefCont<'a><'a>: RefCont<'a, V>;
|
LL | type VRefCont<'a><'a>: RefCont<'a, V>;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error[E0038]: the trait `MapLike` cannot be made into an object
|
error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)`
|
||||||
--> $DIR/issue-79422.rs:44:12
|
|
||||||
|
|
|
||||||
LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
|
|
||||||
|
|
|
||||||
= help: consider moving `get` to another trait
|
|
||||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
|
||||||
--> $DIR/issue-79422.rs:23:38
|
|
||||||
|
|
|
||||||
LL | trait MapLike<K, V> {
|
|
||||||
| ------- this trait cannot be made into an object...
|
|
||||||
...
|
|
||||||
LL | fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
|
|
||||||
|
|
||||||
error[E0038]: the trait `MapLike` cannot be made into an object
|
|
||||||
--> $DIR/issue-79422.rs:43:13
|
--> $DIR/issue-79422.rs:43:13
|
||||||
|
|
|
|
||||||
LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
|
LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference
|
||||||
|
|
|
|
||||||
= help: consider moving `get` to another trait
|
= note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
|
||||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
found reference `&'static u8`
|
||||||
--> $DIR/issue-79422.rs:23:38
|
= note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>`
|
||||||
|
|
|
||||||
LL | trait MapLike<K, V> {
|
|
||||||
| ------- this trait cannot be made into an object...
|
|
||||||
...
|
|
||||||
LL | fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type
|
|
||||||
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
|
|
||||||
= note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0038, E0107.
|
Some errors have detailed explanations: E0107, E0271.
|
||||||
For more information about an error, try `rustc --explain E0038`.
|
For more information about an error, try `rustc --explain E0107`.
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Test that the predicate printed in an unresolved method error prints the
|
||||||
|
// generics for a generic associated type.
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
//~^ WARNING the feature `generic_associated_types` is incomplete
|
||||||
|
//~| NOTE `#[warn(incomplete_features)]` on by default
|
||||||
|
//~| NOTE see issue #44265
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
type Y<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait M {
|
||||||
|
fn f(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: X<Y<i32> = i32>> M for T {}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
//~^ NOTE method `f` not found for this
|
||||||
|
//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
|
||||||
|
//~| NOTE doesn't satisfy `S: M`
|
||||||
|
|
||||||
|
impl X for S {
|
||||||
|
type Y<T> = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(a: S) {
|
||||||
|
a.f();
|
||||||
|
//~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
|
||||||
|
//~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
|
||||||
|
//~| NOTE the following trait bounds were not satisfied:
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,29 @@
|
||||||
|
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/method-unsatified-assoc-type-predicate.rs:4:12
|
||||||
|
|
|
||||||
|
LL | #![feature(generic_associated_types)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
|
||||||
|
|
||||||
|
error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
|
||||||
|
--> $DIR/method-unsatified-assoc-type-predicate.rs:29:7
|
||||||
|
|
|
||||||
|
LL | struct S;
|
||||||
|
| ---------
|
||||||
|
| |
|
||||||
|
| method `f` not found for this
|
||||||
|
| doesn't satisfy `<S as X>::Y<i32> = i32`
|
||||||
|
| doesn't satisfy `S: M`
|
||||||
|
...
|
||||||
|
LL | a.f();
|
||||||
|
| ^ method cannot be called on `S` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
= note: the following trait bounds were not satisfied:
|
||||||
|
`<S as X>::Y<i32> = i32`
|
||||||
|
which is required by `S: M`
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
|
@ -0,0 +1,36 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
pub trait X {
|
||||||
|
type Y<'a>;
|
||||||
|
fn m(&self) -> Self::Y<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X for () {
|
||||||
|
type Y<'a> = &'a ();
|
||||||
|
|
||||||
|
fn m(&self) -> Self::Y<'_> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
|
||||||
|
x.m()
|
||||||
|
//~^ ERROR explicit lifetime required
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
|
||||||
|
x.m()
|
||||||
|
//~^ ERROR explicit lifetime required
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h(x: &()) -> &'static () {
|
||||||
|
x.m()
|
||||||
|
//~^ ERROR explicit lifetime required
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
f(&());
|
||||||
|
g(&());
|
||||||
|
h(&());
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
error[E0621]: explicit lifetime required in the type of `x`
|
||||||
|
--> $DIR/projection-type-lifetime-mismatch.rs:18:5
|
||||||
|
|
|
||||||
|
LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
|
||||||
|
| ------------------------------- help: add explicit lifetime `'static` to the type of `x`: `&'static impl for<'a> X<Y<'a> = &'a ()>`
|
||||||
|
LL | x.m()
|
||||||
|
| ^^^^^ lifetime `'static` required
|
||||||
|
|
||||||
|
error[E0621]: explicit lifetime required in the type of `x`
|
||||||
|
--> $DIR/projection-type-lifetime-mismatch.rs:23:5
|
||||||
|
|
|
||||||
|
LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
|
||||||
|
| -- help: add explicit lifetime `'static` to the type of `x`: `&'static T`
|
||||||
|
LL | x.m()
|
||||||
|
| ^^^^^ lifetime `'static` required
|
||||||
|
|
||||||
|
error[E0621]: explicit lifetime required in the type of `x`
|
||||||
|
--> $DIR/projection-type-lifetime-mismatch.rs:28:5
|
||||||
|
|
|
||||||
|
LL | fn h(x: &()) -> &'static () {
|
||||||
|
| --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()`
|
||||||
|
LL | x.m()
|
||||||
|
| ^^^^^ lifetime `'static` required
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0621`.
|
|
@ -0,0 +1,28 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
pub trait X {
|
||||||
|
type Y<'a: 'static>;
|
||||||
|
//~^ WARNING unnecessary lifetime parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X for () {
|
||||||
|
type Y<'a> = &'a ();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
|
||||||
|
f: <T as X>::Y<'a>,
|
||||||
|
//~^ ERROR lifetime bound not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C<'a, T: X> {
|
||||||
|
f: <T as X>::Y<'a>,
|
||||||
|
//~^ ERROR lifetime bound not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
struct D<'a> {
|
||||||
|
f: <() as X>::Y<'a>,
|
||||||
|
//~^ ERROR lifetime bound not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,50 @@
|
||||||
|
warning: unnecessary lifetime parameter `'a`
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:5:12
|
||||||
|
|
|
||||||
|
LL | type Y<'a: 'static>;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: you can use the `'static` lifetime directly, in place of `'a`
|
||||||
|
|
||||||
|
error[E0478]: lifetime bound not satisfied
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:14:8
|
||||||
|
|
|
||||||
|
LL | f: <T as X>::Y<'a>,
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 13:10
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:13:10
|
||||||
|
|
|
||||||
|
LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
|
||||||
|
| ^^
|
||||||
|
= note: but lifetime parameter must outlive the static lifetime
|
||||||
|
|
||||||
|
error[E0478]: lifetime bound not satisfied
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:19:8
|
||||||
|
|
|
||||||
|
LL | f: <T as X>::Y<'a>,
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 18:10
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:18:10
|
||||||
|
|
|
||||||
|
LL | struct C<'a, T: X> {
|
||||||
|
| ^^
|
||||||
|
= note: but lifetime parameter must outlive the static lifetime
|
||||||
|
|
||||||
|
error[E0478]: lifetime bound not satisfied
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:24:8
|
||||||
|
|
|
||||||
|
LL | f: <() as X>::Y<'a>,
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 23:10
|
||||||
|
--> $DIR/unsatified-item-lifetime-bound.rs:23:10
|
||||||
|
|
|
||||||
|
LL | struct D<'a> {
|
||||||
|
| ^^
|
||||||
|
= note: but lifetime parameter must outlive the static lifetime
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0478`.
|
|
@ -1,4 +1,4 @@
|
||||||
// Test if the sugared if-let construct correctly prints "missing an else clause" when an else
|
// Test if the sugared `if let` construct correctly prints "missing an else clause" when an else
|
||||||
// clause does not exist, instead of the unsympathetic "`match` arms have incompatible types"
|
// clause does not exist, instead of the unsympathetic "`match` arms have incompatible types"
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -5,6 +5,10 @@ LL | a == b;
|
||||||
| ^^ no implementation for `&T == T`
|
| ^^ no implementation for `&T == T`
|
||||||
|
|
|
|
||||||
= help: the trait `PartialEq<T>` is not implemented for `&T`
|
= help: the trait `PartialEq<T>` is not implemented for `&T`
|
||||||
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | fn foo<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#![deny(irrefutable_let_patterns)]
|
#![deny(irrefutable_let_patterns)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if let _ = 5 {} //~ ERROR irrefutable if-let pattern
|
if let _ = 5 {} //~ ERROR irrefutable `if let` pattern
|
||||||
|
|
||||||
while let _ = 5 { //~ ERROR irrefutable while-let pattern
|
while let _ = 5 { //~ ERROR irrefutable `while let` pattern
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: irrefutable if-let pattern
|
error: irrefutable `if let` pattern
|
||||||
--> $DIR/deny-irrefutable-let-patterns.rs:4:5
|
--> $DIR/deny-irrefutable-let-patterns.rs:4:5
|
||||||
|
|
|
|
||||||
LL | if let _ = 5 {}
|
LL | if let _ = 5 {}
|
||||||
|
@ -10,7 +10,7 @@ note: the lint level is defined here
|
||||||
LL | #![deny(irrefutable_let_patterns)]
|
LL | #![deny(irrefutable_let_patterns)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: irrefutable while-let pattern
|
error: irrefutable `while let` pattern
|
||||||
--> $DIR/deny-irrefutable-let-patterns.rs:6:5
|
--> $DIR/deny-irrefutable-let-patterns.rs:6:5
|
||||||
|
|
|
|
||||||
LL | / while let _ = 5 {
|
LL | / while let _ = 5 {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
fn irrefutable_let_guard() {
|
fn irrefutable_let_guard() {
|
||||||
match Some(()) {
|
match Some(()) {
|
||||||
Some(x) if let () = x => {}
|
Some(x) if let () = x => {}
|
||||||
//~^ ERROR irrefutable if-let guard
|
//~^ ERROR irrefutable `if let` guard
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: irrefutable if-let guard
|
error: irrefutable `if let` guard
|
||||||
--> $DIR/warns.rs:7:24
|
--> $DIR/warns.rs:7:24
|
||||||
|
|
|
|
||||||
LL | Some(x) if let () = x => {}
|
LL | Some(x) if let () = x => {}
|
||||||
|
|
|
@ -18,6 +18,10 @@ LL | default type U = &'static B;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
|
||||||
|
|
|
|
||||||
= help: the trait `PartialEq<B>` is not implemented for `&'static B`
|
= help: the trait `PartialEq<B>` is not implemented for `&'static B`
|
||||||
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error; 1 warning emitted
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
|
|
@ -116,5 +116,5 @@ LL | #[rustc_deprecated(since = "a", reason = "text")]
|
||||||
|
|
||||||
error: aborting due to 19 previous errors
|
error: aborting due to 19 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0550.
|
Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0549, E0550.
|
||||||
For more information about an error, try `rustc --explain E0539`.
|
For more information about an error, try `rustc --explain E0539`.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::io::{BufRead, BufReader, Read, Write};
|
use std::io::{BufRead, BufReader, Read, Write};
|
||||||
|
|
||||||
fn issue_81421<T: Read + Write>(mut stream: T) {
|
fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` bound
|
||||||
let initial_message = format!("Hello world");
|
let initial_message = format!("Hello world");
|
||||||
let mut buffer: Vec<u8> = Vec::new();
|
let mut buffer: Vec<u8> = Vec::new();
|
||||||
let bytes_written = stream.write_all(initial_message.as_bytes());
|
let bytes_written = stream.write_all(initial_message.as_bytes());
|
||||||
|
|
|
@ -9,6 +9,10 @@ help: consider removing the leading `&`-reference
|
||||||
|
|
|
|
||||||
LL | let mut stream_reader = BufReader::new(stream);
|
LL | let mut stream_reader = BufReader::new(stream);
|
||||||
| --
|
| --
|
||||||
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | fn issue_81421<T: Read + Write>(mut stream: T) where &T: std::io::Read {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: consider changing this borrow's mutability
|
help: consider changing this borrow's mutability
|
||||||
|
|
|
|
||||||
LL | let mut stream_reader = BufReader::new(&mut stream);
|
LL | let mut stream_reader = BufReader::new(&mut stream);
|
||||||
|
|
|
@ -35,6 +35,10 @@ LL | <u64 as From<T>>::from;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64`
|
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64`
|
||||||
|
|
|
|
||||||
= note: required by `from`
|
= note: required by `from`
|
||||||
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | fn check<T: Iterator, U: ?Sized>() where u64: From<T> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfied
|
error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfied
|
||||||
--> $DIR/suggest-where-clause.rs:18:5
|
--> $DIR/suggest-where-clause.rs:18:5
|
||||||
|
@ -43,6 +47,10 @@ LL | <u64 as From<<T as Iterator>::Item>>::from;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64`
|
||||||
|
|
|
|
||||||
= note: required by `from`
|
= note: required by `from`
|
||||||
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | fn check<T: Iterator, U: ?Sized>() where u64: From<<T as Iterator>::Item> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: the trait bound `Misc<_>: From<T>` is not satisfied
|
error[E0277]: the trait bound `Misc<_>: From<T>` is not satisfied
|
||||||
--> $DIR/suggest-where-clause.rs:23:5
|
--> $DIR/suggest-where-clause.rs:23:5
|
||||||
|
|
|
@ -5,8 +5,8 @@ fn macros() {
|
||||||
macro_rules! foo{
|
macro_rules! foo{
|
||||||
($p:pat, $e:expr, $b:block) => {{
|
($p:pat, $e:expr, $b:block) => {{
|
||||||
while let $p = $e $b
|
while let $p = $e $b
|
||||||
//~^ WARN irrefutable while-let
|
//~^ WARN irrefutable `while let`
|
||||||
//~| WARN irrefutable while-let
|
//~| WARN irrefutable `while let`
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
macro_rules! bar{
|
macro_rules! bar{
|
||||||
|
@ -24,7 +24,7 @@ fn macros() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
while let _a = 1 { //~ WARN irrefutable while-let
|
while let _a = 1 { //~ WARN irrefutable `while let`
|
||||||
println!("irrefutable pattern");
|
println!("irrefutable pattern");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: irrefutable while-let pattern
|
warning: irrefutable `while let` pattern
|
||||||
--> $DIR/while-let.rs:7:13
|
--> $DIR/while-let.rs:7:13
|
||||||
|
|
|
|
||||||
LL | while let $p = $e $b
|
LL | while let $p = $e $b
|
||||||
|
@ -12,7 +12,7 @@ LL | | });
|
||||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
warning: irrefutable while-let pattern
|
warning: irrefutable `while let` pattern
|
||||||
--> $DIR/while-let.rs:7:13
|
--> $DIR/while-let.rs:7:13
|
||||||
|
|
|
|
||||||
LL | while let $p = $e $b
|
LL | while let $p = $e $b
|
||||||
|
@ -25,7 +25,7 @@ LL | | });
|
||||||
|
|
|
|
||||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
warning: irrefutable while-let pattern
|
warning: irrefutable `while let` pattern
|
||||||
--> $DIR/while-let.rs:27:5
|
--> $DIR/while-let.rs:27:5
|
||||||
|
|
|
|
||||||
LL | / while let _a = 1 {
|
LL | / while let _a = 1 {
|
||||||
|
|
|
@ -340,7 +340,7 @@ declare_clippy_lint! {
|
||||||
/// ```
|
/// ```
|
||||||
pub WHILE_LET_ON_ITERATOR,
|
pub WHILE_LET_ON_ITERATOR,
|
||||||
style,
|
style,
|
||||||
"using a while-let loop instead of a for loop on an iterator"
|
"using a `while let` loop instead of a for loop on an iterator"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue