From 73a3c7eac8be9580f2a75d6d96a05e7e212baa22 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 13 Aug 2022 19:30:02 +0300 Subject: [PATCH 1/5] [REFACTOR] add fn finalize_opaque_types --- compiler/rustc_borrowck/src/type_check/mod.rs | 88 +++++++++++-------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7bf7f7357bf4f..bd79c5647952e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -200,46 +200,8 @@ pub(crate) fn type_check<'mir, 'tcx>( ); translate_outlives_facts(&mut cx); - let opaque_type_values = - infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - - opaque_type_values - .into_iter() - .map(|(opaque_type_key, decl)| { - cx.fully_perform_op( - Locations::All(body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |infcx| { - infcx.register_member_constraints( - param_env, - opaque_type_key, - decl.hidden_type.ty, - decl.hidden_type.span, - ); - Ok(InferOk { value: (), obligations: vec![] }) - }, - || "opaque_type_map".to_string(), - ), - ) - .unwrap(); - let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); - trace!( - "finalized opaque type {:?} to {:#?}", - opaque_type_key, - hidden_type.ty.kind() - ); - if hidden_type.has_infer_types_or_consts() { - infcx.tcx.sess.delay_span_bug( - decl.hidden_type.span, - &format!("could not resolve {:#?}", hidden_type.ty.kind()), - ); - hidden_type.ty = infcx.tcx.ty_error(); - } - (opaque_type_key, (hidden_type, decl.origin)) - }) - .collect() + cx.finalize_opaque_types() }, ); @@ -2680,6 +2642,54 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_iscleanup(&body, block_data); } } + + /// Generates member constraints for the opaque types found so far. + /// Returns a map to their hidden types. + fn finalize_opaque_types( + &mut self, + ) -> VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)> { + let opaque_type_values = + self.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + opaque_type_values + .into_iter() + .map(|(opaque_type_key, decl)| { + let param_env = self.param_env; + self.fully_perform_op( + Locations::All(self.body.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |infcx| { + infcx.register_member_constraints( + param_env, + opaque_type_key, + decl.hidden_type.ty, + decl.hidden_type.span, + ); + Ok(InferOk { value: (), obligations: vec![] }) + }, + || "opaque_type_map".to_string(), + ), + ) + .unwrap(); + let mut hidden_type = self.infcx.resolve_vars_if_possible(decl.hidden_type); + trace!( + "finalized opaque type {:?} to {:#?}", + opaque_type_key, + hidden_type.ty.kind() + ); + if hidden_type.has_infer_types_or_consts() { + self.infcx.tcx.sess.delay_span_bug( + decl.hidden_type.span, + &format!("could not resolve {:#?}", hidden_type.ty.kind()), + ); + hidden_type.ty = self.infcx.tcx.ty_error(); + } + + (opaque_type_key, (hidden_type, decl.origin)) + }) + .collect() + } } trait NormalizeLocation: fmt::Debug + Copy { From 0329621e9ed1cb19c96e9c656ac6dfa427f2b66f Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 13 Aug 2022 20:07:59 +0300 Subject: [PATCH 2/5] [REFACTOR] use OpaqueTypeMap type alias --- .../src/region_infer/opaque_types.rs | 19 ++++++++++--------- compiler/rustc_borrowck/src/type_check/mod.rs | 16 ++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d6712b6a4799c..3eed9f33fb8c0 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -3,6 +3,7 @@ use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; +use rustc_infer::infer::opaque_types::OpaqueTypeMap; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; @@ -62,12 +63,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + opaque_ty_decls: OpaqueTypeMap<'tcx>, ) -> VecMap> { let mut result: VecMap> = VecMap::new(); - for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { + for (opaque_type_key, decl) in opaque_ty_decls { let substs = opaque_type_key.substs; - debug!(?concrete_type, ?substs); + debug!(?decl.hidden_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; let universal_substs = infcx.tcx.fold_regions(substs, |region, _| { @@ -90,7 +91,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { None => { subst_regions.push(vid); infcx.tcx.sess.delay_span_bug( - concrete_type.span, + decl.hidden_type.span, "opaque type with non-universal region substs", ); infcx.tcx.lifetimes.re_static @@ -102,7 +103,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { subst_regions.dedup(); let universal_concrete_type = - infcx.tcx.fold_regions(concrete_type, |region, _| match *region { + infcx.tcx.fold_regions(decl.hidden_type, |region, _| match *region { ty::ReVar(vid) => subst_regions .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) @@ -118,7 +119,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let ty = infcx.infer_opaque_definition_from_instantiation( opaque_type_key, universal_concrete_type, - origin, + decl.origin, ); // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to `(X, Y)` @@ -128,7 +129,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if prev.ty != ty { if !ty.references_error() { prev.report_mismatch( - &OpaqueHiddenType { ty, span: concrete_type.span }, + &OpaqueHiddenType { ty, span: decl.hidden_type.span }, infcx.tcx, ); } @@ -136,11 +137,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Pick a better span if there is one. // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. - prev.span = prev.span.substitute_dummy(concrete_type.span); + prev.span = prev.span.substitute_dummy(decl.hidden_type.span); } else { result.insert( opaque_type_key.def_id, - OpaqueHiddenType { ty, span: concrete_type.span }, + OpaqueHiddenType { ty, span: decl.hidden_type.span }, ); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index bd79c5647952e..d2220b9fd7717 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -5,16 +5,15 @@ use std::{fmt, iter, mem}; use either::Either; -use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::opaque_types::{OpaqueTypeDecl, OpaqueTypeMap}; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -30,8 +29,8 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, - OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty, + TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -870,8 +869,7 @@ struct BorrowCheckContext<'a, 'tcx> { pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen>, - pub(crate) opaque_type_values: - VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + pub(crate) opaque_type_values: OpaqueTypeMap<'tcx>, } /// A collection of region constraints that must be satisfied for the @@ -2645,9 +2643,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// Generates member constraints for the opaque types found so far. /// Returns a map to their hidden types. - fn finalize_opaque_types( - &mut self, - ) -> VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)> { + fn finalize_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { let opaque_type_values = self.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); @@ -2686,7 +2682,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { hidden_type.ty = self.infcx.tcx.ty_error(); } - (opaque_type_key, (hidden_type, decl.origin)) + (opaque_type_key, OpaqueTypeDecl { hidden_type, ..decl }) }) .collect() } From 3a423b75d50d1a5813433558fe38f2fea42e16ab Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 15 Aug 2022 23:07:42 +0300 Subject: [PATCH 3/5] fix eval_outlives for higher-ranked regions When checking `'sup: 'sub`, take placeholder elements into account. This wasn't a problem previously (I hope!) because `eval_outlives` was only used for type_tests, which don't have higher-ranked outlive relations. --- compiler/rustc_borrowck/src/region_infer/mod.rs | 8 ++++++++ .../rustc_borrowck/src/region_infer/values.rs | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2894c6d29ec43..0970b5f82b2f5 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1360,6 +1360,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { return self.eval_outlives(sup_region, self.universal_regions.fr_static); } + // Check `sup_region` contains all the placeholder regions in `sub_region`. + if !self.scc_values.contains_placeholders(sup_region_scc, sub_region_scc) { + debug!( + "eval_outlives: returning false because sub region contains a placeholder region not present in super" + ); + return false; + } + // Both the `sub_region` and `sup_region` consist of the union // of some number of universal regions (along with the union // of various points in the CFG; ignore those points for diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index c81ef10f7c740..f6baa3fd8e510 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -303,6 +303,22 @@ impl RegionValues { } } + /// Returns `true` if `sup_region` contains all the placeholder elements that + /// `sub_region` contains. + pub(crate) fn contains_placeholders(&self, sup_region: N, sub_region: N) -> bool { + if let Some(sub_row) = self.placeholders.row(sub_region) { + if let Some(sup_row) = self.placeholders.row(sup_region) { + sup_row.superset(sub_row) + } else { + // sup row is empty, so sub row must be empty + sub_row.is_empty() + } + } else { + // sub row is empty, always true + true + } + } + /// Returns the locations contained within a given region `r`. pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { self.points.row(r).into_iter().flat_map(move |set| { From fcbd6a30b9dccf5daa47b8ab4de7bb0e12ddbc7a Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Tue, 16 Aug 2022 02:21:56 +0300 Subject: [PATCH 4/5] support higher-ranked region in member constraints --- .../rustc_borrowck/src/region_infer/mod.rs | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 0970b5f82b2f5..8783a16d6fc68 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -712,16 +712,28 @@ impl<'tcx> RegionInferenceContext<'tcx> { *c_r = self.scc_representatives[scc]; } - // The 'member region' in a member constraint is part of the - // hidden type, which must be in the root universe. Therefore, - // it cannot have any placeholders in its value. - assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT); - debug_assert!( - self.scc_values.placeholders_contained_in(scc).next().is_none(), - "scc {:?} in a member constraint has placeholder value: {:?}", - scc, - self.scc_values.region_value_str(scc), - ); + // The 'member region' may have a placeholder region in its value. + // Consider the inner opaque type `impl Sized` in: + // `fn test() -> impl for<'a> Trait<'a, Ty = impl Sized + 'a>`. + // Here choice_regions = ['static, Placeholder('a, U1)]. + if self.scc_universes[scc] != ty::UniverseIndex::ROOT { + let Some(&choice) = choice_regions + .iter() + .find(|&&choice| self.eval_equal(choice, self.scc_representatives[scc])) + else { + debug!("failed higher-ranked member constraint"); + return false; + }; + + self.member_constraints_applied.push(AppliedMemberConstraint { + member_region_scc: scc, + min_choice: choice, + member_constraint_index, + }); + + debug!(?choice, "higher-ranked"); + return true; + } // The existing value for `scc` is a lower-bound. This will // consist of some set `{P} + {LB}` of points `{P}` and From e6b62a006d889b78b550d4c4a5a550bdd64a4590 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Tue, 16 Aug 2022 02:31:16 +0300 Subject: [PATCH 5/5] support higher-ranked regions in opaque type inference --- .../rustc_borrowck/src/region_infer/mod.rs | 16 ++++ .../src/region_infer/opaque_types.rs | 54 ++++++++++--- compiler/rustc_borrowck/src/type_check/mod.rs | 15 ++++ .../impl-trait/higher-ranked-regions-diag.rs | 25 ++++++ .../higher-ranked-regions-diag.stderr | 11 +++ .../higher-ranked-regions-basic.rs | 77 +++++++++++++++++++ .../higher-ranked-regions-basic.stderr | 49 ++++++++++++ .../higher-ranked-regions-gat.rs | 22 ++++++ 8 files changed, 257 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/impl-trait/higher-ranked-regions-diag.rs create mode 100644 src/test/ui/impl-trait/higher-ranked-regions-diag.stderr create mode 100644 src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.rs create mode 100644 src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.stderr create mode 100644 src/test/ui/type-alias-impl-trait/higher-ranked-regions-gat.rs diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 8783a16d6fc68..cc908909f2d2a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -167,9 +167,25 @@ pub(crate) struct RegionDefinition<'tcx> { /// If this is 'static or an early-bound region, then this is /// `Some(X)` where `X` is the name of the region. + /// + /// Use the method `Self::external_name` for more flexibility. pub(crate) external_name: Option>, } +impl<'tcx> RegionDefinition<'tcx> { + /// Gets the name of a universal region (including placeholders). + /// Returns `None` if this is an existential variable. + pub fn external_name(&self, tcx: TyCtxt<'tcx>) -> Option> { + match self.origin { + NllRegionVariableOrigin::FreeRegion => self.external_name, + NllRegionVariableOrigin::Placeholder(placeholder) => { + Some(tcx.mk_region(ty::RePlaceholder(placeholder))) + } + NllRegionVariableOrigin::Existential { .. } => None, + } + } +} + /// N.B., the variants in `Cause` are intentionally ordered. Lower /// values are preferred when it comes to error messages. Do not /// reorder willy nilly. diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 3eed9f33fb8c0..5ae45f9489e40 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -72,14 +72,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut subst_regions = vec![self.universal_regions.fr_static]; let universal_substs = infcx.tcx.fold_regions(substs, |region, _| { - if let ty::RePlaceholder(..) = region.kind() { - // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs. - return region; + let (vid, scc) = match region.kind() { + ty::ReVar(vid) => (vid, self.constraint_sccs.scc(vid)), + _ => bug!("expected nll var"), + }; + trace!(?vid, ?scc); + + // Special handling of higher-ranked regions. These appear in the substs of the + // inner opaque type `impl Sized` in: + // `fn test() -> impl for<'a> Trait<'a, Ty = impl Sized + 'a>` + if self.scc_universes[scc] != ty::UniverseIndex::ROOT { + subst_regions.push(vid); + return self.definitions[vid] + .external_name(infcx.tcx) + .expect("higher-ranked existential region found in opaque type substs"); } - let vid = self.to_region_vid(region); - trace!(?vid); - let scc = self.constraint_sccs.scc(vid); - trace!(?scc); + match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| { self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?) }) { @@ -107,9 +115,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { ty::ReVar(vid) => subst_regions .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) - .and_then(|ur_vid| self.definitions[*ur_vid].external_name) + .and_then(|ur_vid| self.definitions[*ur_vid].external_name(infcx.tcx)) .unwrap_or(infcx.tcx.lifetimes.re_root_empty), - _ => region, + _ => bug!("expected nll var"), }); debug!(?universal_concrete_type, ?universal_substs); @@ -160,6 +168,25 @@ impl<'tcx> RegionInferenceContext<'tcx> { { tcx.fold_regions(ty, |region, _| match *region { ty::ReVar(vid) => { + let scc = self.constraint_sccs.scc(vid); + + // Special handling of higher-ranked regions. + if self.scc_universes[scc] != ty::UniverseIndex::ROOT { + // If the region contains a single placeholder then they're equal. + if let Some((0, placeholder)) = + self.scc_values.placeholders_contained_in(scc).enumerate().last() + { + // HACK: we convert named placeholders to free regions for better errors. + // Otherwise, this is incorrect. + if let bound_region @ ty::BrNamed(scope, _) = placeholder.name { + return tcx + .mk_region(ty::ReFree(ty::FreeRegion { scope, bound_region })); + } + } + // Fallback: this will produce a cryptic error message. + return region; + } + // Find something that we can name let upper_bound = self.approx_universal_upper_bound(vid); let upper_bound = &self.definitions[upper_bound]; @@ -385,7 +412,7 @@ fn check_opaque_type_parameter_valid( return false; } GenericArgKind::Lifetime(lt) => { - matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_) | ty::RePlaceholder(_)) } GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), }; @@ -495,9 +522,12 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { ty::ReErased => return r, // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} + ty::ReEarlyBound(_) + | ty::ReFree(_) + | ty::RePlaceholder(_) + | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} - ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { + ty::ReEmpty(_) | ty::ReVar(_) => { // All of the regions in the type should either have been // erased by writeback, or mapped back to named regions by // borrow checking. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d2220b9fd7717..8b4817e734a59 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2682,6 +2682,21 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { hidden_type.ty = self.infcx.tcx.ty_error(); } + // Convert all regions to nll vars. + let (opaque_type_key, hidden_type) = + self.infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| { + match region.kind() { + ty::ReVar(_) => region, + ty::RePlaceholder(placeholder) => self + .borrowck_context + .constraints + .placeholder_region(self.infcx, placeholder), + _ => self.infcx.tcx.mk_region(ty::ReVar( + self.borrowck_context.universal_regions.to_region_vid(region), + )), + } + }); + (opaque_type_key, OpaqueTypeDecl { hidden_type, ..decl }) }) .collect() diff --git a/src/test/ui/impl-trait/higher-ranked-regions-diag.rs b/src/test/ui/impl-trait/higher-ranked-regions-diag.rs new file mode 100644 index 0000000000000..470022565f6da --- /dev/null +++ b/src/test/ui/impl-trait/higher-ranked-regions-diag.rs @@ -0,0 +1,25 @@ +// Regression test for #97099. +// This was an ICE because `impl Sized` captures the lifetime 'a. + +// check-fail + +trait Trait { + type Assoc; +} + +struct Foo; + +impl<'a> Trait<&'a ()> for Foo { + type Assoc = (); +} + +fn foo() -> impl for<'a> Trait<&'a ()> { + Foo +} + +fn bar() -> impl for<'a> Trait<&'a (), Assoc = impl Sized> { + foo() + //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/src/test/ui/impl-trait/higher-ranked-regions-diag.stderr b/src/test/ui/impl-trait/higher-ranked-regions-diag.stderr new file mode 100644 index 0000000000000..b8a2c96c563a3 --- /dev/null +++ b/src/test/ui/impl-trait/higher-ranked-regions-diag.stderr @@ -0,0 +1,11 @@ +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/higher-ranked-regions-diag.rs:21:5 + | +LL | fn bar() -> impl for<'a> Trait<&'a (), Assoc = impl Sized> { + | -- hidden type ` Trait<&'a ()> as Trait<&'a ()>>::Assoc` captures the lifetime `'a` as defined here +LL | foo() + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.rs b/src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.rs new file mode 100644 index 0000000000000..099d489148b05 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.rs @@ -0,0 +1,77 @@ +// Basic tests for opaque type inference under for<_> binders. + +// check-fail + +#![feature(type_alias_impl_trait)] + +trait Trait<'a> { + type Ty; +} +impl<'a, T> Trait<'a> for T { + type Ty = &'a (); +} + +mod basic_pass { + use super::*; + type Opq<'a> = impl Sized + 'a; + fn test() -> impl for<'a> Trait<'a, Ty = Opq<'a>> {} +} + +mod capture_rpit { + use super::*; + fn test() -> impl for<'a> Trait<'a, Ty = impl Sized> {} + //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds +} + +mod capture_tait { + use super::*; + type Opq0 = impl Sized; + type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0>; + type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>; + fn test() -> Opq2 {} + //~^ ERROR hidden type for `capture_tait::Opq0` captures lifetime that does not appear in bounds +} + +mod capture_tait_complex_pass { + use super::*; + type Opq0<'a> = impl Sized; + type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'b>>; // <- Note 'b + type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>; + fn test() -> Opq2 {} +} + +// Same as the above, but make sure that different placeholder regions are not equal. +mod capture_tait_complex_fail { + use super::*; + type Opq0<'a> = impl Sized; + type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a>>; // <- Note 'a + type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>; + fn test() -> Opq2 {} + //~^ ERROR hidden type for `capture_tait_complex_fail::Opq0<'a>` captures lifetime that does not appear in bounds +} + +// non-defining use because 'static is used. +mod constrain_fail0 { + use super::*; + type Opq0<'a, 'b> = impl Sized; + fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'static>> {} + //~^ ERROR non-defining opaque type use in defining scope +} + +// non-defining use because generic lifetime is used multiple times. +mod constrain_fail { + use super::*; + type Opq0<'a, 'b> = impl Sized; + fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'a>> {} + //~^ ERROR non-defining opaque type use in defining scope +} + +mod constrain_pass { + use super::*; + type Opq0<'a, 'b> = impl Sized; + type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a, 'b>>; + type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>; + fn test() -> Opq2 {} +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.stderr b/src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.stderr new file mode 100644 index 0000000000000..85456ff6e5257 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/higher-ranked-regions-basic.stderr @@ -0,0 +1,49 @@ +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/higher-ranked-regions-basic.rs:22:58 + | +LL | fn test() -> impl for<'a> Trait<'a, Ty = impl Sized> {} + | -- ^^ + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here + +error[E0700]: hidden type for `capture_tait::Opq0` captures lifetime that does not appear in bounds + --> $DIR/higher-ranked-regions-basic.rs:31:23 + | +LL | type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0>; + | -- hidden type `&'b ()` captures the lifetime `'b` as defined here +LL | type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>; +LL | fn test() -> Opq2 {} + | ^^ + +error[E0700]: hidden type for `capture_tait_complex_fail::Opq0<'a>` captures lifetime that does not appear in bounds + --> $DIR/higher-ranked-regions-basic.rs:49:23 + | +LL | type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a>>; // <- Note 'a + | -- hidden type `&'b ()` captures the lifetime `'b` as defined here +LL | type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>; +LL | fn test() -> Opq2 {} + | ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/higher-ranked-regions-basic.rs:57:65 + | +LL | type Opq0<'a, 'b> = impl Sized; + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +LL | fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'static>> {} + | ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/higher-ranked-regions-basic.rs:65:60 + | +LL | fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'a>> {} + | ^^ + | +note: lifetime used multiple times + --> $DIR/higher-ranked-regions-basic.rs:64:15 + | +LL | type Opq0<'a, 'b> = impl Sized; + | ^^ ^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/type-alias-impl-trait/higher-ranked-regions-gat.rs b/src/test/ui/type-alias-impl-trait/higher-ranked-regions-gat.rs new file mode 100644 index 0000000000000..c3d4cab64f6c6 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/higher-ranked-regions-gat.rs @@ -0,0 +1,22 @@ +// Regression test for #97098. + +// check-pass + +#![feature(generic_associated_types)] +#![feature(type_alias_impl_trait)] + +pub trait Trait { + type Assoc<'a>; +} + +pub type Foo = impl for<'a> Trait = FooAssoc<'a>>; +pub type FooAssoc<'a> = impl Sized; + +struct Struct; +impl Trait for Struct { + type Assoc<'a> = &'a u32; +} + +const FOO: Foo = Struct; + +fn main() {}