Auto merge of #90945 - JohnTitor:rollup-wc35xss, r=JohnTitor
Rollup of 8 pull requests Successful merges: - #86455 (check where-clause for explicit `Sized` before suggesting `?Sized`) - #90801 (Normalize both arguments of `equate_normalized_input_or_output`) - #90803 (Suggest `&str.chars()` on attempt to `&str.iter()`) - #90819 (Fixes incorrect handling of TraitRefs when emitting suggestions.) - #90910 (fix getting the discriminant of a zero-variant enum) - #90925 (rustc_mir_build: reorder bindings) - #90928 (Use a different server for checking clock drift) - #90936 (Add a regression test for #80772) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
934624fe5f
22 changed files with 342 additions and 96 deletions
|
@ -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<Ty<'tcx>> {
|
||||
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::<Vec<_>>() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AllFacts>,
|
||||
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>,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -2067,7 +2067,9 @@ impl<'tcx> TyS<'tcx> {
|
|||
) -> Option<Discr<'tcx>> {
|
||||
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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2009,6 +2009,19 @@ 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,
|
||||
})
|
||||
.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;
|
||||
}
|
||||
debug!("maybe_suggest_unsized_generics: param={:?}", param);
|
||||
match node {
|
||||
hir::Node::Item(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 =="
|
||||
}
|
||||
|
|
21
src/test/ui/borrowck/issue-80772.rs
Normal file
21
src/test/ui/borrowck/issue-80772.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// check-pass
|
||||
|
||||
trait SomeTrait {}
|
||||
|
||||
pub struct Exhibit {
|
||||
constant: usize,
|
||||
factory: fn(&usize) -> Box<dyn SomeTrait>,
|
||||
}
|
||||
|
||||
pub const A_CONSTANT: &[Exhibit] = &[
|
||||
Exhibit {
|
||||
constant: 1,
|
||||
factory: |_| unimplemented!(),
|
||||
},
|
||||
Exhibit {
|
||||
constant: "Hello world".len(),
|
||||
factory: |_| unimplemented!(),
|
||||
},
|
||||
];
|
||||
|
||||
fn main() {}
|
|
@ -25,6 +25,13 @@ enum SingleVariant {
|
|||
|
||||
const TEST_V: Discriminant<SingleVariant> = 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)); };
|
||||
};
|
||||
|
||||
|
||||
fn main() {
|
||||
assert_eq!(TEST_A, TEST_A_OTHER);
|
||||
assert_eq!(TEST_A, discriminant(black_box(&Test::A(17))));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0277]: the trait bound `C: Copy` is not satisfied
|
||||
error[E0277]: the trait bound `B<C>: 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<C>: 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<D>: Copy` is not satisfied
|
||||
--> $DIR/deriving-copyclone.rs:35:13
|
||||
|
|
||||
LL | is_copy(B { a: 1, b: D });
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(generic_associated_types)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
trait Family: Sized {
|
||||
type Item<'a>;
|
||||
|
||||
fn apply_all<F>(&self, f: F)
|
||||
where
|
||||
F: FamilyItemFn<Self> { }
|
||||
}
|
||||
|
||||
struct Array<T>(PhantomData<T>);
|
||||
|
||||
impl<T: 'static> Family for Array<T> {
|
||||
type Item<'a> = &'a T;
|
||||
}
|
||||
|
||||
trait FamilyItemFn<T: Family> {
|
||||
fn apply(&self, item: T::Item<'_>);
|
||||
}
|
||||
|
||||
impl<T, F> FamilyItemFn<T> for F
|
||||
where
|
||||
T: Family,
|
||||
for<'a> F: Fn(T::Item<'a>)
|
||||
{
|
||||
fn apply(&self, item: T::Item<'_>) {
|
||||
(*self)(item);
|
||||
}
|
||||
}
|
||||
|
||||
fn process<T: 'static>(array: Array<T>) {
|
||||
// Works
|
||||
array.apply_all(|x: &T| { });
|
||||
|
||||
// ICE: NoSolution
|
||||
array.apply_all(|x: <Array<T> as Family>::Item<'_>| { });
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,37 @@
|
|||
//check-pass
|
||||
|
||||
#![feature(generic_associated_types)]
|
||||
|
||||
trait Yokeable<'a>: 'static {
|
||||
type Output: 'a;
|
||||
}
|
||||
|
||||
trait IsCovariant<'a> {}
|
||||
|
||||
struct Yoke<Y: for<'a> Yokeable<'a>> {
|
||||
data: Y,
|
||||
}
|
||||
|
||||
impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
|
||||
fn project<Y2: for<'a> Yokeable<'a>>(&self, _f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a ())
|
||||
-> <Y2 as Yokeable<'a>>::Output) -> Yoke<Y2> {
|
||||
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn _upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
|
||||
Y: for<'a> Yokeable<'a>,
|
||||
for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
|
||||
{
|
||||
x.project(|data, _| {
|
||||
Box::new(data)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
impl<'a> Yokeable<'a> for Box<dyn IsCovariant<'static> + 'static> {
|
||||
type Output = Box<dyn IsCovariant<'a> + 'a>;
|
||||
}
|
||||
|
||||
fn main() {}
|
7
src/test/ui/suggest-using-chars.rs
Normal file
7
src/test/ui/suggest-using-chars.rs
Normal file
|
@ -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
|
||||
}
|
48
src/test/ui/suggest-using-chars.stderr
Normal file
48
src/test/ui/suggest-using-chars.stderr
Normal file
|
@ -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`.
|
|
@ -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>(_: &T) where T: Sized {}
|
||||
fn bar() { foo(""); }
|
||||
//~^ERROR the size for values of type
|
||||
|
||||
pub fn main() {
|
||||
}
|
|
@ -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>(_: &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`.
|
|
@ -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<dummy2::TestType>: Send` is not satisfied
|
||||
= note: required because of the requirements on the impl of `Send` for `Unique<dummy2::TestType>`
|
||||
= note: required because it appears within the type `Box<dummy2::TestType>`
|
||||
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<main::TestType>`
|
||||
--> $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: 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
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// Do not suggest referencing the parameter to `check`
|
||||
|
||||
trait Marker<T> {}
|
||||
|
||||
impl<T> Marker<i32> for T {}
|
||||
|
||||
pub fn check<T: Marker<u32>>(_: T) {}
|
||||
|
||||
pub fn main() {
|
||||
check::<()>(()); //~ ERROR [E0277]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
error[E0277]: the trait bound `(): Marker<u32>` is not satisfied
|
||||
--> $DIR/issue-90804-incorrect-reference-suggestion.rs:10:17
|
||||
|
|
||||
LL | check::<()>(());
|
||||
| ----------- ^^ the trait `Marker<u32>` 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: Marker<u32>>(_: T) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue