From 26ca71fdb2070ae970ea9ce40a52a7b663897940 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 9 Nov 2021 20:21:51 +0100 Subject: [PATCH 01/11] normalize argument b in equate_normalized_inputs_output --- .../src/type_check/input_output.rs | 60 ++++++++++++------- compiler/rustc_borrowck/src/type_check/mod.rs | 5 +- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 24332690bec31..92d2d04f23f23 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,13 +7,16 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). +use crate::type_check::constraint_conversion::ConstraintConversion; use rustc_index::vec::Idx; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::*; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_span::Span; -use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; +use rustc_trait_selection::traits::query::Fallible; +use type_op::TypeOpOutput; use crate::universal_regions::UniversalRegions; @@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let (&normalized_output_ty, normalized_input_tys) = normalized_inputs_and_output.split_last().unwrap(); + debug!(?normalized_output_ty); + debug!(?normalized_input_tys); + let mir_def_id = body.source.def_id().expect_local(); // If the user explicitly annotated the input types, extract @@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); break; } + // In MIR, argument N is stored in local N+1. let local = Local::new(argument_index + 1); let mir_input_ty = body.local_decls[local].ty; + let mir_input_span = body.local_decls[local].source_info.span; self.equate_normalized_input_or_output( normalized_input_ty, @@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // If the user explicitly annotated the input types, enforce those. let user_provided_input_ty = self.normalize(user_provided_input_ty, Locations::All(mir_input_span)); + self.equate_normalized_input_or_output( user_provided_input_ty, mir_input_ty, @@ -167,30 +176,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd // like to normalize *before* inserting into `local_decls`, but // doing so ends up causing some other trouble. - let b = match self - .infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(b) - { - Ok(n) => { - debug!("equate_inputs_and_outputs: {:?}", n); - if n.obligations.iter().all(|o| { - matches!( - o.predicate.kind().skip_binder(), - ty::PredicateKind::RegionOutlives(_) - | ty::PredicateKind::TypeOutlives(_) - ) - }) { - n.value - } else { - b - } - } + let b = match self.normalize_and_add_constraints(b) { + Ok(n) => n, Err(_) => { debug!("equate_inputs_and_outputs: NoSolution"); b } }; + // Note: if we have to introduce new placeholders during normalization above, then we won't have // added those universes to the universe info, which we would want in `relate_tys`. if let Err(terr) = @@ -207,4 +200,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } + + pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible> { + let TypeOpOutput { output: norm_ty, constraints, .. } = + self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?; + + debug!("{:?} normalized to {:?}", t, norm_ty); + + for data in constraints.into_iter().collect::>() { + ConstraintConversion::new( + self.infcx, + &self.borrowck_context.universal_regions, + &self.region_bound_pairs, + Some(self.implicit_region_bound), + self.param_env, + Locations::All(DUMMY_SP), + ConstraintCategory::Internal, + &mut self.borrowck_context.constraints, + ) + .convert_all(&*data); + } + + Ok(norm_ty) + } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ddd077c22faf8..da26d9c7b8779 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -893,11 +893,11 @@ struct TypeChecker<'a, 'tcx> { } struct BorrowCheckContext<'a, 'tcx> { - universal_regions: &'a UniversalRegions<'tcx>, + pub(crate) universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, all_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, upvars: &'a [Upvar<'tcx>], } @@ -1157,6 +1157,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) } + #[instrument(skip(self, category), level = "debug")] fn eq_types( &mut self, expected: Ty<'tcx>, From 7a4aa65810b1e77f5bbfa442ca36b6fd9530e4be Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 9 Nov 2021 20:41:13 +0100 Subject: [PATCH 02/11] add tests --- .../normalize-under-binder/issue-90612.rs | 43 +++++++++++++++++++ .../normalize-under-binder/issue-90638.rs | 37 ++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs create mode 100644 src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs new file mode 100644 index 0000000000000..e150ecfe9a0dc --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs @@ -0,0 +1,43 @@ +// check-pass + +#![feature(generic_associated_types)] + +use std::marker::PhantomData; + +trait Family: Sized { + type Item<'a>; + + fn apply_all(&self, f: F) + where + F: FamilyItemFn { } +} + +struct Array(PhantomData); + +impl Family for Array { + type Item<'a> = &'a T; +} + +trait FamilyItemFn { + fn apply(&self, item: T::Item<'_>); +} + +impl FamilyItemFn for F +where + T: Family, + for<'a> F: Fn(T::Item<'a>) +{ + fn apply(&self, item: T::Item<'_>) { + (*self)(item); + } +} + +fn process(array: Array) { + // Works + array.apply_all(|x: &T| { }); + + // ICE: NoSolution + array.apply_all(|x: as Family>::Item<'_>| { }); +} + +fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs new file mode 100644 index 0000000000000..18b7f383482a1 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs @@ -0,0 +1,37 @@ +//check-pass + +#![feature(generic_associated_types)] + +trait Yokeable<'a>: 'static { + type Output: 'a; +} + +trait IsCovariant<'a> {} + +struct Yoke Yokeable<'a>> { + data: Y, +} + +impl Yokeable<'a>> Yoke { + fn project Yokeable<'a>>(&self, _f: for<'a> fn(>::Output, &'a ()) + -> >::Output) -> Yoke { + + unimplemented!() + } +} + +fn _upcast(x: Yoke) -> Yoke + 'static>> where + Y: for<'a> Yokeable<'a>, + for<'a> >::Output: IsCovariant<'a> + { + x.project(|data, _| { + Box::new(data) + }) +} + + +impl<'a> Yokeable<'a> for Box + 'static> { + type Output = Box + 'a>; +} + +fn main() {} From d58d52a39759960009ca2817f7edcdf22d8722df Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Thu, 11 Nov 2021 18:28:19 -0500 Subject: [PATCH 03/11] Fix handling of substitutions and binders when deciding whether to suggest references When suggesting references, substitutions were being forgotten and some types were misused. This led to at least one ICE and other incorrectly emitted diagnostics. This has been fixed; in some cases this leads to diagnostics changing, and tests have been adjusted. --- .../src/traits/error_reporting/suggestions.rs | 59 +++++++------------ src/test/ui/derives/deriving-copyclone.stderr | 6 +- .../negated-auto-traits-error.stderr | 12 +--- ...ue-90804-incorrect-reference-suggestion.rs | 11 ++++ ...0804-incorrect-reference-suggestion.stderr | 17 ++++++ 5 files changed, 55 insertions(+), 50 deletions(-) create mode 100644 src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs create mode 100644 src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr 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 b21936a00b04f..89aa507061af0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -706,36 +706,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } let param_env = obligation.param_env; - let trait_ref = poly_trait_ref.skip_binder(); - - let found_ty = trait_ref.self_ty(); - let found_ty_str = found_ty.to_string(); - let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty); - let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]); - let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty); - let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&expected_trait_ref.def_id()) { + if blacklist.contains(&old_ref.def_id()) { return false; } - let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_imm_trait_ref.without_const().to_predicate(self.tcx), - )); - - let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_mut_trait_ref.without_const().to_predicate(self.tcx), - )); + let orig_ty = old_ref.self_ty().skip_binder(); + let mk_result = |new_ty| { + let new_ref = old_ref.rebind(ty::TraitRef::new( + old_ref.def_id(), + self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]), + )); + self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + new_ref.without_const().to_predicate(self.tcx), + )) + }; + let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty)); + let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty)); if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -747,8 +740,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let msg = format!( "the trait bound `{}: {}` is not satisfied", - found_ty_str, - expected_trait_ref.print_only_trait_path(), + orig_ty.to_string(), + old_ref.print_only_trait_path(), ); if has_custom_message { err.note(&msg); @@ -764,7 +757,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, &format!( "expected an implementor of trait `{}`", - expected_trait_ref.print_only_trait_path(), + old_ref.print_only_trait_path(), ), ); @@ -807,21 +800,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { - let expected_trait_ref = obligation.parent_trait_ref; - let new_imm_trait_ref = poly_trait_ref - .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs)); - let new_mut_trait_ref = poly_trait_ref - .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs)); - return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); + try_borrowing(obligation.parent_trait_ref, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = &*code { - return try_borrowing( - poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)), - poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)), - *poly_trait_ref, - &never_suggest_borrow[..], - ); + try_borrowing(*poly_trait_ref, &never_suggest_borrow[..]) } else { false } diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 1d0554ad0477f..13097edf0adf9 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `C: Copy` is not satisfied +error[E0277]: the trait bound `B: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:13 | LL | is_copy(B { a: 1, b: C }); @@ -22,7 +22,7 @@ help: consider borrowing here LL | is_copy(&B { a: 1, b: C }); | + -error[E0277]: the trait bound `C: Clone` is not satisfied +error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | is_clone(B { a: 1, b: C }); @@ -46,7 +46,7 @@ help: consider borrowing here LL | is_clone(&B { a: 1, b: C }); | + -error[E0277]: the trait bound `D: Copy` is not satisfied +error[E0277]: the trait bound `B: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | is_copy(B { a: 1, b: D }); diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 1cf73fcdebd0b..1ab130e0ab143 100644 --- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -65,7 +65,7 @@ LL | is_send(Box::new(TestType)); | | | required by a bound introduced by this call | - = note: the trait bound `dummy2::TestType: Send` is not satisfied + = note: the trait bound `Unique: Send` is not satisfied = note: required because of the requirements on the impl of `Send` for `Unique` = note: required because it appears within the type `Box` note: required by a bound in `is_send` @@ -104,11 +104,11 @@ error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:66:13 | LL | is_sync(Outer2(TestType)); - | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync` + | ------- ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely | | | required by a bound introduced by this call | - = note: the trait bound `main::TestType: Sync` is not satisfied + = help: the trait `Send` is not implemented for `main::TestType` note: required because of the requirements on the impl of `Sync` for `Outer2` --> $DIR/negated-auto-traits-error.rs:14:22 | @@ -119,12 +119,6 @@ note: required by a bound in `is_sync` | LL | fn is_sync(_: T) {} | ^^^^ required by this bound in `is_sync` -help: consider borrowing here - | -LL | is_sync(&Outer2(TestType)); - | + -LL | is_sync(&mut Outer2(TestType)); - | ++++ error: aborting due to 7 previous errors diff --git a/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs new file mode 100644 index 0000000000000..f891a42fc2af0 --- /dev/null +++ b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs @@ -0,0 +1,11 @@ +// Do not suggest referencing the parameter to `check` + +trait Marker {} + +impl Marker for T {} + +pub fn check>(_: T) {} + +pub fn main() { + check::<()>(()); //~ ERROR [E0277] +} diff --git a/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr new file mode 100644 index 0000000000000..08eab0253701e --- /dev/null +++ b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `(): Marker` is not satisfied + --> $DIR/issue-90804-incorrect-reference-suggestion.rs:10:17 + | +LL | check::<()>(()); + | ----------- ^^ the trait `Marker` is not implemented for `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/issue-90804-incorrect-reference-suggestion.rs:7:17 + | +LL | pub fn check>(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From eebf676bf8f76fcdfa610e7e46ab6c135a9cd2d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Nov 2021 13:28:47 -0500 Subject: [PATCH 04/11] fix getting the discriminant of a zero-variant enum --- compiler/rustc_middle/src/ty/sty.rs | 4 +++- src/test/ui/consts/const_discriminant.rs | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e57075ed33811..59601e1484956 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2067,7 +2067,9 @@ impl<'tcx> TyS<'tcx> { ) -> Option> { match self.kind() { TyKind::Adt(adt, _) if adt.variants.is_empty() => { - bug!("discriminant_for_variant called on zero variant enum"); + // This can actually happen during CTFE, see + // https://github.com/rust-lang/rust/issues/89765. + None } TyKind::Adt(adt, _) if adt.is_enum() => { Some(adt.discriminant_for_variant(tcx, variant_index)) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index a47f6af02965b..a9c0217ae2421 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -25,6 +25,12 @@ enum SingleVariant { const TEST_V: Discriminant = discriminant(&SingleVariant::V); +pub const TEST_VOID: () = { + // This is UB, but CTFE does not check validity so it does not detect this. + unsafe { std::mem::discriminant(&*(&() as *const () as *const Void)); }; +}; + + fn main() { assert_eq!(TEST_A, TEST_A_OTHER); assert_eq!(TEST_A, discriminant(black_box(&Test::A(17)))); From 9ec88626eac5e3e7c5fd719135545f1ac31fab8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Nov 2021 19:03:32 -0500 Subject: [PATCH 05/11] expand comment --- src/test/ui/consts/const_discriminant.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index a9c0217ae2421..f623c5101f4cd 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -27,6 +27,7 @@ const TEST_V: Discriminant = discriminant(&SingleVariant::V); pub const TEST_VOID: () = { // This is UB, but CTFE does not check validity so it does not detect this. + // This is a regression test for https://github.com/rust-lang/rust/issues/89765. unsafe { std::mem::discriminant(&*(&() as *const () as *const Void)); }; }; From d562f487c92698cb901df89cab0682ec2cbef222 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 12 Nov 2021 01:47:43 +0900 Subject: [PATCH 06/11] suggest `&str.chars()` on attempt to `&str.iter()` check if `String` or `&String` or `&str` Update compiler/rustc_typeck/src/check/method/suggest.rs Co-authored-by: Esteban Kuber remove some trailing whitespace --- .../rustc_typeck/src/check/method/suggest.rs | 20 ++++++++ src/test/ui/suggest-using-chars.rs | 7 +++ src/test/ui/suggest-using-chars.stderr | 48 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/test/ui/suggest-using-chars.rs create mode 100644 src/test/ui/suggest-using-chars.stderr diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 71cd8a43329c5..661ced952c736 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -478,6 +478,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut label_span_not_found = || { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); + let is_string_or_ref_str = match actual.kind() { + ty::Ref(_, ty, _) => { + ty.is_str() + || matches!( + ty.kind(), + ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did) + ) + } + ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did), + _ => false, + }; + if is_string_or_ref_str && item_name.name == sym::iter { + err.span_suggestion_verbose( + item_name.span, + "because of the in-memory representation of `&str`, to obtain \ + an `Iterator` over each of its codepoint use method `chars`", + String::from("chars"), + Applicability::MachineApplicable, + ); + } if let ty::Adt(adt, _) = rcvr_ty.kind() { let mut inherent_impls_candidate = self .tcx diff --git a/src/test/ui/suggest-using-chars.rs b/src/test/ui/suggest-using-chars.rs new file mode 100644 index 0000000000000..95732881baf09 --- /dev/null +++ b/src/test/ui/suggest-using-chars.rs @@ -0,0 +1,7 @@ +pub fn main() { + let _ = "foo".iter(); //~ ERROR no method named `iter` found for reference `&'static str` in the current scope + let _ = "foo".foo(); //~ ERROR no method named `foo` found for reference `&'static str` in the current scope + let _ = String::from("bar").iter(); //~ ERROR no method named `iter` found for struct `String` in the current scope + let _ = (&String::from("bar")).iter(); //~ ERROR no method named `iter` found for reference `&String` in the current scope + let _ = 0.iter(); //~ ERROR no method named `iter` found for type `{integer}` in the current scope +} diff --git a/src/test/ui/suggest-using-chars.stderr b/src/test/ui/suggest-using-chars.stderr new file mode 100644 index 0000000000000..99bcfb08a0892 --- /dev/null +++ b/src/test/ui/suggest-using-chars.stderr @@ -0,0 +1,48 @@ +error[E0599]: no method named `iter` found for reference `&'static str` in the current scope + --> $DIR/suggest-using-chars.rs:2:19 + | +LL | let _ = "foo".iter(); + | ^^^^ method not found in `&'static str` + | +help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars` + | +LL | let _ = "foo".chars(); + | ~~~~~ + +error[E0599]: no method named `foo` found for reference `&'static str` in the current scope + --> $DIR/suggest-using-chars.rs:3:19 + | +LL | let _ = "foo".foo(); + | ^^^ method not found in `&'static str` + +error[E0599]: no method named `iter` found for struct `String` in the current scope + --> $DIR/suggest-using-chars.rs:4:33 + | +LL | let _ = String::from("bar").iter(); + | ^^^^ method not found in `String` + | +help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars` + | +LL | let _ = String::from("bar").chars(); + | ~~~~~ + +error[E0599]: no method named `iter` found for reference `&String` in the current scope + --> $DIR/suggest-using-chars.rs:5:36 + | +LL | let _ = (&String::from("bar")).iter(); + | ^^^^ method not found in `&String` + | +help: because of the in-memory representation of `&str`, to obtain an `Iterator` over each of its codepoint use method `chars` + | +LL | let _ = (&String::from("bar")).chars(); + | ~~~~~ + +error[E0599]: no method named `iter` found for type `{integer}` in the current scope + --> $DIR/suggest-using-chars.rs:6:15 + | +LL | let _ = 0.iter(); + | ^^^^ method not found in `{integer}` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0599`. From c1c20138a9c895fe285c864b432472438ff978fd Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 15 Nov 2021 16:23:02 +0100 Subject: [PATCH 07/11] rustc_mir_build: reorder bindings No functional changes intended. I'm playing around with building compiler components using nightly rust (2021-11-02) in a non-standard way. I encountered the following error while trying to build rustc_mir_build: ``` error[E0597]: `wildcard` does not live long enough --> rust/src/nightly/compiler/rustc_mir_build/src/build/matches/mod.rs:1767:82 | 1767 | let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false); | ^^^^^^^^^ borrowed value does not live long enough ... 1799 | } | - | | | `wildcard` dropped here while still borrowed | borrow might be used here, when `guard_candidate` is dropped and runs the destructor for type `Candidate<'_, '_>` | = note: values in a scope are dropped in the opposite order they are defined ``` I believe this flags an issue that may become an error in the future. Swapping the order of `wildcard` and `guard_candidate` resolves it. --- compiler/rustc_mir_build/src/build/matches/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4df073c40e22c..6320d5d47497f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1762,8 +1762,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { let expr_span = expr.span; let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span)); - let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false); let wildcard = Pat::wildcard_from_ty(pat.ty); + let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false); let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false); let fake_borrow_temps = self.lower_match_tree( block, From 9c7f4f481453006f1834d013c18e57e556623f2f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 15 Nov 2021 13:35:06 -0500 Subject: [PATCH 08/11] Use a different server for checking clock drift The detectportal.firefox.com server seems to return a random-ish date; for example I see the following across 5 curl's done consecutively locally, where the real date is approximaly 15 Nov 2021 06:36 UTC. Date: Mon, 15 Nov 2021 13:34:53 GMT Date: Mon, 15 Nov 2021 12:20:21 GMT Date: Mon, 15 Nov 2021 00:06:47 GMT Date: Mon, 15 Nov 2021 17:14:33 GMT Date: Mon, 15 Nov 2021 13:33:21 GMT --- src/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index a21b40cfb779f..948445427d95b 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -117,7 +117,7 @@ datecheck() { echo -n " local time: " date echo -n " network time: " - curl -fs --head http://detectportal.firefox.com/success.txt | grep ^Date: \ + curl -fs --head http://ci-caches.rust-lang.org | grep ^Date: \ | sed 's/Date: //g' || true echo "== end clock drift check ==" } From 894c0e41907b581563120516862c8ea85cbb65d9 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 16 Nov 2021 09:38:43 +0900 Subject: [PATCH 09/11] Add a regression test for #80772 --- src/test/ui/borrowck/issue-80772.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/ui/borrowck/issue-80772.rs diff --git a/src/test/ui/borrowck/issue-80772.rs b/src/test/ui/borrowck/issue-80772.rs new file mode 100644 index 0000000000000..1b8caa3f8ac8b --- /dev/null +++ b/src/test/ui/borrowck/issue-80772.rs @@ -0,0 +1,21 @@ +// check-pass + +trait SomeTrait {} + +pub struct Exhibit { + constant: usize, + factory: fn(&usize) -> Box, +} + +pub const A_CONSTANT: &[Exhibit] = &[ + Exhibit { + constant: 1, + factory: |_| unimplemented!(), + }, + Exhibit { + constant: "Hello world".len(), + factory: |_| unimplemented!(), + }, +]; + +fn main() {} From c9fcbda389adfffd72405905de67be1aa444820f Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 18 Jun 2021 14:13:12 -0500 Subject: [PATCH 10/11] check where clause before suggesting unsized --- .../src/traits/error_reporting/mod.rs | 19 +++++++++++++++++++ ...-where-clause-before-suggesting-unsized.rs | 8 ++++++++ ...re-clause-before-suggesting-unsized.stderr | 18 ++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs create mode 100644 src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.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 79194718d1efd..305af6db29833 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -14,6 +14,7 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; @@ -2009,6 +2010,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { Some(param) => param, _ => return, }; + let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id(); + let preds = generics.where_clause.predicates.iter(); + let explicitly_sized = preds + .filter_map(|pred| match pred { + hir::WherePredicate::BoundPredicate(bp) => Some(bp), + _ => None, + }) + .flat_map(|bp| match bp.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved( + None, + &hir::Path { res: Res::Def(DefKind::TyParam, def_id), .. }, + )) if def_id == param_def_id => bp.bounds, + _ => &[][..], + }) + .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); + if explicitly_sized { + return; + } debug!("maybe_suggest_unsized_generics: param={:?}", param); match node { hir::Node::Item( diff --git a/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs new file mode 100644 index 0000000000000..5cfaf4be96aeb --- /dev/null +++ b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs @@ -0,0 +1,8 @@ +// Regression test for #85945: Don't suggest `?Sized` bound if an explicit +// `Sized` bound is already in a `where` clause. +fn foo(_: &T) where T: Sized {} +fn bar() { foo(""); } +//~^ERROR the size for values of type + +pub fn main() { +} diff --git a/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr new file mode 100644 index 0000000000000..92be9f764cc4b --- /dev/null +++ b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.stderr @@ -0,0 +1,18 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-85945-check-where-clause-before-suggesting-unsized.rs:4:16 + | +LL | fn bar() { foo(""); } + | --- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `str` +note: required by a bound in `foo` + --> $DIR/issue-85945-check-where-clause-before-suggesting-unsized.rs:3:8 + | +LL | fn foo(_: &T) where T: Sized {} + | ^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 1a50725a4d6814abe0f2a03551bb60ba90412959 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 18 Jun 2021 19:24:22 -0500 Subject: [PATCH 11/11] refactor is_param_bound --- compiler/rustc_hir/src/hir.rs | 16 ++++++++++++++ .../src/traits/error_reporting/mod.rs | 10 ++------- compiler/rustc_typeck/src/collect.rs | 22 +++---------------- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a441a635c1eb3..e00c5789fe9c7 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -647,6 +647,22 @@ pub struct WhereBoundPredicate<'hir> { pub bounds: GenericBounds<'hir>, } +impl WhereBoundPredicate<'hir> { + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn is_param_bound(&self, param_def_id: DefId) -> bool { + let path = match self.bounded_ty.kind { + TyKind::Path(QPath::Resolved(None, path)) => path, + _ => return false, + }; + match path.res { + Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => { + def_id == param_def_id + } + _ => false, + } + } +} + /// A lifetime predicate (e.g., `'a: 'b + 'c`). #[derive(Debug, HashStable_Generic)] pub struct WhereRegionPredicate<'hir> { 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 305af6db29833..f8df0e2595973 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -14,7 +14,6 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; @@ -2017,13 +2016,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { hir::WherePredicate::BoundPredicate(bp) => Some(bp), _ => None, }) - .flat_map(|bp| match bp.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved( - None, - &hir::Path { res: Res::Def(DefKind::TyParam, def_id), .. }, - )) if def_id == param_def_id => bp.bounds, - _ => &[][..], - }) + .filter(|bp| bp.is_param_bound(param_def_id)) + .flat_map(|bp| bp.bounds) .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); if explicitly_sized { return; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2274db76c05fb..2f427305782c5 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -28,7 +28,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; @@ -668,6 +668,7 @@ impl ItemCtxt<'tcx> { }) .flat_map(|b| predicates_from_bound(self, ty, b)); + let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id(); let from_where_clauses = ast_generics .where_clause .predicates @@ -677,7 +678,7 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bp| { - let bt = if is_param(self.tcx, bp.bounded_ty, param_id) { + let bt = if bp.is_param_bound(param_def_id) { Some(ty) } else if !only_self_bounds.0 { Some(self.to_ty(bp.bounded_ty)) @@ -714,23 +715,6 @@ impl ItemCtxt<'tcx> { } } -/// Tests whether this is the AST for a reference to the type -/// parameter with ID `param_id`. We use this so as to avoid running -/// `ast_ty_to_ty`, because we want to avoid triggering an all-out -/// conversion of the type to avoid inducing unnecessary cycles. -fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool { - if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind { - match path.res { - Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { - def_id == tcx.hir().local_def_id(param_id).to_def_id() - } - _ => false, - } - } else { - false - } -} - fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir().item(item_id); debug!("convert: item {} with id {}", it.ident, it.hir_id());