diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 65b91eedf8a27..5c8bf0a84161e 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -381,9 +381,19 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> RefDecodable<'tcx, D> for ty::List> { + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder.tcx().mk_generator_predicates( + (0..len).map::, _>(|_| Decodable::decode(decoder)), + ) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, + &'tcx ty::List>, &'tcx ty::List>>, &'tcx Allocation, &'tcx mir::Body<'tcx>, @@ -504,6 +514,8 @@ macro_rules! impl_binder_encode_decode { impl_binder_encode_decode! { &'tcx ty::List>, + &'tcx ty::List>, + ty::GeneratorInterior<'tcx>, ty::FnSig<'tcx>, ty::ExistentialPredicate<'tcx>, ty::TraitRef<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6c8573805cb94..1db3625acbd0f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -17,9 +17,10 @@ use crate::ty::TyKind::*; use crate::ty::{ self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar, - FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst, - ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, - ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, + FloatVid, GeneratorInterior, GeneratorPredicate, GenericParamDefKind, InferConst, InferTy, + IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, + PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, + TyS, TyVar, TyVid, TypeAndMut, UintTy, }; use rustc_ast as ast; use rustc_attr as attr; @@ -102,6 +103,7 @@ pub struct CtxtInterners<'tcx> { substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind>, + generator_predicates: InternedSet<'tcx, List>>, poly_existential_predicates: InternedSet<'tcx, List>>>, predicate: InternedSet<'tcx, PredicateInner<'tcx>>, @@ -129,6 +131,7 @@ impl<'tcx> CtxtInterners<'tcx> { type_list: Default::default(), substs: Default::default(), region: Default::default(), + generator_predicates: Default::default(), poly_existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicate: Default::default(), @@ -1654,6 +1657,7 @@ nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} +nop_list_lift! {generator_predicates; GeneratorPredicate<'a> => GeneratorPredicate<'tcx>} nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} @@ -2115,6 +2119,7 @@ slice_interners!( type_list: _intern_type_list(Ty<'tcx>), substs: _intern_substs(GenericArg<'tcx>), canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>), + generator_predicates: _intern_generator_predicates(GeneratorPredicate<'tcx>), poly_existential_predicates: _intern_poly_existential_predicates(ty::Binder<'tcx, ExistentialPredicate<'tcx>>), predicates: _intern_predicates(Predicate<'tcx>), @@ -2406,8 +2411,11 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List>>) -> Ty<'tcx> { - self.mk_ty(GeneratorWitness(types)) + pub fn mk_generator_witness( + self, + inner: ty::Binder<'tcx, GeneratorInterior<'tcx>>, + ) -> Ty<'tcx> { + self.mk_ty(GeneratorWitness(inner)) } #[inline] @@ -2509,6 +2517,17 @@ impl<'tcx> TyCtxt<'tcx> { Place { local: place.local, projection: self.intern_place_elems(&projection) } } + pub fn intern_generator_predicates( + self, + predicates: &[GeneratorPredicate<'tcx>], + ) -> &'tcx List> { + if predicates.is_empty() { + List::empty() + } else { + self._intern_generator_predicates(predicates) + } + } + pub fn intern_poly_existential_predicates( self, eps: &[ty::Binder<'tcx, ExistentialPredicate<'tcx>>], @@ -2583,6 +2602,15 @@ impl<'tcx> TyCtxt<'tcx> { }) } + pub fn mk_generator_predicates< + I: InternAs<[GeneratorPredicate<'tcx>], &'tcx List>>, + >( + self, + iter: I, + ) -> I::Output { + iter.intern_with(|xs| self.intern_generator_predicates(xs)) + } + pub fn mk_poly_existential_predicates< I: InternAs< [ty::Binder<'tcx, ExistentialPredicate<'tcx>>], diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index daf9156a15f34..4d2a1b0a267e4 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -118,8 +118,8 @@ pub fn simplify_type( } ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), - ty::GeneratorWitness(ref tys) => { - Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())) + ty::GeneratorWitness(ref inner, ..) => { + Some(GeneratorWitnessSimplifiedType(inner.as_ref().skip_binder().tys.len())) } ty::Never => Some(NeverSimplifiedType), ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())), diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index f06a1b09cd82a..08829abfb6aae 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -117,8 +117,13 @@ impl FlagComputation { self.add_ty(substs.tupled_upvars_ty()); } - &ty::GeneratorWitness(ts) => { - self.bound_computation(ts, |flags, ts| flags.add_tys(ts)); + &ty::GeneratorWitness(inner) => { + self.bound_computation(inner, |computation, inner| { + computation.add_tys(&inner.tys); + for predicate in inner.predicates { + computation.add_predicate_atom(predicate.to_predicate_atom()); + } + }); } &ty::Closure(_, substs) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6174c922e2d06..62b7a8fc29623 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -75,10 +75,10 @@ pub use self::sty::{ Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, - GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, - ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, - PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, - UpvarSubsts, VarianceDiagInfo, + GeneratorInterior, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, + InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, + PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, + RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; @@ -170,18 +170,8 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } -#[derive( - Copy, - Clone, - PartialEq, - Eq, - Hash, - TyEncodable, - TyDecodable, - HashStable, - Debug, - TypeFoldable -)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(TyEncodable, TyDecodable, HashStable, Debug, TypeFoldable)] pub enum ImplPolarity { /// `impl Trait for Type` Positive, @@ -225,7 +215,8 @@ pub enum Visibility { Invisible, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Hash, HashStable, TyEncodable, TyDecodable)] pub enum BoundConstness { /// `T: Trait` NotConst, @@ -744,7 +735,7 @@ impl<'tcx> Predicate<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx>, @@ -871,7 +862,7 @@ impl<'tcx> Term<'tcx> { /// equality between arbitrary types. Processing an instance of /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, @@ -997,6 +988,37 @@ impl<'tcx> Predicate<'tcx> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Hash, HashStable, TyEncodable, TyDecodable, TypeFoldable)] +pub enum GeneratorPredicate<'tcx> { + Trait(TraitPredicate<'tcx>), + RegionOutlives(RegionOutlivesPredicate<'tcx>), + TypeOutlives(TypeOutlivesPredicate<'tcx>), + Projection(ProjectionPredicate<'tcx>), +} + +impl<'tcx> GeneratorPredicate<'tcx> { + pub fn to_predicate_atom(self) -> PredicateKind<'tcx> { + match self { + GeneratorPredicate::Trait(p) => PredicateKind::Trait(p), + GeneratorPredicate::RegionOutlives(p) => PredicateKind::RegionOutlives(p), + GeneratorPredicate::TypeOutlives(p) => PredicateKind::TypeOutlives(p), + GeneratorPredicate::Projection(p) => PredicateKind::Projection(p), + } + } +} + +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, GeneratorPredicate<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + match self.skip_binder() { + GeneratorPredicate::Trait(p) => self.rebind(p).to_predicate(tcx), + GeneratorPredicate::RegionOutlives(p) => self.rebind(p).to_predicate(tcx), + GeneratorPredicate::TypeOutlives(p) => self.rebind(p).to_predicate(tcx), + GeneratorPredicate::Projection(p) => self.rebind(p).to_predicate(tcx), + } + } +} + /// Represents the bounds declared on a particular set of type /// parameters. Should eventually be generalized into a flag list of /// where-clauses. You can obtain an `InstantiatedPredicates` list from a diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ddcc8680d8352..37ff0cffe691f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -698,8 +698,8 @@ pub trait PrettyPrinter<'tcx>: p!("]") } - ty::GeneratorWitness(types) => { - p!(in_binder(&types)); + ty::GeneratorWitness(inner, ..) => { + p!(in_binder(&inner.map_bound(|inner| inner.tys))); } ty::Closure(did, substs) => { p!(write("[")); diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index bb040acd2703d..872eb99dcf70a 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -340,19 +340,22 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { } } -#[derive(Copy, Debug, Clone, TypeFoldable)] -struct GeneratorWitness<'tcx>(&'tcx ty::List>); - -impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { +impl<'tcx> Relate<'tcx> for ty::GeneratorInterior<'tcx> { fn relate>( relation: &mut R, - a: GeneratorWitness<'tcx>, - b: GeneratorWitness<'tcx>, - ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> { - assert_eq!(a.0.len(), b.0.len()); - let tcx = relation.tcx(); - let types = tcx.mk_type_list(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?; - Ok(GeneratorWitness(types)) + a: ty::GeneratorInterior<'tcx>, + b: ty::GeneratorInterior<'tcx>, + ) -> RelateResult<'tcx, ty::GeneratorInterior<'tcx>> { + assert_eq!(a.tys.len(), b.tys.len()); + assert_eq!(a.predicates.len(), b.predicates.len()); + Ok(ty::GeneratorInterior { + tys: relation + .tcx() + .mk_type_list(a.tys.iter().zip(b.tys).map(|(a, b)| relation.relate(a, b)))?, + predicates: relation.tcx().mk_generator_predicates( + a.predicates.iter().zip(b.predicates).map(|(a, b)| relation.relate(a, b)), + )?, + }) } } @@ -434,14 +437,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(tcx.mk_generator(a_id, substs, movability)) } - (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => { - // Wrap our types with a temporary GeneratorWitness struct - // inside the binder so we can related them - let a_types = a_types.map_bound(GeneratorWitness); - let b_types = b_types.map_bound(GeneratorWitness); - // Then remove the GeneratorWitness for the result - let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0); - Ok(tcx.mk_generator_witness(types)) + (&ty::GeneratorWitness(a_interior), &ty::GeneratorWitness(b_interior)) => { + Ok(tcx.mk_generator_witness(relation.relate(a_interior, b_interior)?)) } (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => { @@ -860,6 +857,45 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::GeneratorPredicate<'tcx> { + fn relate>( + relation: &mut R, + a: ty::GeneratorPredicate<'tcx>, + b: ty::GeneratorPredicate<'tcx>, + ) -> RelateResult<'tcx, ty::GeneratorPredicate<'tcx>> { + Ok(match (a, b) { + (ty::GeneratorPredicate::Trait(a), ty::GeneratorPredicate::Trait(b)) => { + ty::GeneratorPredicate::Trait(relation.relate(a, b)?) + } + ( + ty::GeneratorPredicate::RegionOutlives(a), + ty::GeneratorPredicate::RegionOutlives(b), + ) => ty::GeneratorPredicate::RegionOutlives(relation.relate(a, b)?), + (ty::GeneratorPredicate::TypeOutlives(a), ty::GeneratorPredicate::TypeOutlives(b)) => { + ty::GeneratorPredicate::TypeOutlives(relation.relate(a, b)?) + } + (ty::GeneratorPredicate::Projection(a), ty::GeneratorPredicate::Projection(b)) => { + ty::GeneratorPredicate::Projection(relation.relate(a, b)?) + } + _ => bug!("cannot relate {:?} and {:?}", a, b), + }) + } +} + +impl<'tcx, A, B> Relate<'tcx> for ty::OutlivesPredicate +where + A: Relate<'tcx>, + B: Relate<'tcx>, +{ + fn relate>( + relation: &mut R, + a: ty::OutlivesPredicate, + b: ty::OutlivesPredicate, + ) -> RelateResult<'tcx, Self> { + Ok(ty::OutlivesPredicate(relation.relate(a.0, b.0)?, relation.relate(a.1, b.1)?)) + } +} + /////////////////////////////////////////////////////////////////////////// // Error handling diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1c5bc7860db2d..301001637a57b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -908,6 +908,19 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { + fn try_super_fold_with>( + self, + folder: &mut F, + ) -> Result { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_generator_predicates(v)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { + self.iter().try_for_each(|t| t.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { fn try_super_fold_with>( self, @@ -1007,7 +1020,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::Generator(did, substs, movability) => { ty::Generator(did, substs.try_fold_with(folder)?, movability) } - ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?), + ty::GeneratorWitness(inner) => ty::GeneratorWitness(inner.try_fold_with(folder)?), ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?), ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?), ty::Opaque(did, substs) => ty::Opaque(did, substs.try_fold_with(folder)?), @@ -1055,7 +1068,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty.visit_with(visitor) } ty::Generator(_did, ref substs, _) => substs.visit_with(visitor), - ty::GeneratorWitness(ref types) => types.visit_with(visitor), + ty::GeneratorWitness(ref inner, ..) => inner.visit_with(visitor), ty::Closure(_did, ref substs) => substs.visit_with(visitor), ty::Projection(ref data) => data.visit_with(visitor), ty::Opaque(_, ref substs) => substs.visit_with(visitor), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 20db25f7899dd..aefea18e36dab 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -159,8 +159,8 @@ pub enum TyKind<'tcx> { Generator(DefId, SubstsRef<'tcx>, hir::Movability), /// A type representing the types stored inside a generator. - /// This should only appear in GeneratorInteriors. - GeneratorWitness(Binder<'tcx, &'tcx List>>), + /// This should only appear inside of a generator's interior types. + GeneratorWitness(Binder<'tcx, GeneratorInterior<'tcx>>), /// The never type `!`. Never, @@ -2308,3 +2308,13 @@ impl<'tcx> VarianceDiagInfo<'tcx> { } } } + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] +pub struct GeneratorInterior<'tcx> { + /// types alive across await points in the generator + pub tys: &'tcx List>, + /// predicates that we know hold in the environment where the generator was created, + /// which are used when checking auto traits on the generator witness + pub predicates: &'tcx List>, +} diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 38aa76333851f..befbc5497dee7 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -179,8 +179,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::FnDef(_, substs) => { stack.extend(substs.iter().rev()); } - ty::GeneratorWitness(ts) => { - stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into())); + ty::GeneratorWitness(inner) => { + stack.extend(inner.skip_binder().tys.iter().rev().map(|ty| ty.into())); } ty::FnPtr(sig) => { stack.push(sig.skip_binder().output().into()); diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 433a1c6ad67cc..78564e222e900 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -730,9 +730,10 @@ fn sanitize_witness<'tcx>( let allowed_upvars = tcx.normalize_erasing_regions(param_env, upvars); let allowed = match witness.kind() { - &ty::GeneratorWitness(interior_tys) => { - tcx.normalize_erasing_late_bound_regions(param_env, interior_tys) - } + &ty::GeneratorWitness(interior) => tcx.normalize_erasing_late_bound_regions( + param_env, + interior.map_bound(|interior| interior.tys), + ), _ => { tcx.sess.delay_span_bug( body.span, diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 4b17c22a68c26..c16716df724b6 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -329,6 +329,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.visit_child_body(def_id, substs); ControlFlow::CONTINUE } + ty::GeneratorWitness(inner) => inner.map_bound(|inner| inner.tys).visit_with(self), ty::Param(param) => { debug!(?param); self.unused_parameters.clear(param.index); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f2ed5ae26a3c2..9f48d29fe663d 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -5,7 +5,6 @@ use super::*; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; -use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{Region, RegionVid, Term}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -867,23 +866,3 @@ impl<'tcx> AutoTraitFinder<'tcx> { infcx.freshen(p) } } - -// Replaces all ReVars in a type with ty::Region's, using the provided map -pub struct RegionReplacer<'a, 'tcx> { - vid_to_region: &'a FxHashMap>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - (match r { - ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(), - _ => None, - }) - .unwrap_or_else(|| r.super_fold_with(self)) - } -} diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2e20ea34e10ef..4da959632d90f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -12,8 +12,8 @@ use rustc_hir::Constness; use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_middle::ty; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; -use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{ToPolyTraitRef, ToPredicate}; use rustc_span::def_id::DefId; @@ -310,23 +310,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> ImplSourceAutoImplData> { debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate"); - let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); - let types = self.constituent_types_for_ty(self_ty); - self.vtable_auto_impl(obligation, trait_def_id, types) - } - - /// See `confirm_auto_impl_candidate`. - fn vtable_auto_impl( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder<'tcx, Vec>>, - ) -> ImplSourceAutoImplData> { - debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { + let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); let cause = obligation.derived_cause(BuiltinDerivedObligation); + + let (param_env, nested) = + if let ty::GeneratorWitness(interior) = self_ty.skip_binder().kind() { + self.infcx().commit_unconditionally(|_| { + let ty::GeneratorInterior { tys: nested, predicates } = + self.infcx().replace_bound_vars_with_placeholders(*interior); + // FIXME(compiler-errors): Not sure if we should augment the param_env, + // or just make a new param_env from these predicates... + // Some tests fail if we do the former, but doing the latter doesn't + // sound like it works 100% either... + let new_param_env = ty::ParamEnv::new( + self.tcx().mk_predicates(predicates.iter().map(|predicate| { + ty::Binder::dummy(predicate).to_predicate(self.tcx()) + })), + obligation.param_env.reveal(), + obligation.param_env.constness(), + ); + (new_param_env, ty::Binder::dummy(nested.to_vec())) + }) + } else { + (obligation.param_env, self.constituent_types_for_auto_trait(self_ty)) + }; + let mut obligations = self.collect_predicates_for_types( - obligation.param_env, + param_env, cause, obligation.recursion_depth + 1, trait_def_id, @@ -341,17 +352,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.impl_or_trait_obligations( cause, obligation.recursion_depth + 1, - obligation.param_env, + param_env, trait_def_id, &trait_ref.substs, ) }); // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); - - debug!(?obligations, "vtable_auto_impl"); + // predicate as usual, but we filter it out below. + obligations.extend(trait_obligations.into_iter().filter(|implied| { + let kind = implied.predicate.kind(); + match kind.skip_binder() { + ty::PredicateKind::Trait(t) => kind.rebind(t) != obligation.predicate, + _ => true, + } + })); ImplSourceAutoImplData { trait_def_id, nested: obligations } }) @@ -1151,8 +1166,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let generator = substs.as_generator(); stack.extend([generator.tupled_upvars_ty(), generator.witness()]); } - ty::GeneratorWitness(tys) => { - stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); + ty::GeneratorWitness(inner) => { + stack.extend( + tcx.erase_late_bound_regions(inner.map_bound(|inner| inner.tys.to_vec())), + ); } // If we have a projection type, make sure to normalize it so we replace it diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ae53690548375..c0f6c2a36f0fb 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1938,7 +1938,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` - fn constituent_types_for_ty( + fn constituent_types_for_auto_trait( &self, t: ty::Binder<'tcx, Ty<'tcx>>, ) -> ty::Binder<'tcx, Vec>> { @@ -1982,14 +1982,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Generator(_, ref substs, _) => { - let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); - let witness = substs.as_generator().witness(); - t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) + let generator = substs.as_generator(); + let ty = self.infcx.shallow_resolve(generator.tupled_upvars_ty()); + let witness = generator.witness(); + t.rebind(vec![ty, witness]) } - ty::GeneratorWitness(types) => { - debug_assert!(!types.has_escaping_bound_vars()); - types.map_bound(|types| types.to_vec()) + ty::GeneratorWitness(..) => { + unreachable!("This should be handled separately") } // For `PhantomData`, we pass `T`. @@ -2035,8 +2035,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .skip_binder() // binder moved -\ .iter() .flat_map(|ty| { - let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(ty); // <----/ - + let ty = types.rebind(*ty); // <----/ self.infcx.commit_unconditionally(|_| { let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); let Normalized { value: normalized_ty, mut obligations } = diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index fc309aa848ca1..15f871237df20 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -122,8 +122,10 @@ where queue_type(self, substs.tupled_upvars_ty()); let witness = substs.witness(); - let interior_tys = match witness.kind() { - &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), + let interior = match witness.kind() { + &ty::GeneratorWitness(interior, ..) => { + tcx.normalize_erasing_late_bound_regions(self.param_env, interior) + } _ => { tcx.sess.delay_span_bug( tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), @@ -133,7 +135,7 @@ where } }; - for interior_ty in interior_tys { + for interior_ty in interior.tys { queue_type(self, interior_ty); } } diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index c6b92db88ae8a..264e0dc45d1b4 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -3,9 +3,11 @@ //! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the //! types computed here. +mod structural_predicate; + use self::drop_ranges::DropRanges; use super::FnCtxt; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -18,7 +20,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; -use tracing::debug; mod drop_ranges; @@ -59,9 +60,14 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { let ty = self.fcx.resolve_vars_if_possible(ty); - debug!( + trace!( "attempting to record type ty={:?}; hir_id={:?}; scope={:?}; expr={:?}; source_span={:?}; expr_count={:?}", - ty, hir_id, scope, expr, source_span, self.expr_count, + ty, + hir_id, + scope, + expr, + source_span, + self.expr_count, ); let live_across_yield = scope @@ -77,9 +83,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data .iter() .find(|yield_data| { - debug!( + trace!( "comparing counts yield: {} self: {}, source_span = {:?}", - yield_data.expr_and_pat_count, self.expr_count, source_span + yield_data.expr_and_pat_count, + self.expr_count, + source_span ); if ENABLE_DROP_TRACKING @@ -87,7 +95,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { .drop_ranges .is_dropped_at(hir_id, yield_data.expr_and_pat_count) { - debug!("value is dropped at yield point; not recording"); + trace!("value is dropped at yield point; not recording"); return false; } @@ -105,9 +113,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { }); if let Some(yield_data) = live_across_yield { - debug!( + trace!( "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", - expr, scope, ty, self.expr_count, yield_data.span + expr, + scope, + ty, + self.expr_count, + yield_data.span ); if let Some((unresolved_type, unresolved_type_span)) = @@ -167,7 +179,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { }); } } else { - debug!( + trace!( "no type in expr = {:?}, count = {:?}, span = {:?}", expr, self.expr_count, @@ -176,9 +188,10 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { - debug!( + trace!( "remained unresolved_type = {:?}, unresolved_type_span: {:?}", - unresolved_type, unresolved_type_span + unresolved_type, + unresolved_type_span ); self.prev_unresolved_span = unresolved_type_span; } @@ -208,66 +221,98 @@ pub fn resolve_interior<'a, 'tcx>( }; intravisit::walk_body(&mut visitor, body); - // Check that we visited the same amount of expressions and the RegionResolutionVisitor + // Check that we visited the same amount of expressions as the RegionResolutionVisitor let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap(); assert_eq!(region_expr_count, visitor.expr_count); // The types are already kept in insertion order. - let types = visitor.types; + let mut causes = visitor.types; // The types in the generator interior contain lifetimes local to the generator itself, // which should not be exposed outside of the generator. Therefore, we replace these // lifetimes with existentially-bound lifetimes, which reflect the exact value of the // lifetimes not being known by users. - // - // These lifetimes are used in auto trait impl checking (for example, - // if a Sync generator contains an &'α T, we need to check whether &'α T: Sync), - // so knowledge of the exact relationships between them isn't particularly important. - debug!("types in generator {:?}, span = {:?}", types, body.value.span); + debug!("types in generator {:?}, span = {:?}", causes, body.value.span); + // Mapping from region -> anonymized bound region let mut counter = 0; + let mut region_to_anon = FxHashMap::default(); + let mut anonymize_regions = |region, current_depth| { + let region = fcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_region(fcx.tcx, region); + let br = region_to_anon.entry(region).or_insert_with(|| { + let br = + ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon(counter) }; + counter += 1; + br + }); + fcx.tcx.mk_region(ty::ReLateBound(current_depth, *br)) + }; + + // Deduplicate the generator interior types, since we don't need several of the same type let mut captured_tys = FxHashSet::default(); - let type_causes: Vec<_> = types - .into_iter() - .filter_map(|mut cause| { - // Erase regions and canonicalize late-bound regions to deduplicate as many types as we - // can. - let erased = fcx.tcx.erase_regions(cause.ty); - if captured_tys.insert(erased) { - // Replace all regions inside the generator interior with late bound regions. - // Note that each region slot in the types gets a new fresh late bound region, - // which means that none of the regions inside relate to any other, even if - // typeck had previously found constraints that would cause them to be related. - let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| { - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(counter), - kind: ty::BrAnon(counter), - }; - let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br)); - counter += 1; - r - }); + causes.retain(|cause| captured_tys.insert(cause.ty)); - cause.ty = folded; - Some(cause) - } else { - None + // Extract type components to build the witness type, anonymizing regions + let anon_tys = fcx.tcx.mk_type_list( + causes + .iter() + .map(|cause| fcx.tcx.fold_regions(cause.ty, &mut false, &mut anonymize_regions)), + ); + debug!("erased generator interior types: {:?}", anon_tys); + + // Extract the projection types that we know hold in the interior types, so we can reapply them + // later. This step is important because when we erase regions, we might no longer be able to + // apply some projections (since they depend on region knowledge we erased). But since we know + // they hold now, they should hold forever, so we'll add these projections to the param-env later. + let structural_predicates = structural_predicate::StructuralPredicateElaborator::new( + &fcx, + causes.iter().map(|cause| cause.ty), + body.value.span, + ); + let env_predicates = + fcx.param_env.caller_bounds().iter().filter_map(|predicate| { + match predicate.kind().skip_binder() { + ty::PredicateKind::Trait(p) => Some(ty::GeneratorPredicate::Trait(p)), + ty::PredicateKind::RegionOutlives(p) => { + Some(ty::GeneratorPredicate::RegionOutlives(p)) + } + ty::PredicateKind::TypeOutlives(p) => Some(ty::GeneratorPredicate::TypeOutlives(p)), + ty::PredicateKind::Projection(p) => Some(ty::GeneratorPredicate::Projection(p)), + _ => None, } + }); + let anon_predicates = fcx.tcx.mk_generator_predicates( + structural_predicates + .chain(env_predicates) + .map(|predicate| fcx.tcx.fold_regions(predicate, &mut false, &mut anonymize_regions)), + ); + debug!("erased generator implied predicates: {:#?}", anon_predicates); + + let anon_causes = causes + .into_iter() + .map(|mut cause| { + cause.ty = fcx.tcx.fold_regions(cause.ty, &mut false, &mut anonymize_regions); + cause }) .collect(); - // Extract type components to build the witness type. - let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty)); let bound_vars = fcx.tcx.mk_bound_variable_kinds( (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))), ); - let witness = - fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone())); + + let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars( + ty::GeneratorInterior { tys: anon_tys, predicates: anon_predicates }, + bound_vars.clone(), + )); // Store the generator types and spans into the typeck results for this generator. visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = - ty::Binder::bind_with_vars(type_causes, bound_vars); + ty::Binder::bind_with_vars(anon_causes, bound_vars); debug!( "types in generator after region replacement {:?}, span = {:?}", diff --git a/compiler/rustc_typeck/src/check/generator_interior/structural_predicate.rs b/compiler/rustc_typeck/src/check/generator_interior/structural_predicate.rs new file mode 100644 index 0000000000000..1f2a6a482f52a --- /dev/null +++ b/compiler/rustc_typeck/src/check/generator_interior/structural_predicate.rs @@ -0,0 +1,128 @@ +use super::FnCtxt; + +use rustc_data_structures::stable_set::FxHashSet; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; + +/// This helper walks through generator-interior types, collecting projection types, +/// and creating ProjectionPredicates that we can use in the param-env when checking +/// auto traits later on. +/// +/// We walk through the constituent types of a type, and when we encounter a projection, +/// normalize that projection. If that normalization was successful, then create a +/// ProjectionPredicate out of the old projection type and its normalized ty. +pub(super) struct StructuralPredicateElaborator<'a, 'tcx> { + stack: Vec>, + seen: FxHashSet>, + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, +} + +impl<'a, 'tcx> StructuralPredicateElaborator<'a, 'tcx> { + pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, tys: impl Iterator>, span: Span) -> Self { + let mut seen = FxHashSet::default(); + let stack = + tys.map(|ty| fcx.resolve_vars_if_possible(ty)).filter(|ty| seen.insert(*ty)).collect(); + StructuralPredicateElaborator { seen, stack, fcx, span } + } + + // Ripped from confirmation code, lol. + fn constituent_types(&self, t: Ty<'tcx>) -> Vec> { + match *t.kind() { + ty::Projection(..) => { + bug!("this type should be handled separately: {:?}", t) + } + + ty::Placeholder(..) | ty::Bound(..) => { + bug!("do not know how to handle this type: {:?}", t) + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("this type shouldn't show up after normalization: {:?}", t) + } + + // These types have no constituents + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char + | ty::Param(_) => vec![], + + // We're treating these types as opaque + ty::Dynamic(..) | ty::GeneratorWitness(..) | ty::Opaque(..) | ty::Foreign(..) => { + vec![] + } + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + vec![element_ty] + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + tys.iter().map(|k| k.expect_ty()).collect() + } + + ty::Closure(_, ref substs) => { + let ty = self.fcx.resolve_vars_if_possible(substs.as_closure().tupled_upvars_ty()); + vec![ty] + } + + ty::Generator(_, ref substs, _) => { + let generator = substs.as_generator(); + let ty = self.fcx.resolve_vars_if_possible(generator.tupled_upvars_ty()); + vec![ty] + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), + + ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.fcx.tcx, substs)).collect(), + } + } +} + +impl<'tcx> Iterator for StructuralPredicateElaborator<'_, 'tcx> { + type Item = ty::GeneratorPredicate<'tcx>; + + fn next(&mut self) -> Option { + while let Some(ty) = self.stack.pop() { + if let ty::Projection(projection_ty) = *ty.kind() { + let mut normalized_ty = self.fcx.normalize_associated_types_in(self.span, ty); + // Try to resolve the projection type + if normalized_ty.is_ty_var() { + self.fcx.select_obligations_where_possible(false, |_| {}); + normalized_ty = self.fcx.resolve_vars_if_possible(normalized_ty); + } + // If we have a normalized type, then stash it + if !normalized_ty.is_ty_var() && normalized_ty != ty { + if self.seen.insert(normalized_ty) { + self.stack.push(normalized_ty); + } + return Some(ty::GeneratorPredicate::Projection(ty::ProjectionPredicate { + projection_ty, + term: ty::Term::Ty(normalized_ty), + })); + } + } else { + let structural: Vec<_> = self + .constituent_types(ty) + .into_iter() + .map(|ty| self.fcx.resolve_vars_if_possible(ty)) + .filter(|ty| self.seen.insert(ty)) + .collect(); + self.stack.extend(structural); + } + } + + None + } +} diff --git a/src/test/ui/async-await/auto-trait/send-2.rs b/src/test/ui/async-await/auto-trait/send-2.rs new file mode 100644 index 0000000000000..39b766e0516bb --- /dev/null +++ b/src/test/ui/async-await/auto-trait/send-2.rs @@ -0,0 +1,46 @@ +// run-pass +// edition:2018 + +#![allow(unused)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Poll, Context}; + +struct Map(Fut, F); + +impl Future for Map where Fut: Future, F: FnOnce(Fut::Output) -> S { + type Output = S; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + todo!() + } +} + +enum MaybeDone { + Maybe(Fut), + Done(Fut::Output), +} + +impl Future for MaybeDone { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + todo!() + } +} + +fn drop_static(s: &'static str) {} + +async fn foo() { + let a = async { "hello" as &'static str}; + let b = Map(a, drop_static); + let c = MaybeDone::Maybe(b); + c.await +} + +fn needs_send(t: T) {} + +fn main() { + needs_send(foo()); +} diff --git a/src/test/ui/async-await/auto-trait/send-3.rs b/src/test/ui/async-await/auto-trait/send-3.rs new file mode 100644 index 0000000000000..0562ce1dc4d29 --- /dev/null +++ b/src/test/ui/async-await/auto-trait/send-3.rs @@ -0,0 +1,23 @@ +// run-pass +// edition:2018 + +#![allow(unused)] + +use std::marker::PhantomData; + +pub struct One(PhantomData); +pub struct Two(PhantomData<(T, U)>); + +unsafe impl Send for Two where U: IsOne {} + +pub trait IsOne {} +impl IsOne for One {} + +fn main() { + fn assert_send(_: impl Send) {} + assert_send(async { + type T = Box; + let _value = Two::>(PhantomData); + async {}.await; + }); +} diff --git a/src/test/ui/async-await/auto-trait/send-4.rs b/src/test/ui/async-await/auto-trait/send-4.rs new file mode 100644 index 0000000000000..7e0a9f4f921fa --- /dev/null +++ b/src/test/ui/async-await/auto-trait/send-4.rs @@ -0,0 +1,57 @@ +// run-pass +// edition:2018 + +#![allow(unused)] + +use core::future::Future; +use core::marker::PhantomData; +use core::pin::Pin; +use core::task::{Context, Poll}; + +async fn f() {} + +pub fn fail<'a>() -> Box + Send + 'a> { + Box::new(async { new(|| async { f().await }).await }) +} + +fn new(_a: A) -> F +where + A: Fn() -> B, +{ + F { _i: PhantomData } +} + +trait Stream { + type Item; +} + +struct T { + _a: PhantomData, + _b: PhantomData, +} + +impl Stream for T +where + A: Fn() -> B, +{ + type Item = B; +} + +struct F +where + A: Fn() -> B, +{ + _i: PhantomData< as Stream>::Item>, +} + +impl Future for F +where + A: Fn() -> B, +{ + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll { + unimplemented!() + } +} + +fn main() {} diff --git a/src/test/ui/async-await/auto-trait/send-5.rs b/src/test/ui/async-await/auto-trait/send-5.rs new file mode 100644 index 0000000000000..b2bb1baf22c51 --- /dev/null +++ b/src/test/ui/async-await/auto-trait/send-5.rs @@ -0,0 +1,45 @@ +// run-pass +// edition:2018 + +#![allow(unused)] + +use std::future::Future; +use std::marker::PhantomData; + +trait Stream { + type Item; +} + +struct Filter { + pending_item: St::Item, +} + +fn filter(_: St) -> Filter { + unimplemented!(); +} + +struct FilterMap { + f: F, + pending: PhantomData, +} + +impl Stream for FilterMap +where + F: FnMut() -> Fut, + Fut: Future, +{ + type Item = (); +} + +pub fn get_foo() -> impl Future + Send { + async { + let _y = &(); + let _x = filter(FilterMap { + f: || async move { *_y }, + pending: PhantomData, + }); + async {}.await; + } +} + +fn main() {} diff --git a/src/test/ui/generator/auto-trait-regions.nll.stderr b/src/test/ui/generator/auto-trait-regions.nll.stderr deleted file mode 100644 index 76970fb787214..0000000000000 --- a/src/test/ui/generator/auto-trait-regions.nll.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/auto-trait-regions.rs:46:24 - | -LL | let a = A(&mut true, &mut true, No); - | ^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -LL | yield; -LL | assert_foo(a); - | - borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error[E0716]: temporary value dropped while borrowed - --> $DIR/auto-trait-regions.rs:46:35 - | -LL | let a = A(&mut true, &mut true, No); - | ^^^^ - temporary value is freed at the end of this statement - | | - | creates a temporary which is freed while still in use -LL | yield; -LL | assert_foo(a); - | - borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:31:5 - | -LL | assert_foo(gen); - | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... - = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` - -error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:50:5 - | -LL | assert_foo(gen); - | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 8f1e4f1b66f48..e8853554a571d 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -2,13 +2,19 @@ #![feature(auto_traits)] #![feature(negative_impls)] +use std::cell::Cell; + auto trait Foo {} struct No; impl !Foo for No {} -struct A<'a, 'b>(&'a mut bool, &'b mut bool, No); +struct A<'a, 'b>(Cell<&'a bool>, Cell<&'b mut bool>, No); + +impl<'a, 'b> Drop for A<'a, 'b> { + fn drop(&mut self) {} +} impl<'a, 'b: 'a> Foo for A<'a, 'b> {} @@ -18,36 +24,37 @@ impl Foo for &'static OnlyFooIfStaticRef {} struct OnlyFooIfRef(No); impl<'a> Foo for &'a OnlyFooIfRef {} -fn assert_foo(f: T) {} +fn assert_foo(_f: T) {} fn main() { - // Make sure 'static is erased for generator interiors so we can't match it in trait selection - let x: &'static _ = &OnlyFooIfStaticRef(No); + let z = OnlyFooIfStaticRef(No); + let x = &z; let gen = || { let x = x; yield; assert_foo(x); }; - assert_foo(gen); + assert_foo(gen); // bad //~^ ERROR implementation of `Foo` is not general enough - //~| ERROR implementation of `Foo` is not general enough + drop(z); // Allow impls which matches any lifetime - let x = &OnlyFooIfRef(No); + let z = OnlyFooIfRef(No); + let x = &z; let gen = || { let x = x; yield; assert_foo(x); }; assert_foo(gen); // ok + drop(z); - // Disallow impls which relates lifetimes in the generator interior - let gen = || { - let a = A(&mut true, &mut true, No); + let gen = static || { + let mut y = true; + let a = A::<'static, '_>(Cell::new(&true), Cell::new(&mut y), No); yield; - assert_foo(a); + drop(a); }; assert_foo(gen); - //~^ ERROR not general enough - //~| ERROR not general enough + //~^ ERROR implementation of `Foo` is not general enough } diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index da3d3249f0e7e..ba718206cee6b 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,32 +1,14 @@ error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:31:5 + --> $DIR/auto-trait-regions.rs:37:5 | -LL | assert_foo(gen); - | ^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... - = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` - -error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:31:5 - | -LL | assert_foo(gen); +LL | assert_foo(gen); // bad | ^^^^^^^^^^ implementation of `Foo` is not general enough | = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:50:5 - | -LL | assert_foo(gen); - | ^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` - -error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:50:5 + --> $DIR/auto-trait-regions.rs:58:5 | LL | assert_foo(gen); | ^^^^^^^^^^ implementation of `Foo` is not general enough @@ -34,5 +16,5 @@ LL | assert_foo(gen); = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr index 72ade5774d749..b4e543ca88b4e 100644 --- a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr +++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr @@ -6,13 +6,5 @@ LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send | | | help: consider adding an explicit lifetime bound...: `C: 'a` -error[E0311]: the parameter type `C` may not live long enough - --> $DIR/issue-92096.rs:20:33 - | -LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send - | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `C: 'a` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-92096.rs b/src/test/ui/generic-associated-types/issue-92096.rs index 066132a5d98bb..b66a1ba3b3c50 100644 --- a/src/test/ui/generic-associated-types/issue-92096.rs +++ b/src/test/ui/generic-associated-types/issue-92096.rs @@ -19,7 +19,6 @@ trait Client { fn call_connect(c: &'_ C) -> impl '_ + Future + Send //[migrate]~^ ERROR the parameter -//[migrate]~| ERROR the parameter where C: Client + Send + Sync, {