1
Fork 0

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:
bors 2021-02-18 19:45:42 +00:00
commit 0148b971c9
89 changed files with 877 additions and 391 deletions

View file

@ -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 } => {

View file

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

View file

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

View file

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

View file

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

View 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

View file

@ -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) {

View file

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

View file

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

View file

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

View file

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

View file

@ -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)),
}
}
}

View file

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

View file

@ -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! {

View file

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

View file

@ -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<'_>,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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)),
} }
} }

View file

@ -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)))
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -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)
); );

View file

@ -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
); );

View file

@ -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) {

View file

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

View file

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

View file

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

View file

@ -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, &param_name, &constraint) {
return;
}
}
hir::Node::Crate(..) => return, hir::Node::Crate(..) => return,
_ => {} _ => {}

View file

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

View file

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

View file

@ -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);

View file

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

View file

@ -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),
} }
} }

View file

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

View file

@ -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;
} }

View file

@ -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))
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -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")))
{ {

View file

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

View file

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

View file

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

View file

@ -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)
} }

View file

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

View 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))

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

View file

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

View file

@ -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;
} }
}; };

View file

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

View file

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

View file

@ -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`.

View file

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

View file

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

View file

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

View file

@ -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`.

View file

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

View file

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

View file

@ -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`.

View file

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

View file

@ -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`.

View file

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

View file

@ -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`.

View file

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

View file

@ -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`.

View file

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

View file

@ -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`.

View file

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

View file

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

View file

@ -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;
} }
} }

View file

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

View file

@ -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
_ => {} _ => {}
} }
} }

View file

@ -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 => {}

View file

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

View file

@ -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`.

View file

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

View file

@ -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);

View file

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

View file

@ -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;
} }

View file

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

View file

@ -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! {