From 63396b30cf6e4f9148c7af8a21727b4d2109b632 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 5 Mar 2023 18:16:58 -0800 Subject: [PATCH 01/18] Allow binary files to go through the `FileLoader` --- compiler/rustc_span/src/source_map.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 2e339a9d2d2b0..a1cb810a4293b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -100,6 +100,9 @@ pub trait FileLoader { /// Read the contents of a UTF-8 file into memory. fn read_file(&self, path: &Path) -> io::Result; + + /// Read the contents of a potentially non-UTF-8 file into memory. + fn read_binary_file(&self, path: &Path) -> io::Result>; } /// A FileLoader that uses std::fs to load real files. @@ -113,6 +116,10 @@ impl FileLoader for RealFileLoader { fn read_file(&self, path: &Path) -> io::Result { fs::read_to_string(path) } + + fn read_binary_file(&self, path: &Path) -> io::Result> { + fs::read(path) + } } /// This is a [SourceFile] identifier that is used to correlate source files between @@ -220,9 +227,7 @@ impl SourceMap { /// Unlike `load_file`, guarantees that no normalization like BOM-removal /// takes place. pub fn load_binary_file(&self, path: &Path) -> io::Result> { - // Ideally, this should use `self.file_loader`, but it can't - // deal with binary files yet. - let bytes = fs::read(path)?; + let bytes = self.file_loader.read_binary_file(path)?; // We need to add file to the `SourceMap`, so that it is present // in dep-info. There's also an edge case that file might be both From 8ac7d0eef5621338d3650ec6884c58bc28a5c5f6 Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Sun, 28 Nov 2021 06:33:06 -0600 Subject: [PATCH 02/18] Add suggestion to diagnostic when user has array but trait wants slice. For #90528. --- .../src/traits/error_reporting/mod.rs | 20 ++-- .../src/traits/error_reporting/suggestions.rs | 77 ++++++++++++++- .../dst/issue-90528-unsizing-suggestion-1.rs | 20 ++++ .../issue-90528-unsizing-suggestion-1.stderr | 56 +++++++++++ .../dst/issue-90528-unsizing-suggestion-2.rs | 28 ++++++ .../issue-90528-unsizing-suggestion-2.stderr | 94 +++++++++++++++++++ .../dst/issue-90528-unsizing-suggestion-3.rs | 22 +++++ .../issue-90528-unsizing-suggestion-3.stderr | 75 +++++++++++++++ .../dst/issue-90528-unsizing-suggestion-4.rs | 26 +++++ .../issue-90528-unsizing-suggestion-4.stderr | 79 ++++++++++++++++ 10 files changed, 490 insertions(+), 7 deletions(-) create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-1.rs create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-1.stderr create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-2.rs create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-2.stderr create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-3.rs create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-3.stderr create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-4.rs create mode 100644 tests/ui/dst/issue-90528-unsizing-suggestion-4.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index a844a1494e262..4ca67d7ad73ac 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1035,7 +1035,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( - impl_candidates, + &impl_candidates, trait_ref, body_hir_id, &mut err, @@ -1071,7 +1071,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(trait_pred); self.report_similar_impl_candidates( - impl_candidates, + &impl_candidates, trait_ref, body_hir_id, &mut err, @@ -1079,6 +1079,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } } + + self.maybe_suggest_convert_to_slice( + &mut err, + trait_ref, + impl_candidates.as_slice(), + span, + ); } // Changing mutability doesn't make a difference to whether we have @@ -1529,7 +1536,7 @@ trait InferCtxtPrivExt<'tcx> { fn report_similar_impl_candidates( &self, - impl_candidates: Vec>, + impl_candidates: &[ImplCandidate<'tcx>], trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, err: &mut Diagnostic, @@ -2027,7 +2034,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn report_similar_impl_candidates( &self, - impl_candidates: Vec>, + impl_candidates: &[ImplCandidate<'tcx>], trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, err: &mut Diagnostic, @@ -2138,7 +2145,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Prefer more similar candidates first, then sort lexicographically // by their normalized string representation. let mut normalized_impl_candidates_and_similarities = impl_candidates - .into_iter() + .iter() + .copied() .map(|ImplCandidate { trait_ref, similarity }| { // FIXME(compiler-errors): This should be using `NormalizeExt::normalize` let normalized = self @@ -2351,7 +2359,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); self.report_similar_impl_candidates( - impl_candidates, + impl_candidates.as_slice(), trait_ref, body_id.map(|id| id.hir_id).unwrap_or(hir), &mut err, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9ab753c5a4826..172039879d7f1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1,7 +1,7 @@ // ignore-tidy-filelength use super::{ - DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode, + DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, }; @@ -382,6 +382,14 @@ pub trait TypeErrCtxtExt<'tcx> { body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, ) -> Vec))>>; + + fn maybe_suggest_convert_to_slice( + &self, + err: &mut Diagnostic, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + candidate_impls: &[ImplCandidate<'tcx>], + span: Span, + ); } fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { @@ -3826,6 +3834,73 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } assocs_in_this_method } + + /// If the type that failed selection is an array or a reference to an array, + /// but the trait is implemented for slices, suggest that the user converts + /// the array into a slice. + fn maybe_suggest_convert_to_slice( + &self, + err: &mut Diagnostic, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + candidate_impls: &[ImplCandidate<'tcx>], + span: Span, + ) { + // Three cases where we can make a suggestion: + // 1. `[T; _]` (array of T) + // 2. `&[T; _]` (reference to array of T) + // 3. `&mut [T; _]` (mutable reference to array of T) + let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() { + ty::Array(element_ty, _) => (element_ty, None), + + ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() { + ty::Array(element_ty, _) => (element_ty, Some(mutability)), + _ => return, + }, + + _ => return, + }; + + // Go through all the candidate impls to see if any of them is for + // slices of `element_ty` with `mutability`. + let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() { + ty::RawPtr(ty::TypeAndMut { ty: t, mutbl: m }) | ty::Ref(_, t, m) => { + if matches!(*t.kind(), ty::Slice(e) if e == element_ty) + && m == mutability.unwrap_or(m) + { + // Use the candidate's mutability going forward. + mutability = Some(m); + true + } else { + false + } + } + _ => false, + }; + + // Grab the first candidate that matches, if any, and make a suggestion. + if let Some(slice_ty) = candidate_impls + .iter() + .map(|trait_ref| trait_ref.trait_ref.self_ty()) + .filter(|t| is_slice(*t)) + .next() + { + let msg = &format!("convert the array to a `{}` slice instead", slice_ty); + + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let mut suggestions = vec![]; + if snippet.starts_with('&') { + } else if let Some(hir::Mutability::Mut) = mutability { + suggestions.push((span.shrink_to_lo(), "&mut ".into())); + } else { + suggestions.push((span.shrink_to_lo(), "&".into())); + } + suggestions.push((span.shrink_to_hi(), "[..]".into())); + err.multipart_suggestion_verbose(msg, suggestions, Applicability::MaybeIncorrect); + } else { + err.span_help(span, msg); + } + } + } } /// Add a hint to add a missing borrow or remove an unnecessary one. diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-1.rs b/tests/ui/dst/issue-90528-unsizing-suggestion-1.rs new file mode 100644 index 0000000000000..52863e22bb6fa --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-1.rs @@ -0,0 +1,20 @@ +// Issue #90528: provide helpful suggestions when a trait bound is unsatisfied +// due to a missed unsizing coercion. +// +// This test exercises array literals and a trait implemented on immutable slices. + +trait Read {} + +impl Read for &[u8] {} + +fn wants_read(_: impl Read) {} + +fn main() { + wants_read([0u8]); + //~^ ERROR the trait bound `[u8; 1]: Read` is not satisfied + wants_read(&[0u8]); + //~^ ERROR the trait bound `&[u8; 1]: Read` is not satisfied + wants_read(&[0u8][..]); + wants_read(&mut [0u8]); + //~^ ERROR the trait bound `&mut [u8; 1]: Read` is not satisfied +} diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-1.stderr b/tests/ui/dst/issue-90528-unsizing-suggestion-1.stderr new file mode 100644 index 0000000000000..27ef3fe97a5b0 --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-1.stderr @@ -0,0 +1,56 @@ +error[E0277]: the trait bound `[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-1.rs:13:16 + | +LL | wants_read([0u8]); + | ---------- ^^^^^ the trait `Read` is not implemented for `[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-1.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` +help: convert the array to a `&[u8]` slice instead + | +LL | wants_read(&[0u8][..]); + | + ++++ + +error[E0277]: the trait bound `&[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-1.rs:15:16 + | +LL | wants_read(&[0u8]); + | ---------- ^^^^^^ the trait `Read` is not implemented for `&[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-1.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` +help: convert the array to a `&[u8]` slice instead + | +LL | wants_read(&[0u8][..]); + | ++++ + +error[E0277]: the trait bound `&mut [u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-1.rs:18:16 + | +LL | wants_read(&mut [0u8]); + | ---------- ^^^^^^^^^^ the trait `Read` is not implemented for `&mut [u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-1.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-2.rs b/tests/ui/dst/issue-90528-unsizing-suggestion-2.rs new file mode 100644 index 0000000000000..f2762ad421ba5 --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-2.rs @@ -0,0 +1,28 @@ +// Issue #90528: provide helpful suggestions when a trait bound is unsatisfied +// due to a missed unsizing coercion. +// +// This test exercises array variables and a trait implemented on immmutable slices. + +trait Read {} + +impl Read for &[u8] {} + +fn wants_read(_: impl Read) {} + +fn main() { + let x = [0u8]; + wants_read(x); + //~^ ERROR the trait bound `[u8; 1]: Read` is not satisfied + wants_read(&x); + //~^ ERROR the trait bound `&[u8; 1]: Read` is not satisfied + wants_read(&x[..]); + + let x = &[0u8]; + wants_read(x); + //~^ ERROR the trait bound `&[u8; 1]: Read` is not satisfied + wants_read(&x); + //~^ ERROR the trait bound `&&[u8; 1]: Read` is not satisfied + wants_read(*x); + //~^ ERROR the trait bound `[u8; 1]: Read` is not satisfied + wants_read(&x[..]); +} diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-2.stderr b/tests/ui/dst/issue-90528-unsizing-suggestion-2.stderr new file mode 100644 index 0000000000000..ae0c4ca506ab2 --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-2.stderr @@ -0,0 +1,94 @@ +error[E0277]: the trait bound `[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-2.rs:14:16 + | +LL | wants_read(x); + | ---------- ^ the trait `Read` is not implemented for `[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-2.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` +help: convert the array to a `&[u8]` slice instead + | +LL | wants_read(&x[..]); + | + ++++ + +error[E0277]: the trait bound `&[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-2.rs:16:16 + | +LL | wants_read(&x); + | ---------- ^^ the trait `Read` is not implemented for `&[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-2.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` +help: convert the array to a `&[u8]` slice instead + | +LL | wants_read(&x[..]); + | ++++ + +error[E0277]: the trait bound `&[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-2.rs:21:16 + | +LL | wants_read(x); + | ---------- ^ the trait `Read` is not implemented for `&[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-2.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` +help: convert the array to a `&[u8]` slice instead + | +LL | wants_read(&x[..]); + | + ++++ + +error[E0277]: the trait bound `&&[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-2.rs:23:16 + | +LL | wants_read(&x); + | ---------- ^^ the trait `Read` is not implemented for `&&[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-2.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` + +error[E0277]: the trait bound `[u8; 1]: Read` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-2.rs:25:16 + | +LL | wants_read(*x); + | ---------- ^^ the trait `Read` is not implemented for `[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Read` is implemented for `&[u8]` +note: required by a bound in `wants_read` + --> $DIR/issue-90528-unsizing-suggestion-2.rs:10:23 + | +LL | fn wants_read(_: impl Read) {} + | ^^^^ required by this bound in `wants_read` +help: convert the array to a `&[u8]` slice instead + | +LL | wants_read(&*x[..]); + | + ++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-3.rs b/tests/ui/dst/issue-90528-unsizing-suggestion-3.rs new file mode 100644 index 0000000000000..218843d050028 --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-3.rs @@ -0,0 +1,22 @@ +// Issue #90528: provide helpful suggestions when a trait bound is unsatisfied +// due to a missed unsizing coercion. +// +// This test exercises array literals and a trait implemented on mutable slices. + +trait Write {} + +impl Write for &mut [u8] {} + +fn wants_write(_: impl Write) {} + +fn main() { + wants_write([0u8]); + //~^ ERROR the trait bound `[u8; 1]: Write` is not satisfied + wants_write(&mut [0u8]); + //~^ ERROR the trait bound `&mut [u8; 1]: Write` is not satisfied + wants_write(&mut [0u8][..]); + wants_write(&[0u8]); + //~^ ERROR the trait bound `&[u8; 1]: Write` is not satisfied + wants_write(&[0u8][..]); + //~^ ERROR the trait bound `&[u8]: Write` is not satisfied +} diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-3.stderr b/tests/ui/dst/issue-90528-unsizing-suggestion-3.stderr new file mode 100644 index 0000000000000..774d5ba3c892c --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-3.stderr @@ -0,0 +1,75 @@ +error[E0277]: the trait bound `[u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-3.rs:13:17 + | +LL | wants_write([0u8]); + | ----------- ^^^^^ the trait `Write` is not implemented for `[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-3.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: convert the array to a `&mut [u8]` slice instead + | +LL | wants_write(&mut [0u8][..]); + | ++++ ++++ + +error[E0277]: the trait bound `&mut [u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-3.rs:15:17 + | +LL | wants_write(&mut [0u8]); + | ----------- ^^^^^^^^^^ the trait `Write` is not implemented for `&mut [u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-3.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: convert the array to a `&mut [u8]` slice instead + | +LL | wants_write(&mut [0u8][..]); + | ++++ + +error[E0277]: the trait bound `&[u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-3.rs:18:17 + | +LL | wants_write(&[0u8]); + | ----------- ^^^^^^ the trait `Write` is not implemented for `&[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-3.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` + +error[E0277]: the trait bound `&[u8]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-3.rs:20:17 + | +LL | wants_write(&[0u8][..]); + | ----------- ^^^^^^^^^^ the trait `Write` is not implemented for `&[u8]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-3.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: consider changing this borrow's mutability + | +LL | wants_write(&mut [0u8][..]); + | ~~~~ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-4.rs b/tests/ui/dst/issue-90528-unsizing-suggestion-4.rs new file mode 100644 index 0000000000000..eae953c61ff09 --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-4.rs @@ -0,0 +1,26 @@ +// Issue #90528: provide helpful suggestions when a trait bound is unsatisfied +// due to a missed unsizing coercion. +// +// This test exercises array variables and a trait implemented on mutable slices. + +trait Write {} + +impl Write for &mut [u8] {} + +fn wants_write(_: impl Write) {} + +fn main() { + let mut x = [0u8]; + wants_write(x); + //~^ ERROR the trait bound `[u8; 1]: Write` is not satisfied + wants_write(&mut x); + //~^ ERROR the trait bound `&mut [u8; 1]: Write` is not satisfied + wants_write(&mut x[..]); + + let x = &mut [0u8]; + wants_write(x); + //~^ ERROR the trait bound `&mut [u8; 1]: Write` is not satisfied + wants_write(*x); + //~^ ERROR the trait bound `[u8; 1]: Write` is not satisfied + wants_write(&mut x[..]); +} diff --git a/tests/ui/dst/issue-90528-unsizing-suggestion-4.stderr b/tests/ui/dst/issue-90528-unsizing-suggestion-4.stderr new file mode 100644 index 0000000000000..a4020ee070808 --- /dev/null +++ b/tests/ui/dst/issue-90528-unsizing-suggestion-4.stderr @@ -0,0 +1,79 @@ +error[E0277]: the trait bound `[u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-4.rs:14:17 + | +LL | wants_write(x); + | ----------- ^ the trait `Write` is not implemented for `[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-4.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: convert the array to a `&mut [u8]` slice instead + | +LL | wants_write(&mut x[..]); + | ++++ ++++ + +error[E0277]: the trait bound `&mut [u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-4.rs:16:17 + | +LL | wants_write(&mut x); + | ----------- ^^^^^^ the trait `Write` is not implemented for `&mut [u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-4.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: convert the array to a `&mut [u8]` slice instead + | +LL | wants_write(&mut x[..]); + | ++++ + +error[E0277]: the trait bound `&mut [u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-4.rs:21:17 + | +LL | wants_write(x); + | ----------- ^ the trait `Write` is not implemented for `&mut [u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-4.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: convert the array to a `&mut [u8]` slice instead + | +LL | wants_write(&mut x[..]); + | ++++ ++++ + +error[E0277]: the trait bound `[u8; 1]: Write` is not satisfied + --> $DIR/issue-90528-unsizing-suggestion-4.rs:23:17 + | +LL | wants_write(*x); + | ----------- ^^ the trait `Write` is not implemented for `[u8; 1]` + | | + | required by a bound introduced by this call + | + = help: the trait `Write` is implemented for `&mut [u8]` +note: required by a bound in `wants_write` + --> $DIR/issue-90528-unsizing-suggestion-4.rs:10:24 + | +LL | fn wants_write(_: impl Write) {} + | ^^^^^ required by this bound in `wants_write` +help: convert the array to a `&mut [u8]` slice instead + | +LL | wants_write(&mut *x[..]); + | ++++ ++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. From 29b0befd18b91e8af9ca039526e4aa0c05fb0f2b Mon Sep 17 00:00:00 2001 From: Alex Huang Date: Fri, 10 Mar 2023 08:23:45 -0500 Subject: [PATCH 03/18] bootstrap: document tidy --- src/bootstrap/builder.rs | 1 + src/bootstrap/doc.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9b5e116aa5c9c..bba7281052872 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -741,6 +741,7 @@ impl<'a> Builder<'a> { doc::EmbeddedBook, doc::EditionGuide, doc::StyleGuide, + doc::Tidy, ), Kind::Dist => describe!( dist::Docs, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index cc80763ef4495..36fdd4abf4ffc 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -882,6 +882,7 @@ tool_doc!( // "cargo-credential-wincred", ] ); +tool_doc!(Tidy, "tidy", "src/tools/tidy", ["tidy"]); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { From b7a7077ba44b0d0ea561c0210dbc02f42cb0fc6d Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 11 Mar 2023 11:25:03 +0100 Subject: [PATCH 04/18] Give proper error message when tcx wasn't passed to decoder --- compiler/rustc_metadata/src/rmeta/decoder.rs | 23 +++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b1e59b0a470b5..771fb09113437 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -311,8 +311,11 @@ impl LazyArray { impl<'a, 'tcx> DecodeContext<'a, 'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { - debug_assert!(self.tcx.is_some(), "missing TyCtxt in DecodeContext"); - self.tcx.unwrap() + let Some(tcx) = self.tcx else { + bug!("No TyCtxt found for decoding. \ + You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."); + }; + tcx } #[inline] @@ -454,7 +457,12 @@ impl<'a, 'tcx> Decodable> for ast::AttrId { impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext { let cdata = decoder.cdata(); - let sess = decoder.sess.unwrap(); + + let Some(sess) = decoder.sess else { + bug!("Cannot decode SyntaxContext without Session.\ + You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."); + }; + let cname = cdata.root.name; rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| { debug!("SpecializedDecoder: decoding {}", id); @@ -471,7 +479,11 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId { let local_cdata = decoder.cdata(); - let sess = decoder.sess.unwrap(); + + let Some(sess) = decoder.sess else { + bug!("Cannot decode ExpnId without Session. \ + You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."); + }; let cnum = CrateNum::decode(decoder); let index = u32::decode(decoder); @@ -520,7 +532,8 @@ impl<'a, 'tcx> Decodable> for Span { let hi = lo + len; let Some(sess) = decoder.sess else { - bug!("Cannot decode Span without Session.") + bug!("Cannot decode Span without Session. \ + You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`.") }; // Index of the file in the corresponding crate's list of encoded files. From 898d2c14e3e538056800499598b54e3d2daa5b87 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 11 Mar 2023 16:15:06 +0300 Subject: [PATCH 05/18] remove duplicated calls to sort_string --- compiler/rustc_middle/src/ty/error.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 9c171a69d064f..aff6c77e039af 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -151,12 +151,8 @@ impl<'tcx> TypeError<'tcx> { .into(), RegionsPlaceholderMismatch => "one type is more general than the other".into(), ArgumentSorts(values, _) | Sorts(values) => { - let mut expected = values.expected.sort_string(tcx); - let mut found = values.found.sort_string(tcx); - if expected == found { - expected = values.expected.sort_string(tcx); - found = values.found.sort_string(tcx); - } + let expected = values.expected.sort_string(tcx); + let found = values.found.sort_string(tcx); report_maybe_different(&expected, &found).into() } Traits(values) => { From 9a24e2fee959fa9a7c3493489dba0223bfbc8928 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 11 Mar 2023 07:49:22 -0600 Subject: [PATCH 06/18] Expand on the allocator comment in `rustc-main` Before, it said "global_allocator does nothing". Now it gives you suggestions for what to do if you want to change the global allocator (which is likely the main reason you'd be reading the comment). --- compiler/rustc/src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index e21c9b6604440..f5536b78bebf9 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -24,6 +24,15 @@ // The two crates we link to here, `std` and `rustc_driver`, are both dynamic // libraries. So we must reference jemalloc symbols one way or another, because // this file is the only object code in the rustc executable. +// +// NOTE: if you are reading this comment because you want to set a custom `global_allocator` for +// benchmarking, consider using the benchmarks in the `rustc-perf` collector suite instead: +// https://github.com/rust-lang/rustc-perf/blob/master/collector/README.md#profiling +// +// NOTE: if you are reading this comment because you want to replace jemalloc with another allocator +// to compare their performance, see +// https://github.com/fee1-dead-contrib/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef +// for an example of how to do so. #[unix_sigpipe = "sig_dfl"] fn main() { From e89bd9428f621545c979c0ec686addc6563a394e Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 11 Mar 2023 10:53:47 -0600 Subject: [PATCH 07/18] fix link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémy Rakic --- compiler/rustc/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index f5536b78bebf9..434b978ae3151 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -31,7 +31,7 @@ // // NOTE: if you are reading this comment because you want to replace jemalloc with another allocator // to compare their performance, see -// https://github.com/fee1-dead-contrib/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef +// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef // for an example of how to do so. #[unix_sigpipe = "sig_dfl"] From cde0b164d28382da7de892172d9129f21f8bb179 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Mar 2023 04:24:09 +0100 Subject: [PATCH 08/18] tidy: allow direct format args capture in macro --- src/tools/tidy/src/style.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 9ecb30529cc92..8b10c635ef4f3 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -171,9 +171,9 @@ fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> } macro_rules! suppressible_tidy_err { - ($err:ident, $skip:ident, $msg:expr) => { + ($err:ident, $skip:ident, $msg:literal) => { if let Directive::Deny = $skip { - $err($msg); + $err(&format!($msg)); } else { $skip = Directive::Ignore(true); } @@ -351,7 +351,7 @@ pub fn check(path: &Path, bad: &mut bool) { suppressible_tidy_err!( err, skip_line_length, - &format!("line longer than {max_columns} chars") + "line longer than {max_columns} chars" ); } if !is_style_file && line.contains('\t') { @@ -441,7 +441,7 @@ pub fn check(path: &Path, bad: &mut bool) { n => suppressible_tidy_err!( err, skip_trailing_newlines, - &format!("too many trailing newlines ({n})") + "too many trailing newlines ({n})" ), }; if lines > LINES { From 7a686bf41dbaf065203336c1e99e0406de621587 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 3 Mar 2023 08:04:53 +0100 Subject: [PATCH 09/18] tidy: enforce comment blocks to have even number of backticks Some comments may be formed like: // This function takes a tuple `(Vec, // Box<[u8]>)` and transforms it into `Vec`. where the "back-ticked" section wraps around. Therefore, we can't make a single-line based lint. We also cannot make the lint paragraph based, as it would otherwise complain about inline code blocks: /// ``` /// use super::Foo; /// /// fn main() { Foo::new(); } /// ``` For the future, one could introduce some checks to treat code blocks specially, but such code would make the check even more complicated. --- src/tools/tidy/src/style.rs | 56 +++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 8b10c635ef4f3..af6231ed0df7a 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -300,10 +300,13 @@ pub fn check(path: &Path, bad: &mut bool) { contains_ignore_directive(can_contain, &contents, "leading-newlines"); let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright"); let mut skip_dbg = contains_ignore_directive(can_contain, &contents, "dbg"); + let mut skip_odd_backticks = + contains_ignore_directive(can_contain, &contents, "odd-backticks"); let mut leading_new_lines = false; let mut trailing_new_lines = 0; let mut lines = 0; let mut last_safety_comment = false; + let mut comment_block: Option<(usize, usize)> = None; let is_test = file.components().any(|c| c.as_os_str() == "tests"); // scanning the whole file for multiple needles at once is more efficient than // executing lines times needles separate searches. @@ -415,15 +418,50 @@ pub fn check(path: &Path, bad: &mut bool) { // For now only enforce in compiler let is_compiler = || file.components().any(|c| c.as_os_str() == "compiler"); - if is_compiler() - && line.contains("//") - && line - .chars() - .collect::>() - .windows(4) - .any(|cs| matches!(cs, ['.', ' ', ' ', last] if last.is_alphabetic())) - { - err(DOUBLE_SPACE_AFTER_DOT) + + if is_compiler() { + if line.contains("//") + && line + .chars() + .collect::>() + .windows(4) + .any(|cs| matches!(cs, ['.', ' ', ' ', last] if last.is_alphabetic())) + { + err(DOUBLE_SPACE_AFTER_DOT) + } + + if line.contains("//") { + let (start_line, mut backtick_count) = comment_block.unwrap_or((i + 1, 0)); + let line_backticks = line.chars().filter(|ch| *ch == '`').count(); + let comment_text = line.split("//").nth(1).unwrap(); + // This check ensures that we don't lint for code that has `//` in a string literal + if line_backticks % 2 == 1 { + backtick_count += comment_text.chars().filter(|ch| *ch == '`').count(); + } + comment_block = Some((start_line, backtick_count)); + } else { + if let Some((start_line, backtick_count)) = comment_block.take() { + if backtick_count % 2 == 1 { + let mut err = |msg: &str| { + tidy_error!(bad, "{}:{start_line}: {msg}", file.display()); + }; + let block_len = (i + 1) - start_line; + if block_len == 1 { + suppressible_tidy_err!( + err, + skip_odd_backticks, + "comment with odd number of backticks" + ); + } else { + suppressible_tidy_err!( + err, + skip_odd_backticks, + "{block_len}-line comment block with odd number of backticks" + ); + } + } + } + } } } if leading_new_lines { From 7f4cc178f07fca98aee1b58bb4f82b2f45f8afac Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Mar 2023 04:25:36 +0100 Subject: [PATCH 10/18] Address the new odd backticks tidy lint in compiler/ --- compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 1 + .../rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs | 1 + compiler/rustc_error_codes/src/error_codes/E0368.md | 2 +- compiler/rustc_error_codes/src/error_codes/E0710.md | 4 ++-- .../error_reporting/nice_region_error/static_impl_trait.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 1 + compiler/rustc_mir_build/src/build/matches/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 2 +- compiler/rustc_type_ir/src/fold.rs | 2 +- 9 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 1f819beeb5d7d..6b3053fdfac7e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1052,6 +1052,7 @@ impl<'a> MethodDef<'a> { /// ::core::hash::Hash::hash(&{ self.y }, state) /// } /// } + /// ``` fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 93419d27a6236..978141917c6b0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -438,6 +438,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( /// DW_TAG_structure_type (type of variant 1) /// DW_TAG_structure_type (type of variant 2) /// DW_TAG_structure_type (type of variant 3) +/// ``` struct VariantMemberInfo<'a, 'll> { variant_index: VariantIdx, variant_name: Cow<'a, str>, diff --git a/compiler/rustc_error_codes/src/error_codes/E0368.md b/compiler/rustc_error_codes/src/error_codes/E0368.md index 7b9d933482131..b18e8758d712e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0368.md +++ b/compiler/rustc_error_codes/src/error_codes/E0368.md @@ -41,7 +41,7 @@ impl Add for Foo { fn main() { let mut x: Foo = Foo(5); - x += Foo(7); // error, `+= cannot be applied to the type `Foo` + x += Foo(7); // error, `+=` cannot be applied to the type `Foo` } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0710.md b/compiler/rustc_error_codes/src/error_codes/E0710.md index b7037ea611ba2..84d55d524267e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0710.md +++ b/compiler/rustc_error_codes/src/error_codes/E0710.md @@ -3,14 +3,14 @@ An unknown tool name was found in a scoped lint. Erroneous code examples: ```compile_fail,E0710 -#[allow(clipp::filter_map)] // error!` +#[allow(clipp::filter_map)] // error! fn main() { // business logic } ``` ```compile_fail,E0710 -#[warn(clipp::filter_map)] // error!` +#[warn(clipp::filter_map)] // error! fn main() { // business logic } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index b06ff10d86eb0..22c1e3871175e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -104,7 +104,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { // Account for `async fn` like in `async-await/issues/issue-62097.rs`. - // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same + // The desugaring of `async fn`s causes `sup_origin` and `param` to point at the same // place (but with different `ctxt`, hence `overlaps` instead of `==` above). // // This avoids the following: diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index d8829e3e782c5..7e51953599d5a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -123,6 +123,7 @@ fn dump_matched_mir_node<'tcx, F>( // see notes on #41697 above let def_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + // ignore-tidy-odd-backticks the literal below is fine write!(file, "// MIR for `{}", def_path)?; match body.source.promoted { None => write!(file, "`")?, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 9414d9bfa0863..3fb8a6db2d27a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1886,6 +1886,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let place = Foo::new(); // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) } // => { let tmp2 = place; feed(tmp2) }, ... } + // ``` // // And an input like: // diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9ab753c5a4826..c93c26cc04b9e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2220,7 +2220,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // - `BuiltinDerivedObligation` with a generator witness (A) // - `BuiltinDerivedObligation` with a generator (A) // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) - // - `BindingObligation` with `impl_send (Send requirement) + // - `BindingObligation` with `impl_send` (Send requirement) // // The first obligation in the chain is the most useful and has the generator that captured // the type. The last generator (`outer_generator` below) has information about where the diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index ee4ef57c38f11..3a053d4c6a997 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -18,7 +18,7 @@ //! It defines a "skeleton" of how they should be folded. //! - `TypeSuperFoldable`. This is implemented only for each type of interest, //! and defines the folding "skeleton" for these types. -//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each +//! - `TypeFolder`/`FallibleTypeFolder`. One of these is implemented for each //! folder. This defines how types of interest are folded. //! //! This means each fold is a mixture of (a) generic folding operations, and (b) From 9475717ea302b43dcca2ccf49628525cfe82fbf7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Mar 2023 06:20:03 +0100 Subject: [PATCH 11/18] Add a fixme and address a more non trivial case Co-authored-by: nils <48135649+Nilstrieb@users.noreply.github.com> --- compiler/rustc_hir_typeck/src/closure.rs | 2 +- compiler/rustc_trait_selection/src/solve/assembly.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d84fabb783490..773ac0e40c571 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -398,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Here: /// - E would be `fn(&u32) -> &u32`. - /// - S would be `fn(&u32) -> + /// - S would be `fn(&u32) -> ?T` /// - E' is `&'!0 u32 -> &'!0 u32` /// - S' is `&'?0 u32 -> ?T` /// diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index dec9f8016b0c1..626b44d08e7e6 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -247,7 +247,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// /// To deal with this, we first try to normalize the self type and add the candidates for the normalized /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in - /// this case as projections as self types add ` + /// this case as projections as self types add + // FIXME complete the unfinished sentence above fn assemble_candidates_after_normalizing_self_ty>( &mut self, goal: Goal<'tcx, G>, From 3a20d52694c9a293d2fbf1aa7cc1c1643b3e30ec Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Mar 2023 06:55:35 +0100 Subject: [PATCH 12/18] Extend the tidy lint to ftl files --- src/tools/tidy/src/style.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index af6231ed0df7a..e3f98f42d7d44 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -430,7 +430,12 @@ pub fn check(path: &Path, bad: &mut bool) { err(DOUBLE_SPACE_AFTER_DOT) } - if line.contains("//") { + if filename.ends_with(".ftl") { + let line_backticks = line.chars().filter(|ch| *ch == '`').count(); + if line_backticks % 2 == 1 { + suppressible_tidy_err!(err, skip_odd_backticks, "odd number of backticks"); + } + } else if line.contains("//") { let (start_line, mut backtick_count) = comment_block.unwrap_or((i + 1, 0)); let line_backticks = line.chars().filter(|ch| *ch == '`').count(); let comment_text = line.split("//").nth(1).unwrap(); From b2aeb071370afeefceec4d21734e801837dd72e4 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Mar 2023 21:41:24 +0100 Subject: [PATCH 13/18] Use trimmed instead of line for performance --- src/tools/tidy/src/style.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index e3f98f42d7d44..75a4586cb7f1c 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -431,14 +431,14 @@ pub fn check(path: &Path, bad: &mut bool) { } if filename.ends_with(".ftl") { - let line_backticks = line.chars().filter(|ch| *ch == '`').count(); + let line_backticks = trimmed.chars().filter(|ch| *ch == '`').count(); if line_backticks % 2 == 1 { suppressible_tidy_err!(err, skip_odd_backticks, "odd number of backticks"); } - } else if line.contains("//") { + } else if trimmed.contains("//") { let (start_line, mut backtick_count) = comment_block.unwrap_or((i + 1, 0)); - let line_backticks = line.chars().filter(|ch| *ch == '`').count(); - let comment_text = line.split("//").nth(1).unwrap(); + let line_backticks = trimmed.chars().filter(|ch| *ch == '`').count(); + let comment_text = trimmed.split("//").nth(1).unwrap(); // This check ensures that we don't lint for code that has `//` in a string literal if line_backticks % 2 == 1 { backtick_count += comment_text.chars().filter(|ch| *ch == '`').count(); From 856c9bb481bed032f177d29288e348d6d8e060be Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2023 21:37:59 +0100 Subject: [PATCH 14/18] Add eslint checks for rustdoc-js tester --- src/tools/rustdoc-js/.eslintrc.js | 96 +++++++++++++++++++++++++++++++ src/tools/rustdoc-js/tester.js | 76 ++++++++++++------------ 2 files changed, 134 insertions(+), 38 deletions(-) create mode 100644 src/tools/rustdoc-js/.eslintrc.js diff --git a/src/tools/rustdoc-js/.eslintrc.js b/src/tools/rustdoc-js/.eslintrc.js new file mode 100644 index 0000000000000..4ab3a31573309 --- /dev/null +++ b/src/tools/rustdoc-js/.eslintrc.js @@ -0,0 +1,96 @@ +module.exports = { + "env": { + "browser": true, + "node": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2015, + "sourceType": "module" + }, + "rules": { + "linebreak-style": [ + "error", + "unix" + ], + "semi": [ + "error", + "always" + ], + "quotes": [ + "error", + "double" + ], + "linebreak-style": [ + "error", + "unix" + ], + "no-trailing-spaces": "error", + "no-var": ["error"], + "prefer-const": ["error"], + "prefer-arrow-callback": ["error"], + "brace-style": [ + "error", + "1tbs", + { "allowSingleLine": false } + ], + "keyword-spacing": [ + "error", + { "before": true, "after": true } + ], + "arrow-spacing": [ + "error", + { "before": true, "after": true } + ], + "key-spacing": [ + "error", + { "beforeColon": false, "afterColon": true, "mode": "strict" } + ], + "func-call-spacing": ["error", "never"], + "space-infix-ops": "error", + "space-before-function-paren": ["error", "never"], + "space-before-blocks": "error", + "comma-dangle": ["error", "always-multiline"], + "comma-style": ["error", "last"], + "max-len": ["error", { "code": 100, "tabWidth": 4 }], + "eol-last": ["error", "always"], + "arrow-parens": ["error", "as-needed"], + "no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "eqeqeq": "error", + "no-const-assign": "error", + "no-debugger": "error", + "no-dupe-args": "error", + "no-dupe-else-if": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-ex-assign": "error", + "no-fallthrough": "error", + "no-invalid-regexp": "error", + "no-import-assign": "error", + "no-self-compare": "error", + "no-template-curly-in-string": "error", + "block-scoped-var": "error", + "guard-for-in": "error", + "no-alert": "error", + "no-confusing-arrow": "error", + "no-div-regex": "error", + "no-floating-decimal": "error", + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-label-var": "error", + "no-lonely-if": "error", + "no-mixed-operators": "error", + "no-multi-assign": "error", + "no-return-assign": "error", + "no-script-url": "error", + "no-sequences": "error", + "no-div-regex": "error", + } +}; diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index e617ceba3b951..9bd6e0d990d1e 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -1,5 +1,5 @@ -const fs = require('fs'); -const path = require('path'); +const fs = require("fs"); +const path = require("path"); function loadContent(content) { const Module = module.constructor; @@ -15,7 +15,7 @@ function loadContent(content) { } function readFile(filePath) { - return fs.readFileSync(filePath, 'utf8'); + return fs.readFileSync(filePath, "utf8"); } function contentToDiffLine(key, value) { @@ -25,41 +25,41 @@ function contentToDiffLine(key, value) { // This function is only called when no matching result was found and therefore will only display // the diff between the two items. function betterLookingDiff(entry, data) { - let output = ' {\n'; - const spaces = ' '; + let output = " {\n"; + const spaces = " "; for (const key in entry) { - if (!entry.hasOwnProperty(key)) { + if (!Object.prototype.hasOwnProperty.call(entry, key)) { continue; } - if (!data || !data.hasOwnProperty(key)) { - output += '-' + spaces + contentToDiffLine(key, entry[key]) + '\n'; + if (!data || !Object.prototype.hasOwnProperty.call(data, key)) { + output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n"; continue; } const value = data[key]; if (value !== entry[key]) { - output += '-' + spaces + contentToDiffLine(key, entry[key]) + '\n'; - output += '+' + spaces + contentToDiffLine(key, value) + '\n'; + output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n"; + output += "+" + spaces + contentToDiffLine(key, value) + "\n"; } else { - output += spaces + contentToDiffLine(key, value) + '\n'; + output += spaces + contentToDiffLine(key, value) + "\n"; } } - return output + ' }'; + return output + " }"; } function lookForEntry(entry, data) { return data.findIndex(data_entry => { let allGood = true; for (const key in entry) { - if (!entry.hasOwnProperty(key)) { + if (!Object.prototype.hasOwnProperty.call(entry, key)) { continue; } let value = data_entry[key]; // To make our life easier, if there is a "parent" type, we add it to the path. - if (key === 'path' && data_entry['parent'] !== undefined) { + if (key === "path" && data_entry["parent"] !== undefined) { if (value.length > 0) { - value += '::' + data_entry['parent']['name']; + value += "::" + data_entry["parent"]["name"]; } else { - value = data_entry['parent']['name']; + value = data_entry["parent"]["name"]; } } if (value !== entry[key]) { @@ -95,7 +95,7 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position) fieldsToCheck = []; } for (const field of fieldsToCheck) { - if (!expected.hasOwnProperty(field)) { + if (!Object.prototype.hasOwnProperty.call(expected, field)) { let text = `${queryName}==> Mandatory key \`${field}\` is not present`; if (fullPath.length > 0) { text += ` in field \`${fullPath}\``; @@ -117,22 +117,22 @@ function valueCheck(fullPath, expected, result, error_text, queryName) { error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` + `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``); } else { - valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName); + valueCheck(fullPath + "[" + i + "]", expected[i], result[i], error_text, queryName); } } for (; i < result.length; ++i) { error_text.push(`${queryName}==> RESULT has extra value in array from field ` + `\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` + - 'compared to EXPECTED'); + "compared to EXPECTED"); } } else if (expected !== null && typeof expected !== "undefined" && - expected.constructor == Object) { + expected.constructor == Object) { // eslint-disable-line eqeqeq for (const key in expected) { - if (!expected.hasOwnProperty(key)) { + if (!Object.prototype.hasOwnProperty.call(expected, key)) { continue; } - if (!result.hasOwnProperty(key)) { - error_text.push('==> Unknown key "' + key + '"'); + if (!Object.prototype.hasOwnProperty.call(result, key)) { + error_text.push("==> Unknown key \"" + key + "\""); break; } let result_v = result[key]; @@ -147,13 +147,13 @@ function valueCheck(fullPath, expected, result, error_text, queryName) { }); result_v = result_v.join(""); } - const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key; + const obj_path = fullPath + (fullPath.length > 0 ? "." : "") + key; valueCheck(obj_path, expected[key], result_v, error_text, queryName); } } else { const expectedValue = JSON.stringify(expected); const resultValue = JSON.stringify(result); - if (expectedValue != resultValue) { + if (expectedValue !== resultValue) { error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` + `EXPECTED: \`${expectedValue}\`\nRESULT: \`${resultValue}\``); } @@ -164,7 +164,7 @@ function runParser(query, expected, parseQuery, queryName) { const error_text = []; checkNeededFields("", expected, error_text, queryName, null); if (error_text.length === 0) { - valueCheck('', expected, parseQuery(query), error_text, queryName); + valueCheck("", expected, parseQuery(query), error_text, queryName); } return error_text; } @@ -177,16 +177,16 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) { const error_text = []; for (const key in expected) { - if (!expected.hasOwnProperty(key)) { + if (!Object.prototype.hasOwnProperty.call(expected, key)) { continue; } - if (!results.hasOwnProperty(key)) { - error_text.push('==> Unknown key "' + key + '"'); + if (!Object.prototype.hasOwnProperty.call(results, key)) { + error_text.push("==> Unknown key \"" + key + "\""); break; } const entry = expected[key]; - if (exact_check == true && entry.length !== results[key].length) { + if (exact_check && entry.length !== results[key].length) { error_text.push(queryName + "==> Expected exactly " + entry.length + " results but found " + results[key].length + " in '" + key + "'"); } @@ -268,7 +268,7 @@ function runCheck(loadedFile, key, callback) { function runChecks(testFile, doSearch, parseQuery) { let checkExpected = false; let checkParsed = false; - let testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;'; + let testFileContent = readFile(testFile) + "exports.QUERY = QUERY;"; if (testFileContent.indexOf("FILTER_CRATE") !== -1) { testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;"; @@ -277,11 +277,11 @@ function runChecks(testFile, doSearch, parseQuery) { } if (testFileContent.indexOf("\nconst EXPECTED") !== -1) { - testFileContent += 'exports.EXPECTED = EXPECTED;'; + testFileContent += "exports.EXPECTED = EXPECTED;"; checkExpected = true; } if (testFileContent.indexOf("\nconst PARSED") !== -1) { - testFileContent += 'exports.PARSED = PARSED;'; + testFileContent += "exports.PARSED = PARSED;"; checkParsed = true; } if (!checkParsed && !checkExpected) { @@ -325,7 +325,7 @@ function loadSearchJS(doc_folder, resource_suffix) { const searchWords = searchModule.initSearch(searchIndex.searchIndex); return { - doSearch: function (queryStr, filterCrate, currentCrate) { + doSearch: function(queryStr, filterCrate, currentCrate) { return searchModule.execQuery(searchModule.parseQuery(queryStr), searchWords, filterCrate, currentCrate); }, @@ -361,7 +361,7 @@ function parseOptions(args) { }; for (let i = 0; i < args.length; ++i) { - if (correspondences.hasOwnProperty(args[i])) { + if (Object.prototype.hasOwnProperty.call(correspondences, args[i])) { i += 1; if (i >= args.length) { console.log("Missing argument after `" + args[i - 1] + "` option."); @@ -405,17 +405,17 @@ function main(argv) { ); let errors = 0; - const doSearch = function (queryStr, filterCrate) { + const doSearch = function(queryStr, filterCrate) { return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]); }; if (opts["test_file"].length !== 0) { - opts["test_file"].forEach(function (file) { + opts["test_file"].forEach(file => { process.stdout.write(`Testing ${file} ... `); errors += runChecks(file, doSearch, parseAndSearch.parseQuery); }); } else if (opts["test_folder"].length !== 0) { - fs.readdirSync(opts["test_folder"]).forEach(function (file) { + fs.readdirSync(opts["test_folder"]).forEach(file => { if (!file.endsWith(".js")) { return; } From 904d9c5c549745793c98a1c2cd0a2665d30fe34e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2023 21:40:17 +0100 Subject: [PATCH 15/18] Improve rustdoc-js tester code clarity a bit --- src/tools/rustdoc-js/tester.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 9bd6e0d990d1e..8d46a8ce7f1b2 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -361,22 +361,24 @@ function parseOptions(args) { }; for (let i = 0; i < args.length; ++i) { - if (Object.prototype.hasOwnProperty.call(correspondences, args[i])) { + const arg = args[i]; + if (Object.prototype.hasOwnProperty.call(correspondences, arg)) { i += 1; if (i >= args.length) { - console.log("Missing argument after `" + args[i - 1] + "` option."); + console.log("Missing argument after `" + arg + "` option."); return null; } - if (args[i - 1] !== "--test-file") { - opts[correspondences[args[i - 1]]] = args[i]; + const arg_value = args[i]; + if (arg !== "--test-file") { + opts[correspondences[arg]] = arg_value; } else { - opts[correspondences[args[i - 1]]].push(args[i]); + opts[correspondences[arg]].push(arg_value); } - } else if (args[i] === "--help") { + } else if (arg === "--help") { showHelp(); process.exit(0); } else { - console.log("Unknown option `" + args[i] + "`."); + console.log("Unknown option `" + arg + "`."); console.log("Use `--help` to see the list of options"); return null; } From ca9b6180f023d5a8ccf278a48270878daf8ed909 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2023 21:42:11 +0100 Subject: [PATCH 16/18] Add rustdoc-js eslint check into CI --- src/ci/docker/host-x86_64/mingw-check/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 98bd90210d615..9141d3e8a48c2 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -52,4 +52,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ reuse lint && \ # Runs checks to ensure that there are no ES5 issues in our JS code. es-check es6 ../src/librustdoc/html/static/js/*.js && \ - eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js + eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \ + eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js From a2341fbbc2f9b35292473f139d17316a55d9e3d0 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 11 Mar 2023 11:19:25 -0800 Subject: [PATCH 17/18] Introduce `Rc::into_inner`, as a parallel to `Arc::into_inner` Unlike `Arc`, `Rc` doesn't have the same race condition to avoid, but maintaining an equivalent API still makes it easier to work with both `Rc` and `Arc`. --- library/alloc/src/rc.rs | 18 ++++++++++++++++++ library/alloc/src/rc/tests.rs | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c9aa23fc4af1f..0e0cf145a992f 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -681,6 +681,24 @@ impl Rc { Err(this) } } + + /// Returns the inner value, if the `Rc` has exactly one strong reference. + /// + /// Otherwise, [`None`] is returned and the `Rc` is dropped. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// If `Rc::into_inner` is called on every clone of this `Rc`, + /// it is guaranteed that exactly one of the calls returns the inner value. + /// This means in particular that the inner value is not dropped. + /// + /// This is equivalent to `Rc::try_unwrap(...).ok()`. (Note that these are not equivalent for + /// `Arc`, due to race conditions that do not apply to `Rc`.) + #[inline] + #[unstable(feature = "rc_into_inner", issue = "106894")] + pub fn into_inner(this: Self) -> Option { + Rc::try_unwrap(this).ok() + } } impl Rc<[T]> { diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 32433cfbdcff6..342dc686fa3cb 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -151,6 +151,22 @@ fn try_unwrap() { assert_eq!(Rc::try_unwrap(x), Ok(5)); } +#[test] +fn into_inner() { + let x = Rc::new(3); + assert_eq!(Rc::into_inner(x), Some(3)); + + let x = Rc::new(4); + let y = Rc::clone(&x); + assert_eq!(Rc::into_inner(x), None); + assert_eq!(Rc::into_inner(y), Some(4)); + + let x = Rc::new(5); + let _w = Rc::downgrade(&x); + assert_eq!(Rc::into_inner(x), Some(5)); +} + + #[test] fn into_from_raw() { let x = Rc::new(Box::new("hello")); From 1c4603e3b036b3f1292feb1a073fc7f3221a4321 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 11 Mar 2023 23:16:46 +0000 Subject: [PATCH 18/18] Commit some tests for the new solver + lazy norm --- .../cast-checks-handling-projections.rs | 0 .../equating-projection-cyclically.rs | 0 .../equating-projection-cyclically.stderr | 0 .../new-solver/lazy-nested-obligations-1.rs | 13 ++++++ .../new-solver/lazy-nested-obligations-2.rs | 23 +++++++++++ .../new-solver/lazy-nested-obligations-3.rs | 38 ++++++++++++++++++ .../new-solver/normalize-param-env-1.rs | 40 +++++++++++++++++++ .../new-solver/normalize-param-env-2.rs | 26 ++++++++++++ .../new-solver/normalize-param-env-3.rs | 32 +++++++++++++++ 9 files changed, 172 insertions(+) rename tests/ui/{typeck/lazy-norm => traits/new-solver}/cast-checks-handling-projections.rs (100%) rename tests/ui/{typeck/lazy-norm => traits/new-solver}/equating-projection-cyclically.rs (100%) rename tests/ui/{typeck/lazy-norm => traits/new-solver}/equating-projection-cyclically.stderr (100%) create mode 100644 tests/ui/traits/new-solver/lazy-nested-obligations-1.rs create mode 100644 tests/ui/traits/new-solver/lazy-nested-obligations-2.rs create mode 100644 tests/ui/traits/new-solver/lazy-nested-obligations-3.rs create mode 100644 tests/ui/traits/new-solver/normalize-param-env-1.rs create mode 100644 tests/ui/traits/new-solver/normalize-param-env-2.rs create mode 100644 tests/ui/traits/new-solver/normalize-param-env-3.rs diff --git a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs b/tests/ui/traits/new-solver/cast-checks-handling-projections.rs similarity index 100% rename from tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs rename to tests/ui/traits/new-solver/cast-checks-handling-projections.rs diff --git a/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs b/tests/ui/traits/new-solver/equating-projection-cyclically.rs similarity index 100% rename from tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs rename to tests/ui/traits/new-solver/equating-projection-cyclically.rs diff --git a/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr b/tests/ui/traits/new-solver/equating-projection-cyclically.stderr similarity index 100% rename from tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr rename to tests/ui/traits/new-solver/equating-projection-cyclically.stderr diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-1.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-1.rs new file mode 100644 index 0000000000000..af00cbb3ba827 --- /dev/null +++ b/tests/ui/traits/new-solver/lazy-nested-obligations-1.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +// Issue 94358 + +fn foo(_: C) +where + for <'a> &'a C: IntoIterator, + for <'a> <&'a C as IntoIterator>::IntoIter: ExactSizeIterator, +{} + +fn main() { + foo::<_>(vec![true, false]); +} diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs new file mode 100644 index 0000000000000..32addd829dcfd --- /dev/null +++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs @@ -0,0 +1,23 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +// Issue 95863 + +pub trait With { + type F; +} + +impl With for i32 { + type F = fn(&str); +} + +fn f(_: &str) {} + +fn main() { + let _: V = V(f); + pub struct V(::F); + + pub enum E3 { + Var(::F), + } + let _: E3 = E3::Var(f); +} diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-3.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-3.rs new file mode 100644 index 0000000000000..baf3995724023 --- /dev/null +++ b/tests/ui/traits/new-solver/lazy-nested-obligations-3.rs @@ -0,0 +1,38 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +// Issue 96750 + +use std::marker::PhantomData; + +trait AsyncFn { + type Output; +} +trait RequestFamily { + type Type<'a>; +} +trait Service {} + +struct MyFn; +impl AsyncFn for MyFn { + type Output = (); +} + +impl RequestFamily for String { + type Type<'a> = String; +} + +struct ServiceFromAsyncFn(F, PhantomData); + +impl Service for ServiceFromAsyncFn +where + Req: RequestFamily, + F: AsyncFn, + F: for<'a> AsyncFn, Output = O>, +{ +} + +fn assert_service() -> impl Service { + ServiceFromAsyncFn(MyFn, PhantomData) +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/normalize-param-env-1.rs b/tests/ui/traits/new-solver/normalize-param-env-1.rs new file mode 100644 index 0000000000000..b02a5d623307a --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-param-env-1.rs @@ -0,0 +1,40 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +// Issue 108933 + +trait Add { + type Sum; +} + +impl Add<()> for () { + type Sum = (); +} + +type Unit = <() as Add<()>>::Sum; + +trait Trait { + type Output; +} + +fn f() +where + T: Trait<()>, + >::Output: Sized, +{ +} + +fn g() +where + T: Trait, + >::Output: Sized, +{ +} + +fn h() +where + T: Trait<()>, + >::Output: Sized, +{ +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/normalize-param-env-2.rs b/tests/ui/traits/new-solver/normalize-param-env-2.rs new file mode 100644 index 0000000000000..7c2cebdd2002f --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-param-env-2.rs @@ -0,0 +1,26 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +// Issue 92505 + +trait A { + type I; + + fn f() + where + Self::I: A, + { + } +} + +impl A for () { + type I = (); + + fn f() + where + Self::I: A, + { + <() as A>::f(); + } +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/normalize-param-env-3.rs b/tests/ui/traits/new-solver/normalize-param-env-3.rs new file mode 100644 index 0000000000000..ce2974b2a16f4 --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-param-env-3.rs @@ -0,0 +1,32 @@ +// check-pass +// compile-flags: -Ztrait-solver=next +// Issue 100177 + +trait GenericTrait {} + +trait Channel: GenericTrait { + type T; +} + +trait Sender { + type Msg; + + fn send() + where + C: Channel; +} + +impl Sender for T { + type Msg = (); + + fn send() + where + C: Channel, + { + } +} + +// This works +fn foo(ch: C) where C: Channel {} + +fn main() {}