diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index e9d763afa68a0..a56dc908013a1 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -8,6 +8,7 @@ use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_target::spec::abi; use std::iter; @@ -134,7 +135,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( } #[inline] -pub fn relate_args<'tcx, R: TypeRelation<'tcx>>( +pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a_arg: GenericArgsRef<'tcx>, b_arg: GenericArgsRef<'tcx>, @@ -273,7 +274,20 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { if a.def_id != b.def_id { Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relation.relate(a.args, b.args)?; + let args = match relation.tcx().def_kind(a.def_id) { + DefKind::OpaqueTy => relate_args_with_variances( + relation, + a.def_id, + relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => { + relate_args_invariantly(relation, a.args, b.args)? + } + def => bug!("unknown alias DefKind: {def:?}"), + }; Ok(relation.tcx().mk_alias_ty(a.def_id, args)) } } @@ -315,7 +329,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) } } @@ -331,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) } } @@ -449,7 +463,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All Generator types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(self, a_args, b_args)?; Ok(Ty::new_generator(tcx, a_id, args, movability)) } @@ -459,7 +473,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All GeneratorWitness types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(self, a_args, b_args)?; Ok(Ty::new_generator_witness(tcx, a_id, args)) } @@ -467,7 +481,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All Closure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(self, a_args, b_args)?; Ok(Ty::new_closure(tcx, a_id, &args)) } @@ -536,24 +550,6 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_fn_ptr(tcx, fty)) } - // The args of opaque types may not all be invariant, so we have - // to treat them separately from other aliases. - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, args: a_args, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, args: b_args, .. }), - ) if a_def_id == b_def_id => { - let opt_variances = tcx.variances_of(a_def_id); - let args = relate_args_with_variances( - relation, - a_def_id, - opt_variances, - a_args, - b_args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?; - Ok(Ty::new_opaque(tcx, a_def_id, args)) - } - // Alias tend to mostly already be handled downstream due to normalization. (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { let alias_ty = relation.relate(a_data, b_data)?; @@ -709,7 +705,7 @@ impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> { a: ty::ClosureArgs<'tcx>, b: ty::ClosureArgs<'tcx>, ) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::ClosureArgs { args }) } } @@ -720,7 +716,7 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorArgs<'tcx> { a: ty::GeneratorArgs<'tcx>, b: ty::GeneratorArgs<'tcx>, ) -> RelateResult<'tcx, ty::GeneratorArgs<'tcx>> { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::GeneratorArgs { args }) } } @@ -731,7 +727,7 @@ impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { a: GenericArgsRef<'tcx>, b: GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - relate_args(relation, a, b) + relate_args_invariantly(relation, a, b) } } @@ -835,19 +831,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { - fn relate>( - relation: &mut R, - a: ty::ProjectionPredicate<'tcx>, - b: ty::ProjectionPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { - Ok(ty::ProjectionPredicate { - projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, - term: relation.relate(a.term, b.term)?, - }) - } -} - /////////////////////////////////////////////////////////////////////////// // Error handling diff --git a/tests/ui/impl-trait/in-trait/opaque-variances.rs b/tests/ui/impl-trait/in-trait/opaque-variances.rs new file mode 100644 index 0000000000000..60bfab0deb582 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/opaque-variances.rs @@ -0,0 +1,14 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +fn foo<'a: 'a>(x: &'a Vec) -> impl Sized { + () +} + +fn main() { + // in NLL, we want to make sure that the `'a` subst of `foo` does not get + // related between `x` and the RHS of the assignment. That would require + // that the temp is live for the lifetime of the variable `x`, which of + // course is not necessary since `'a` is not captured by the RPIT. + let x = foo(&Vec::new()); +}