diff options
54 files changed, 438 insertions, 439 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 9cf4d8cdf7d..82ff862479e 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -359,9 +359,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubAlias(r_a, kind, alias_b) => { + OutlivesBound::RegionSubAlias(r_a, alias_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Alias(kind, alias_b), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9031c04849d..ce72b78f42f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2602,7 +2602,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { match path.res { Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => { // Check for desugared `impl Trait`. - assert!(ty::is_impl_trait_defn(tcx, did).is_none()); + assert!(tcx.is_type_alias_impl_trait(did)); let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1.iter(), |err| { err.note("`impl Trait` types can't have type parameters"); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 35f47dfc1a5..9be37dbe8c6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -76,6 +76,7 @@ pub fn provide(providers: &mut Providers) { is_foreign_item, generator_kind, collect_mod_item_types, + is_type_alias_impl_trait, ..*providers }; } @@ -1537,3 +1538,13 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> _ => bug!("generator_kind applied to non-local def-id {:?}", def_id), } } + +fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + match tcx.hir().get_if_local(def_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => { + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) + } + Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), + _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id), + } +} diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 3f691beec31..9459c5f54ab 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -80,7 +80,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>( .or_insert(span); } - Component::Alias(kind, alias) => { + Component::Alias(alias_ty) => { // This would either arise from something like: // // ``` @@ -99,13 +99,13 @@ pub(crate) fn insert_outlives_predicate<'tcx>( // // Here we want to add an explicit `where <T as Iterator>::Item: 'a` // or `Opaque<T>: 'a` depending on the alias kind. - let ty: Ty<'tcx> = tcx.mk_ty(ty::Alias(kind, alias)); + let ty = alias_ty.to_ty(tcx); required_predicates .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) .or_insert(span); } - Component::EscapingProjection(_) => { + Component::EscapingAlias(_) => { // As above, but the projection involves // late-bound regions. Therefore, the WF // requirement is not checked in type definition diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 16806fdba4f..b3dd3031db2 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -304,8 +304,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { let mut reinit = None; match expr.kind { ExprKind::Assign(lhs, rhs, _) => { - self.visit_expr(lhs); self.visit_expr(rhs); + self.visit_expr(lhs); reinit = Some(lhs); } @@ -433,7 +433,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { self.drop_ranges.add_control_edge(self.expr_index, *target) }), - ExprKind::Break(destination, ..) => { + ExprKind::Break(destination, value) => { // destination either points to an expression or to a block. We use // find_target_expression_from_destination to use the last expression of the block // if destination points to a block. @@ -443,7 +443,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { // will refer to the end of the block due to the post order traversal. self.find_target_expression_from_destination(destination).map_or((), |target| { self.drop_ranges.add_control_edge_hir_id(self.expr_index, target) - }) + }); + + if let Some(value) = value { + self.visit_expr(value); + } } ExprKind::Call(f, args) => { @@ -465,6 +469,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { ExprKind::AddrOf(..) | ExprKind::Array(..) + // FIXME(eholk): We probably need special handling for AssignOps. The ScopeTree builder + // in region.rs runs both lhs then rhs and rhs then lhs and then sets all yields to be + // the latest they show up in either traversal. With the older scope-based + // approximation, this was fine, but it's probably not right now. What we probably want + // to do instead is still run both orders, but consider anything that showed up as a + // yield in either order. | ExprKind::AssignOp(..) | ExprKind::Binary(..) | ExprKind::Block(..) @@ -502,6 +512,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { // Increment expr_count here to match what InteriorVisitor expects. self.expr_index = self.expr_index + 1; + + // Save a node mapping to get better CFG visualization + self.drop_ranges.add_node_mapping(pat.hir_id, self.expr_index); } } @@ -521,7 +534,7 @@ impl DropRangesBuilder { } }); } - debug!("hir_id_map: {:?}", tracked_value_map); + debug!("hir_id_map: {:#?}", tracked_value_map); let num_values = tracked_value_map.len(); Self { tracked_value_map, diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs index c0a0bfe8e1c..e8d31be79d9 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs @@ -2,6 +2,7 @@ //! flow graph when needed for debugging. use rustc_graphviz as dot; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_middle::ty::TyCtxt; use super::{DropRangesBuilder, PostOrderId}; @@ -80,10 +81,14 @@ impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> { .post_order_map .iter() .find(|(_hir_id, &post_order_id)| post_order_id == *n) - .map_or("<unknown>".into(), |(hir_id, _)| self - .tcx - .hir() - .node_to_string(*hir_id)) + .map_or("<unknown>".into(), |(hir_id, _)| format!( + "{}{}", + self.tcx.hir().node_to_string(*hir_id), + match self.tcx.hir().find(*hir_id) { + Some(Node::Expr(Expr { kind: ExprKind::Yield(..), .. })) => " (yield)", + _ => "", + } + )) ) .into(), ) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 7990d95310b..7af52605385 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -71,10 +71,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.expr_and_pat_count, self.expr_count, source_span ); - if self.fcx.sess().opts.unstable_opts.drop_tracking - && self - .drop_ranges - .is_dropped_at(hir_id, yield_data.expr_and_pat_count) + if self + .is_dropped_at_yield_location(hir_id, yield_data.expr_and_pat_count) { debug!("value is dropped at yield point; not recording"); return false; @@ -173,6 +171,18 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { } } } + + /// If drop tracking is enabled, consult drop_ranges to see if a value is + /// known to be dropped at a yield point and therefore can be omitted from + /// the generator witness. + fn is_dropped_at_yield_location(&self, value_hir_id: HirId, yield_location: usize) -> bool { + // short-circuit if drop tracking is not enabled. + if !self.fcx.sess().opts.unstable_opts.drop_tracking { + return false; + } + + self.drop_ranges.is_dropped_at(value_hir_id, yield_location) + } } pub fn resolve_interior<'a, 'tcx>( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9c38eb6163f..28fd03b878b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2272,13 +2272,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), - GenericKind::Alias(ty::Projection, ref p) => format!("the associated type `{}`", p), - GenericKind::Alias(ty::Opaque, ref p) => { - format!( - "the opaque type `{}`", - self.tcx.def_path_str_with_substs(p.def_id, p.substs) - ) - } + GenericKind::Alias(ref p) => match p.kind(self.tcx) { + ty::AliasKind::Projection => format!("the associated type `{}`", p), + ty::AliasKind::Opaque => format!("the opaque type `{}`", p), + }, }; if let Some(SubregionOrigin::CompareImplItemObligation { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 37907d289a8..3d86279b03c 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -22,7 +22,7 @@ pub enum Component<'tcx> { // is not in a position to judge which is the best technique, so // we just product the projection as a component and leave it to // the consumer to decide (but see `EscapingProjection` below). - Alias(ty::AliasKind, ty::AliasTy<'tcx>), + Alias(ty::AliasTy<'tcx>), // In the case where a projection has escaping regions -- meaning // regions bound within the type itself -- we always use @@ -44,7 +44,7 @@ pub enum Component<'tcx> { // projection, so that implied bounds code can avoid relying on // them. This gives us room to improve the regionck reasoning in // the future without breaking backwards compat. - EscapingProjection(Vec<Component<'tcx>>), + EscapingAlias(Vec<Component<'tcx>>), } /// Push onto `out` all the things that must outlive `'a` for the condition @@ -120,17 +120,6 @@ fn compute_components<'tcx>( out.push(Component::Param(p)); } - // Ignore lifetimes found in opaque types. Opaque types can - // have lifetimes in their substs which their hidden type doesn't - // actually use. If we inferred that an opaque type is outlived by - // its parameter lifetimes, then we could prove that any lifetime - // outlives any other lifetime, which is unsound. - // See https://github.com/rust-lang/rust/issues/84305 for - // more details. - ty::Alias(ty::Opaque, data) => { - out.push(Component::Alias(ty::Opaque, data)); - }, - // For projections, we prefer to generate an obligation like // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the // regionck more ways to prove that it holds. However, @@ -139,15 +128,15 @@ fn compute_components<'tcx>( // trait-ref. Therefore, if we see any higher-ranked regions, // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. - ty::Alias(ty::Projection, data) => { - if !data.has_escaping_bound_vars() { + ty::Alias(_, alias_ty) => { + if !alias_ty.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no // constraints for Pi). This defers the choice between // the rules OutlivesProjectionEnv, // OutlivesProjectionTraitDef, and // OutlivesProjectionComponents to regionck. - out.push(Component::Alias(ty::Projection, data)); + out.push(Component::Alias(alias_ty)); } else { // fallback case: hard code // OutlivesProjectionComponents. Continue walking @@ -155,7 +144,7 @@ fn compute_components<'tcx>( let mut subcomponents = smallvec![]; let mut subvisited = SsoHashSet::new(); compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); - out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); + out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 52c3d97f241..24e3c34dd94 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -138,9 +138,9 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubAlias(r_a, kind, projection_b) => { + OutlivesBound::RegionSubAlias(r_a, alias_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Alias(kind, projection_b), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 77de335e7f5..0194549a886 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -67,7 +67,6 @@ use crate::infer::{ }; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; -use rustc_hir::def_id::DefId; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable}; @@ -266,10 +265,8 @@ where Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); } - Component::Alias(kind, data) => { - self.alias_must_outlive(*kind, *data, origin, region) - } - Component::EscapingProjection(subcomponents) => { + Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty), + Component::EscapingAlias(subcomponents) => { self.components_must_outlive(origin, &subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { @@ -285,61 +282,26 @@ where } } + #[instrument(level = "debug", skip(self))] fn param_ty_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, param_ty: ty::ParamTy, ) { - debug!( - "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", - region, param_ty, origin - ); - - let generic = GenericKind::Param(param_ty); let verify_bound = self.verify_bound.param_bound(param_ty); - self.delegate.push_verify(origin, generic, region, verify_bound); + self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound); } #[instrument(level = "debug", skip(self))] - fn alias_must_outlive( + fn alias_ty_must_outlive( &mut self, - kind: ty::AliasKind, - data: ty::AliasTy<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, - ) { - self.generic_must_outlive( - origin, - region, - GenericKind::Alias(kind, data), - data.def_id, - data.substs, - kind == ty::Opaque, - |ty| match *ty.kind() { - ty::Alias(filter_kind, ty::AliasTy { def_id, substs, .. }) - if kind == filter_kind => - { - (def_id, substs) - } - _ => bug!("expected only projection types from env, not {:?}", ty), - }, - ); - } - - #[instrument(level = "debug", skip(self, filter))] - fn generic_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - generic: GenericKind<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - is_opaque: bool, - filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>), + alias_ty: ty::AliasTy<'tcx>, ) { // An optimization for a common case with opaque types. - if substs.is_empty() { + if alias_ty.substs.is_empty() { return; } @@ -361,14 +323,14 @@ where // These are guaranteed to apply, no matter the inference // results. let trait_bounds: Vec<_> = - self.verify_bound.declared_region_bounds(def_id, substs).collect(); + self.verify_bound.declared_bounds_from_definition(alias_ty).collect(); debug!(?trait_bounds); // Compute the bounds we can derive from the environment. This // is an "approximate" match -- in some cases, these bounds // may not apply. - let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic); + let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty); debug!(?approx_env_bounds); // Remove outlives bounds that we get from the environment but @@ -383,8 +345,8 @@ where // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait` // will be invoked with `['b => ^1]` and so we will get `^1` returned. let bound = bound_outlives.skip_binder(); - let (def_id, substs) = filter(bound.0); - self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1) + let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") }; + self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1) }); // If declared bounds list is empty, the only applicable rule is @@ -401,12 +363,12 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let needs_infer = substs.needs_infer(); - if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) { + if approx_env_bounds.is_empty() + && trait_bounds.is_empty() + && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) + { debug!("no declared bounds"); - - self.substs_must_outlive(substs, origin, region); - + self.substs_must_outlive(alias_ty.substs, origin, region); return; } @@ -447,14 +409,9 @@ where // projection outlive; in some cases, this may add insufficient // edges into the inference graph, leading to inference failures // even though a satisfactory solution exists. - let verify_bound = self.verify_bound.projection_opaque_bounds( - generic, - def_id, - substs, - &mut Default::default(), - ); - debug!("projection_must_outlive: pushing {:?}", verify_bound); - self.delegate.push_verify(origin, generic, region, verify_bound); + let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default()); + debug!("alias_must_outlive: pushing {:?}", verify_bound); + self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound); } fn substs_must_outlive( diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 56695a87b7c..94de9bc2d02 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,11 +1,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; -use crate::infer::{GenericKind, VerifyBound}; +use crate::infer::VerifyBound; use rustc_data_structures::sso::SsoHashSet; -use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericArg; -use rustc_middle::ty::{self, OutlivesPredicate, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; use smallvec::smallvec; @@ -94,29 +93,26 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// this list. pub fn approx_declared_bounds_from_env( &self, - generic: GenericKind<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> { - let projection_ty = generic.to_ty(self.tcx); - let erased_projection_ty = self.tcx.erase_regions(projection_ty); - self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty) + let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); + self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } #[instrument(level = "debug", skip(self, visited))] - pub fn projection_opaque_bounds( + pub fn alias_bound( &self, - generic: GenericKind<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, + alias_ty: ty::AliasTy<'tcx>, visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { - let generic_ty = generic.to_ty(self.tcx); + let alias_ty_as_ty = alias_ty.to_ty(self.tcx); // Search the env for where clauses like `P: 'a`. - let projection_opaque_bounds = self - .approx_declared_bounds_from_env(generic) + let env_bounds = self + .approx_declared_bounds_from_env(alias_ty) .into_iter() .map(|binder| { - if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty { + if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty { // Micro-optimize if this is an exact match (this // occurs often when there are no region variables // involved). @@ -126,19 +122,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { VerifyBound::IfEq(verify_if_eq_b) } }); - // Extend with bounds that we can find from the trait. - let trait_bounds = - self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r)); + + // Extend with bounds that we can find from the definition. + let definition_bounds = + self.declared_bounds_from_definition(alias_ty).map(|r| VerifyBound::OutlivedBy(r)); // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited); + compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited); self.bound_from_components(&components, visited) }; - VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect()) - .or(recursive_bound) + VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound) } fn bound_from_components( @@ -149,10 +145,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let mut bounds = components .iter() .map(|component| self.bound_from_single_component(component, visited)) - .filter(|bound| { - // Remove bounds that must hold, since they are not interesting. - !bound.must_hold() - }); + // Remove bounds that must hold, since they are not interesting. + .filter(|bound| !bound.must_hold()); match (bounds.next(), bounds.next()) { (Some(first), None) => first, @@ -170,13 +164,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match *component { Component::Region(lt) => VerifyBound::OutlivedBy(lt), Component::Param(param_ty) => self.param_bound(param_ty), - Component::Alias(kind, data) => self.projection_opaque_bounds( - GenericKind::Alias(kind, data), - data.def_id, - data.substs, - visited, - ), - Component::EscapingProjection(ref components) => { + Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited), + Component::EscapingAlias(ref components) => { self.bound_from_components(components, visited) } Component::UnresolvedInferenceVariable(v) => { @@ -292,16 +281,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// /// This is for simplicity, and because we are not really smart /// enough to cope with such bounds anywhere. - pub fn declared_region_bounds( + pub fn declared_bounds_from_definition( &self, - def_id: DefId, - substs: SubstsRef<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> impl Iterator<Item = ty::Region<'tcx>> { let tcx = self.tcx; - let bounds = tcx.item_bounds(def_id); + let bounds = tcx.item_bounds(alias_ty.def_id); trace!("{:#?}", bounds.0); bounds - .subst_iter(tcx, substs) + .subst_iter(tcx, alias_ty.substs) .filter_map(|p| p.to_opt_type_outlives()) .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index fda5ffe7846..0428481b7ff 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -167,7 +167,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), - Alias(ty::AliasKind, ty::AliasTy<'tcx>), + Alias(ty::AliasTy<'tcx>), } /// Describes the things that some `GenericKind` value `G` is known to @@ -746,10 +746,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{:?}", p), - GenericKind::Alias(ty::Projection, ref p) => write!(f, "{:?}", p), - GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap())) - }), + GenericKind::Alias(ref p) => write!(f, "{:?}", p), } } } @@ -758,10 +755,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{}", p), - GenericKind::Alias(ty::Projection, ref p) => write!(f, "{}", p), - GenericKind::Alias(ty::Opaque, ref p) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(p.def_id, tcx.lift(p.substs).unwrap())) - }), + GenericKind::Alias(ref p) => write!(f, "{}", p), } } } @@ -770,7 +764,7 @@ impl<'tcx> GenericKind<'tcx> { pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Alias(kind, data) => tcx.mk_ty(ty::Alias(kind, data)), + GenericKind::Alias(ref p) => p.to_ty(tcx), } } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 4ada7b22d08..cd5bde2a791 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -261,14 +261,15 @@ impl<'tcx> Elaborator<'tcx> { Component::UnresolvedInferenceVariable(_) => None, - Component::Alias(kind, data) => { - let ty = tcx.mk_ty(ty::Alias(kind, data)); + Component::Alias(alias_ty) => { + // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`. + // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`. Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(ty, r_min), + ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min), ))) } - Component::EscapingProjection(_) => { + Component::EscapingAlias(_) => { // We might be able to do more here, but we don't // want to deal with escaping vars right now. None diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index cb451931dfe..0d924f27c21 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -223,6 +223,15 @@ provide! { tcx, def_id, other, cdata, generator_kind => { table } trait_def => { table } deduced_param_attrs => { table } + is_type_alias_impl_trait => { + debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); + cdata + .root + .tables + .is_type_alias_impl_trait + .get(cdata, def_id.index) + .is_some() + } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata .root diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a3d44fa890d..ab2ad79b876 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1512,8 +1512,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.owner_id.def_id, m); } - hir::ItemKind::OpaqueTy(..) => { + hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); + if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) { + self.tables.is_type_alias_impl_trait.set(def_id.index, ()); + } } hir::ItemKind::Enum(..) => { let adt_def = self.tcx.adt_def(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5b7b096b4ed..5066dbbb90f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -404,6 +404,8 @@ define_tables! { proc_macro: Table<DefIndex, MacroKind>, module_reexports: Table<DefIndex, LazyArray<ModChild>>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, + // Slot is full when opaque is TAIT. + is_type_alias_impl_trait: Table<DefIndex, ()>, trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0ec6f481af1..6bbf7fa3914 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -177,6 +177,12 @@ rustc_queries! { separate_provide_extern } + query is_type_alias_impl_trait(key: DefId) -> bool + { + desc { "determine whether the opaque is a type-alias impl trait" } + separate_provide_extern + } + query analysis(key: ()) -> Result<(), ErrorGuaranteed> { eval_always desc { "running analysis passes on this crate" } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 2a68315fefc..615154a55e5 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -213,5 +213,5 @@ pub struct NormalizationResult<'tcx> { pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubAlias(ty::Region<'tcx>, ty::AliasKind, ty::AliasTy<'tcx>), + RegionSubAlias(ty::Region<'tcx>, ty::AliasTy<'tcx>), } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index e32a7ee1c35..24f3d1acff1 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -52,6 +52,7 @@ trivially_parameterized_over_tcx! { usize, (), u32, + bool, std::string::String, crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a128e9025fd..6a7b23e40a7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1245,19 +1245,34 @@ pub struct AliasTy<'tcx> { /// aka. `tcx.parent(def_id)`. pub def_id: DefId, - /// This field exists to prevent the creation of `ProjectionTy` without using + /// This field exists to prevent the creation of `AliasTy` without using /// [TyCtxt::mk_alias_ty]. pub(super) _use_mk_alias_ty_instead: (), } impl<'tcx> AliasTy<'tcx> { + pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind { + match tcx.def_kind(self.def_id) { + DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection, + DefKind::OpaqueTy => ty::Opaque, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.mk_ty(ty::Alias(self.kind(tcx), self)) + } +} + +/// The following methods work only with associated type projections. +impl<'tcx> AliasTy<'tcx> { pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { match tcx.def_kind(self.def_id) { DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), DefKind::ImplTraitPlaceholder => { tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id)) } - kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"), + kind => bug!("expected a projection AliasTy; found {kind:?}"), } } 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 434f75de02b..52971486c55 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1350,6 +1350,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected_trait_ref, obligation.cause.code(), found_node, + obligation.param_env, ) } else { let (closure_span, closure_arg_span, found) = found_did 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 195bbe92f8b..39e50b2accf 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -283,6 +283,7 @@ pub trait TypeErrCtxtExt<'tcx> { expected: ty::PolyTraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, found_node: Option<Node<'_>>, + param_env: ty::ParamEnv<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; fn note_conflicting_closure_bounds( @@ -1978,6 +1979,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected: ty::PolyTraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, found_node: Option<Node<'_>>, + param_env: ty::ParamEnv<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, @@ -2040,7 +2042,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.note_conflicting_closure_bounds(cause, &mut err); if let Some(found_node) = found_node { - hint_missing_borrow(span, found, expected, found_node, &mut err); + hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err); } err @@ -3747,6 +3749,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Add a hint to add a missing borrow or remove an unnecessary one. fn hint_missing_borrow<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, span: Span, found: Ty<'tcx>, expected: Ty<'tcx>, @@ -3769,7 +3773,7 @@ fn hint_missing_borrow<'tcx>( // This could be a variant constructor, for example. let Some(fn_decl) = found_node.fn_decl() else { return; }; - let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span); + let args = fn_decl.inputs.iter().map(|ty| ty); fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { let mut refs = 0; @@ -3785,21 +3789,34 @@ fn hint_missing_borrow<'tcx>( let mut to_borrow = Vec::new(); let mut remove_borrow = Vec::new(); - for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) { + for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) { let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); - if found_ty == expected_ty { + if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() { if found_refs < expected_refs { - to_borrow.push((arg_span, expected_arg.to_string())); + to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs))); } else if found_refs > expected_refs { - remove_borrow.push((arg_span, expected_arg.to_string())); + let mut span = arg.span.shrink_to_lo(); + let mut left = found_refs - expected_refs; + let mut ty = arg; + while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { + span = span.with_hi(mut_ty.ty.span.lo()); + ty = mut_ty.ty; + left -= 1; + } + let sugg = if left == 0 { + (span, String::new()) + } else { + (arg.span, expected_arg.to_string()) + }; + remove_borrow.push(sugg); } } } if !to_borrow.is_empty() { - err.multipart_suggestion( + err.multipart_suggestion_verbose( "consider borrowing the argument", to_borrow, Applicability::MaybeIncorrect, @@ -3807,7 +3824,7 @@ fn hint_missing_borrow<'tcx>( } if !remove_borrow.is_empty() { - err.multipart_suggestion( + err.multipart_suggestion_verbose( "do not borrow the argument", remove_borrow, Applicability::MaybeIncorrect, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b47a70b4e7b..12d4cb4fc69 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -654,7 +654,7 @@ impl<'tcx> WfPredicates<'tcx> { // All of the requirements on type parameters // have already been checked for `impl Trait` in // return position. We do need to check type-alias-impl-trait though. - if ty::is_impl_trait_defn(self.tcx, def_id).is_none() { + if self.tcx.is_type_alias_impl_trait(def_id) { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index d457a4a2bea..7d2d8433c93 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -154,10 +154,8 @@ fn implied_bounds_from_components<'tcx>( match component { Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), - Component::Alias(kind, p) => { - Some(OutlivesBound::RegionSubAlias(sub_region, kind, p)) - } - Component::EscapingProjection(_) => + Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), + Component::EscapingAlias(_) => // If the projection has escaping regions, don't // try to infer any implied bounds even for its // free components. This is conservative, because diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ca3e9916487..bc8badad38e 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -138,7 +138,7 @@ pub(super) fn write_shared( Ok((ret, krates)) } - /// Read a file and return all lines that match the <code>"{crate}":{data},\ </code> format, + /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format, /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`. /// /// This forms the payload of files that look like this: diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 7db47035967..22068ebe041 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -5,10 +5,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_item, Visitor}; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; -use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -59,6 +57,9 @@ pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool false } +// Also, is there some reason that this doesn't use the 'visit' +// framework from syntax?. + pub(crate) struct RustdocVisitor<'a, 'tcx> { cx: &'a mut core::DocContext<'tcx>, view_item_stack: FxHashSet<hir::HirId>, @@ -66,7 +67,6 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { /// Are the current module and all of its parents public? inside_public_path: bool, exact_paths: FxHashMap<DefId, Vec<Symbol>>, - modules: Vec<Module<'tcx>>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -74,19 +74,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); stack.insert(hir::CRATE_HIR_ID); - let om = Module::new( - cx.tcx.crate_name(LOCAL_CRATE), - hir::CRATE_HIR_ID, - cx.tcx.hir().root_module().spans.inner_span, - ); - RustdocVisitor { cx, view_item_stack: stack, inlining: false, inside_public_path: true, exact_paths: FxHashMap::default(), - modules: vec![om], } } @@ -96,10 +89,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } pub(crate) fn visit(mut self) -> Module<'tcx> { - let root_module = self.cx.tcx.hir().root_module(); - self.visit_mod_contents(CRATE_HIR_ID, root_module); - - let mut top_level_module = self.modules.pop().unwrap(); + let mut top_level_module = self.visit_mod_contents( + hir::CRATE_HIR_ID, + self.cx.tcx.hir().root_module(), + self.cx.tcx.crate_name(LOCAL_CRATE), + None, + ); // `#[macro_export] macro_rules!` items are reexported at the top level of the // crate, regardless of where they're defined. We want to document the @@ -114,13 +109,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // macro in the same module. let mut inserted = FxHashSet::default(); for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) { - if let Res::Def(DefKind::Macro(_), def_id) = export.res && - let Some(local_def_id) = def_id.as_local() && - self.cx.tcx.has_attr(def_id, sym::macro_export) && - inserted.insert(def_id) - { - let item = self.cx.tcx.hir().expect_item(local_def_id); - top_level_module.items.push((item, None, None)); + if let Res::Def(DefKind::Macro(_), def_id) = export.res { + if let Some(local_def_id) = def_id.as_local() { + if self.cx.tcx.has_attr(def_id, sym::macro_export) { + if inserted.insert(def_id) { + let item = self.cx.tcx.hir().expect_item(local_def_id); + top_level_module.items.push((item, None, None)); + } + } + } } } @@ -154,23 +151,24 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { top_level_module } - /// This method will go through the given module items in two passes: - /// 1. The items which are not glob imports/reexports. - /// 2. The glob imports/reexports. - fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) { - debug!("Going through module {:?}", m); + fn visit_mod_contents( + &mut self, + id: hir::HirId, + m: &'tcx hir::Mod<'tcx>, + name: Symbol, + parent_id: Option<hir::HirId>, + ) -> Module<'tcx> { + let mut om = Module::new(name, id, m.spans.inner_span); let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); // Keep track of if there were any private modules in the path. let orig_inside_public_path = self.inside_public_path; self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); - - // Reimplementation of `walk_mod` because we need to do it in two passes (explanations in - // the second loop): for &i in m.item_ids { let item = self.cx.tcx.hir().item(i); - if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item); + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + continue; } + self.visit_item(item, None, &mut om, parent_id); } for &i in m.item_ids { let item = self.cx.tcx.hir().item(i); @@ -178,10 +176,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Later passes in rustdoc will de-duplicate by name and kind, so if glob- // imported items appear last, then they'll be the ones that get discarded. if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item); + self.visit_item(item, None, &mut om, parent_id); } } self.inside_public_path = orig_inside_public_path; + om } /// Tries to resolve the target of a `pub use` statement and inlines the @@ -199,6 +198,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { res: Res, renamed: Option<Symbol>, glob: bool, + om: &mut Module<'tcx>, please_inline: bool, ) -> bool { debug!("maybe_inline_local res: {:?}", res); @@ -249,20 +249,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { let i = self.cx.tcx.hir().item(i); - self.visit_item_inner(i, None, Some(id)); + self.visit_item(i, None, om, Some(id)); } self.inlining = prev; true } Node::Item(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_item_inner(it, renamed, Some(id)); + self.visit_item(it, renamed, om, Some(id)); self.inlining = prev; true } Node::ForeignItem(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_foreign_item_inner(it, renamed); + self.visit_foreign_item(it, renamed, om); self.inlining = prev; true } @@ -272,22 +272,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ret } - #[inline] - fn add_to_current_mod( + fn visit_item( &mut self, item: &'tcx hir::Item<'_>, renamed: Option<Symbol>, + om: &mut Module<'tcx>, parent_id: Option<hir::HirId>, ) { - self.modules.last_mut().unwrap().items.push((item, renamed, parent_id)) - } - - fn visit_item_inner( - &mut self, - item: &'tcx hir::Item<'_>, - renamed: Option<Symbol>, - parent_id: Option<hir::HirId>, - ) -> bool { debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); @@ -302,7 +293,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::ForeignMod { items, .. } => { for item in items { let item = self.cx.tcx.hir().foreign_item(item.id); - self.visit_foreign_item_inner(item, None); + self.visit_foreign_item(item, None, om); } } // If we're inlining, skip private items or item reexported as "_". @@ -335,13 +326,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { res, ident, is_glob, + om, please_inline, ) { continue; } } - self.add_to_current_mod(item, renamed, parent_id); + om.items.push((item, renamed, parent_id)) } } hir::ItemKind::Macro(ref macro_def, _) => { @@ -361,11 +353,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export); if is_macro_2_0 || nonexported || self.inlining { - self.add_to_current_mod(item, renamed, None); + om.items.push((item, renamed, None)); } } hir::ItemKind::Mod(ref m) => { - self.enter_mod(item.hir_id(), m, name); + om.mods.push(self.visit_mod_contents(item.hir_id(), m, name, parent_id)); } hir::ItemKind::Fn(..) | hir::ItemKind::ExternCrate(..) @@ -376,92 +368,33 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) => { - self.add_to_current_mod(item, renamed, parent_id); - } + | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed, parent_id)), hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - self.add_to_current_mod(item, renamed, parent_id); + om.items.push((item, renamed, parent_id)); } } hir::ItemKind::Impl(impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - self.add_to_current_mod(item, None, None); + om.items.push((item, None, None)); } } } - true } - fn visit_foreign_item_inner( + fn visit_foreign_item( &mut self, item: &'tcx hir::ForeignItem<'_>, renamed: Option<Symbol>, + om: &mut Module<'tcx>, ) { // If inlining we only want to include public functions. if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() { - self.modules.last_mut().unwrap().foreigns.push((item, renamed)); + om.foreigns.push((item, renamed)); } } - - /// This method will create a new module and push it onto the "modules stack" then call - /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead - /// add into the list of modules of the current module. - fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) { - self.modules.push(Module::new(name, id, m.spans.inner_span)); - - self.visit_mod_contents(id, m); - - let last = self.modules.pop().unwrap(); - self.modules.last_mut().unwrap().mods.push(last); - } -} - -// We need to implement this visitor so it'll go everywhere and retrieve items we're interested in -// such as impl blocks in const blocks. -impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - let parent_id = if self.modules.len() > 1 { - Some(self.modules[self.modules.len() - 2].id) - } else { - None - }; - if self.visit_item_inner(i, None, parent_id) { - walk_item(self, i); - } - } - - fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) { - // Handled in `visit_item_inner` - } - - fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) { - // Handled in `visit_item_inner` - } - - fn visit_path(&mut self, _: &hir::Path<'tcx>, _: hir::HirId) { - // Handled in `visit_item_inner` - } - - fn visit_label(&mut self, _: &rustc_ast::Label) { - // Unneeded. - } - - fn visit_infer(&mut self, _: &hir::InferArg) { - // Unneeded. - } - - fn visit_lifetime(&mut self, _: &hir::Lifetime) { - // Unneeded. - } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a5d47a72595dd6fbe7d4e4f6ec20dc5fe724edd +Subproject 50eb688c2bbea5de5a2e8496230a7428798089d diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c5767a79538..c49ecb104a7 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -426,10 +426,15 @@ impl TestProps { self.known_bug = true; } else { panic!( - "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `unknown`." + "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." ); } + } else if config.parse_name_directive(ln, KNOWN_BUG) { + panic!( + "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + ); } + config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| { s.trim().to_string() }); diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs index 939da186fbc..4b1e04234c8 100644 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs +++ b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -1,10 +1,12 @@ +// check-pass // normalize-stderr-test: "`.*`" -> "`DEF_ID`" // normalize-stdout-test: "`.*`" -> "`DEF_ID`" // edition:2018 pub async fn f() -> impl std::fmt::Debug { + // rustdoc doesn't care that this is infinitely sized #[derive(Debug)] - enum E { //~ ERROR + enum E { This(E), Unit, } diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr deleted file mode 100644 index aff7402bc91..00000000000 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0072]: recursive type `DEF_ID` has infinite size - --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5 - | -LL | enum E { - | ^^^^^^ -LL | This(E), - | - recursive without indirection - | -help: insert some indirection (e.g., a `DEF_ID`) to break the cycle - | -LL | This(Box<E>), - | ++++ + - -error: aborting due to previous error - -For more information about this error, try `DEF_ID`. diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs index ac517257498..ac79582fb3f 100644 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs +++ b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs @@ -1,5 +1,8 @@ +// check-pass + fn f() -> impl Sized { - enum E { //~ ERROR + // rustdoc doesn't care that this is infinitely sized + enum E { V(E), } unimplemented!() diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr deleted file mode 100644 index a61577bd14a..00000000000 --- a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0072]: recursive type `f::E` has infinite size - --> $DIR/infinite-recursive-type-impl-trait.rs:2:5 - | -LL | enum E { - | ^^^^^^ -LL | V(E), - | - recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL | V(Box<E>), - | ++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0072`. diff --git a/tests/rustdoc/impl-in-const-block.rs b/tests/rustdoc/impl-in-const-block.rs deleted file mode 100644 index b44e7135246..00000000000 --- a/tests/rustdoc/impl-in-const-block.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Regression test for #83026. -// The goal of this test is to ensure that impl blocks inside -// const expressions are documented as well. - -#![crate_name = "foo"] - -// @has 'foo/struct.A.html' -// @has - '//*[@id="method.new"]/*[@class="code-header"]' 'pub fn new() -> A' -// @has - '//*[@id="method.bar"]/*[@class="code-header"]' 'pub fn bar(&self)' -// @has - '//*[@id="method.woo"]/*[@class="code-header"]' 'pub fn woo(&self)' -// @has - '//*[@id="method.yoo"]/*[@class="code-header"]' 'pub fn yoo()' -// @has - '//*[@id="method.yuu"]/*[@class="code-header"]' 'pub fn yuu()' -pub struct A; - -const _: () = { - impl A { - const FOO: () = { - impl A { - pub fn woo(&self) {} - } - }; - - pub fn new() -> A { - A - } - } -}; -pub const X: () = { - impl A { - pub fn bar(&self) {} - } -}; - -fn foo() { - impl A { - pub fn yoo() {} - } - const _: () = { - impl A { - pub fn yuu() {} - } - }; -} diff --git a/tests/ui/anonymous-higher-ranked-lifetime.stderr b/tests/ui/anonymous-higher-ranked-lifetime.stderr index afb7f8fea92..c023d1b1590 100644 --- a/tests/ui/anonymous-higher-ranked-lifetime.stderr +++ b/tests/ui/anonymous-higher-ranked-lifetime.stderr @@ -16,7 +16,7 @@ LL | fn f1<F>(_: F) where F: Fn(&(), &()) {} help: consider borrowing the argument | LL | f1(|_: &(), _: &()| {}); - | ~~~ ~~~ + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 @@ -35,8 +35,8 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2` help: consider borrowing the argument | -LL | f2(|_: &'a (), _: &()| {}); - | ~~~~~~ ~~~ +LL | f2(|_: &(), _: &()| {}); + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 @@ -56,7 +56,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} help: consider borrowing the argument | LL | f3(|_: &(), _: &()| {}); - | ~~~ ~~~ + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 @@ -75,8 +75,8 @@ LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4` help: consider borrowing the argument | -LL | f4(|_: &(), _: &'r ()| {}); - | ~~~ ~~~~~~ +LL | f4(|_: &(), _: &()| {}); + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 @@ -95,17 +95,15 @@ LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5` help: consider borrowing the argument | -LL | f5(|_: &'r (), _: &'r ()| {}); - | ~~~~~~ ~~~~~~ +LL | f5(|_: &(), _: &()| {}); + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 | LL | g1(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` @@ -115,15 +113,17 @@ note: required by a bound in `g1` | LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1` +help: consider borrowing the argument + | +LL | g1(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | LL | g2(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _` @@ -133,15 +133,17 @@ note: required by a bound in `g2` | LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {} | ^^^^^^^^^^^^^^^^ required by this bound in `g2` +help: consider borrowing the argument + | +LL | g2(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 | LL | g3(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&'s ()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` @@ -151,15 +153,17 @@ note: required by a bound in `g3` | LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3` +help: consider borrowing the argument + | +LL | g3(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | LL | g4(|_: (), _: ()| {}); - | ^^ -------------- - | | | | - | | | help: consider borrowing the argument: `&()` - | | found signature defined here + | ^^ -------------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _` @@ -169,6 +173,10 @@ note: required by a bound in `g4` | LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4` +help: consider borrowing the argument + | +LL | g4(|_: &(), _: ()| {}); + | + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 @@ -188,7 +196,7 @@ LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {} help: consider borrowing the argument | LL | h1(|_: &(), _: (), _: &(), _: ()| {}); - | ~~~ ~~~ + | + + error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 @@ -207,8 +215,8 @@ LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2` help: consider borrowing the argument | -LL | h2(|_: &(), _: (), _: &'t0 (), _: ()| {}); - | ~~~ ~~~~~~~ +LL | h2(|_: &(), _: (), _: &(), _: ()| {}); + | + + error: aborting due to 11 previous errors diff --git a/tests/ui/async-await/auxiliary/issue-107036.rs b/tests/ui/async-await/auxiliary/issue-107036.rs new file mode 100644 index 00000000000..c3f6141b284 --- /dev/null +++ b/tests/ui/async-await/auxiliary/issue-107036.rs @@ -0,0 +1,12 @@ +// edition:2021 + +pub trait T {} +impl T for () {} + +pub struct S {} + +impl S { + pub async fn f<'a>(&self) -> impl T + 'a { + () + } +} diff --git a/tests/ui/async-await/await-sequence.rs b/tests/ui/async-await/await-sequence.rs new file mode 100644 index 00000000000..726c4284ec1 --- /dev/null +++ b/tests/ui/async-await/await-sequence.rs @@ -0,0 +1,21 @@ +// edition:2021 +// compile-flags: -Z drop-tracking +// build-pass + +use std::collections::HashMap; + +fn main() { + let _ = real_main(); +} + +async fn nop() {} + +async fn real_main() { + nop().await; + nop().await; + nop().await; + nop().await; + + let mut map: HashMap<(), ()> = HashMap::new(); + map.insert((), nop().await); +} diff --git a/tests/ui/async-await/issue-107036.rs b/tests/ui/async-await/issue-107036.rs new file mode 100644 index 00000000000..6a22de2c943 --- /dev/null +++ b/tests/ui/async-await/issue-107036.rs @@ -0,0 +1,14 @@ +// aux-build:issue-107036.rs +// edition:2021 +// check-pass + +extern crate issue_107036; +use issue_107036::S; + +async fn f() { + S{}.f().await; +} + +fn main() { + let _ = f(); +} diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs index 1c69b07e3d4..3169e4781ee 100644 --- a/tests/ui/chalkify/bugs/async.rs +++ b/tests/ui/chalkify/bugs/async.rs @@ -1,7 +1,7 @@ -// check-fail -// known-bug +// edition:2021 +// known-bug: unknown // unset-rustc-env:RUST_BACKTRACE -// compile-flags:-Z trait-solver=chalk --edition=2021 +// compile-flags:-Z trait-solver=chalk // error-pattern:internal compiler error // failure-status:101 // normalize-stderr-test "DefId([^)]*)" -> "..." diff --git a/tests/ui/closures/multiple-fn-bounds.stderr b/tests/ui/closures/multiple-fn-bounds.stderr index da26302c9d8..32a1edb0024 100644 --- a/tests/ui/closures/multiple-fn-bounds.stderr +++ b/tests/ui/closures/multiple-fn-bounds.stderr @@ -2,10 +2,8 @@ error[E0631]: type mismatch in closure arguments --> $DIR/multiple-fn-bounds.rs:10:5 | LL | foo(move |x| v); - | ^^^ -------- - | | | | - | | | help: do not borrow the argument: `char` - | | found signature defined here + | ^^^ -------- found signature defined here + | | | expected due to this | = note: expected closure signature `fn(char) -> _` @@ -20,6 +18,10 @@ note: required by a bound in `foo` | LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) { | ^^^^^^^^^^^^^^^^ required by this bound in `foo` +help: do not borrow the argument + | +LL | foo(move |char| v); + | ~~~~ error: aborting due to previous error diff --git a/tests/ui/const-generics/issues/issue-85031-2.rs b/tests/ui/const-generics/issues/issue-85031-2.rs index 4908fb29692..50dd66da6db 100644 --- a/tests/ui/const-generics/issues/issue-85031-2.rs +++ b/tests/ui/const-generics/issues/issue-85031-2.rs @@ -1,5 +1,5 @@ // check-pass -// known-bug +// known-bug: unknown // This should not compile, as the compiler should not know // `A - 0` is satisfied `?x - 0` if `?x` is inferred to `A`. @@ -10,7 +10,6 @@ pub struct Ref<'a>(&'a i32); impl<'a> Ref<'a> { pub fn foo<const A: usize>() -> [(); A - 0] { - //~^ WARN function cannot Self::foo() } } diff --git a/tests/ui/const-generics/issues/issue-85031-2.stderr b/tests/ui/const-generics/issues/issue-85031-2.stderr index fc690576875..896e1c7ea8d 100644 --- a/tests/ui/const-generics/issues/issue-85031-2.stderr +++ b/tests/ui/const-generics/issues/issue-85031-2.stderr @@ -3,7 +3,6 @@ warning: function cannot return without recursing | LL | pub fn foo<const A: usize>() -> [(); A - 0] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | LL | Self::foo() | ----------- recursive call site | diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs index 719d1bd5a4c..5101de19d3c 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for // all 'a where I::Item<'a> is WF", but really means "for all 'a possible" @@ -29,7 +29,6 @@ where fn main() { let slice = &mut (); - //~^ temporary value dropped while borrowed let windows = WindowsMut { slice }; print_items::<WindowsMut<'_>>(windows); } diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr index 1c9abc4e837..362aeae2361 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -3,7 +3,7 @@ error[E0716]: temporary value dropped while borrowed | LL | let slice = &mut (); | ^^ creates a temporary value which is freed while still in use -... +LL | let windows = WindowsMut { slice }; LL | print_items::<WindowsMut<'_>>(windows); | -------------------------------------- argument requires that borrow lasts for `'static` LL | } diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs index 8e6c5348e71..3174227a7a1 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for // all 'a where I::Item<'a> is WF", but really means "for all 'a possible" @@ -16,7 +16,6 @@ where { let mut iter2 = Eat(iter, f); let _next = iter2.next(); - //~^ borrowed data escapes true } impl<I: LendingIterator> LendingIterator for &mut I { diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/bugs/issue-100013.rs index fc4e47a3ba1..973c548d785 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.rs +++ b/tests/ui/generic-associated-types/bugs/issue-100013.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // edition: 2021 // We really should accept this, but we need implied bounds between the regions @@ -13,7 +13,6 @@ pub trait FutureIterator { fn call<I: FutureIterator>() -> impl Send { async { // a generator checked for autotrait impl `Send` - //~^ lifetime bound not satisfied let x = None::<I::Future<'_, '_>>; // a type referencing GAT async {}.await; // a yield point } @@ -21,16 +20,13 @@ fn call<I: FutureIterator>() -> impl Send { fn call2<'a, 'b, I: FutureIterator>() -> impl Send { async { // a generator checked for autotrait impl `Send` - //~^ lifetime bound not satisfied let x = None::<I::Future<'a, 'b>>; // a type referencing GAT - //~^ lifetime may not live long enough async {}.await; // a yield point } } fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { async { // a generator checked for autotrait impl `Send` - //~^ lifetime bound not satisfied let x = None::<I::Future<'a, 'b>>; // a type referencing GAT async {}.await; // a yield point } diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr index 72ae288dcab..9db124a81e4 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-100013.stderr @@ -2,77 +2,73 @@ error: lifetime bound not satisfied --> $DIR/issue-100013.rs:15:5 | LL | / async { // a generator checked for autotrait impl `Send` -LL | | LL | | let x = None::<I::Future<'_, '_>>; // a type referencing GAT LL | | async {}.await; // a yield point LL | | } | |_____^ | note: the lifetime defined here... - --> $DIR/issue-100013.rs:17:38 + --> $DIR/issue-100013.rs:16:38 | LL | let x = None::<I::Future<'_, '_>>; // a type referencing GAT | ^^ note: ...must outlive the lifetime defined here - --> $DIR/issue-100013.rs:17:34 + --> $DIR/issue-100013.rs:16:34 | LL | let x = None::<I::Future<'_, '_>>; // a type referencing GAT | ^^ = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:23:5 + --> $DIR/issue-100013.rs:22:5 | LL | / async { // a generator checked for autotrait impl `Send` -LL | | LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT -LL | | LL | | async {}.await; // a yield point LL | | } | |_____^ | note: the lifetime defined here... - --> $DIR/issue-100013.rs:22:14 + --> $DIR/issue-100013.rs:21:14 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | ^^ note: ...must outlive the lifetime defined here - --> $DIR/issue-100013.rs:22:10 + --> $DIR/issue-100013.rs:21:10 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | ^^ = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) error: lifetime may not live long enough - --> $DIR/issue-100013.rs:25:17 + --> $DIR/issue-100013.rs:23:17 | LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here -... +LL | async { // a generator checked for autotrait impl `Send` LL | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:32:5 + --> $DIR/issue-100013.rs:29:5 | LL | / async { // a generator checked for autotrait impl `Send` -LL | | LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT LL | | async {}.await; // a yield point LL | | } | |_____^ | note: the lifetime defined here... - --> $DIR/issue-100013.rs:31:18 + --> $DIR/issue-100013.rs:28:18 | LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { | ^^ note: ...must outlive the lifetime defined here - --> $DIR/issue-100013.rs:31:10 + --> $DIR/issue-100013.rs:28:10 | LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { | ^^ diff --git a/tests/ui/generic-associated-types/bugs/issue-91762.rs b/tests/ui/generic-associated-types/bugs/issue-91762.rs index dec668bec10..8f2cc45509f 100644 --- a/tests/ui/generic-associated-types/bugs/issue-91762.rs +++ b/tests/ui/generic-associated-types/bugs/issue-91762.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // We almost certainly want this to pass, but // it's particularly difficult currently, because we need a way of specifying @@ -22,7 +22,6 @@ pub trait FunctorExt<T>: Sized { arg = self; ret = <Self::Base as Functor>::fmap(arg); - //~^ type annotations needed } } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed new file mode 100644 index 00000000000..6315fcca2b8 --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments +} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs new file mode 100644 index 00000000000..c12c5362efc --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments + let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments +} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr new file mode 100644 index 00000000000..fb8af4bb7dd --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr @@ -0,0 +1,38 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24 + | +LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); + | ^^^^ -------- found signature defined here + | | + | expected due to this + | + = note: expected closure signature `for<'a> fn(&'a {integer}) -> _` + found closure signature `fn(i32) -> _` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider borrowing the argument + | +LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + | + + +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24 + | +LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + | ^^^^ ----------- found signature defined here + | | + | expected due to this + | + = note: expected closure signature `for<'a> fn(&'a {integer}) -> _` + found closure signature `for<'a, 'b, 'c> fn(&'a &'b &'c i32) -> _` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: do not borrow the argument + | +LL - let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); +LL + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0631`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr index fab9b7edc0c..811ff0533f0 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:3:14 | LL | a.iter().map(|_: (u32, u32)| 45); - | ^^^ --------------- - | | | | - | | | help: consider borrowing the argument: `&(u32, u32)` - | | found signature defined here + | ^^^ --------------- found signature defined here + | | | expected due to this | = note: expected closure signature `fn(&(u32, u32)) -> _` found closure signature `fn((u32, u32)) -> _` note: required by a bound in `map` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider borrowing the argument + | +LL | a.iter().map(|_: &(u32, u32)| 45); + | + error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:4:14 diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr index 72fb0e4d774..a6764a1dc6d 100644 --- a/tests/ui/mismatched_types/issue-36053-2.stderr +++ b/tests/ui/mismatched_types/issue-36053-2.stderr @@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments --> $DIR/issue-36053-2.rs:7:32 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ --------- - | | | | - | | | help: consider borrowing the argument: `&&str` - | | found signature defined here + | ^^^^^^ --------- found signature defined here + | | | expected due to this | = note: expected closure signature `for<'a> fn(&'a &str) -> _` found closure signature `for<'a> fn(&'a str) -> _` note: required by a bound in `filter` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider borrowing the argument + | +LL | once::<&str>("str").fuse().filter(|a: &&str| true).count(); + | + error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied --> $DIR/issue-36053-2.rs:7:55 diff --git a/tests/ui/type-alias-impl-trait/outlives-bound-var.rs b/tests/ui/type-alias-impl-trait/outlives-bound-var.rs new file mode 100644 index 00000000000..b8fac45b76d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/outlives-bound-var.rs @@ -0,0 +1,18 @@ +// Here we process outlive obligations involving +// opaque types with bound vars in substs. +// This was an ICE. +// +// check-pass +#![feature(type_alias_impl_trait)] + +type Ty<'a> = impl Sized + 'a; +fn define<'a>() -> Ty<'a> {} + +// Ty<'^0>: 'static +fn test1(_: &'static fn(Ty<'_>)) {} + +fn test2() { + None::<&fn(Ty<'_>)>; +} + +fn main() { } |
