diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index b3955b8f864e..23445781eb2f 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -11,6 +11,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::Fallible; use hir::def_id::DefId; +use mir::ProjectionKind; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::UserSubsts; @@ -20,6 +21,7 @@ pub struct AscribeUserType<'tcx> { pub variance: ty::Variance, pub def_id: DefId, pub user_substs: UserSubsts<'tcx>, + pub projs: &'tcx ty::List>, } impl<'tcx> AscribeUserType<'tcx> { @@ -28,8 +30,9 @@ impl<'tcx> AscribeUserType<'tcx> { variance: ty::Variance, def_id: DefId, user_substs: UserSubsts<'tcx>, + projs: &'tcx ty::List>, ) -> Self { - AscribeUserType { mir_ty, variance, def_id, user_substs } + AscribeUserType { mir_ty, variance, def_id, user_substs, projs } } } @@ -59,19 +62,19 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx> BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> { - mir_ty, variance, def_id, user_substs + mir_ty, variance, def_id, user_substs, projs } } BraceStructLiftImpl! { impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> { type Lifted = AscribeUserType<'tcx>; - mir_ty, variance, def_id, user_substs + mir_ty, variance, def_id, user_substs, projs } } impl_stable_hash_for! { struct AscribeUserType<'tcx> { - mir_ty, variance, def_id, user_substs + mir_ty, variance, def_id, user_substs, projs } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 4d1eea4724be..953fe0c9521e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1013,12 +1013,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - // FIXME: add user_ty.projs support to `AscribeUserType`. + let projs = self.infcx.tcx.intern_projs(&user_ty.projs); self.fully_perform_op( locations, category, self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - a, v, def_id, user_substs, + a, v, def_id, user_substs, projs, )), )?; } diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index cf274a9c8510..2ed02a4cdab1 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -12,6 +12,8 @@ use rustc::infer::at::ToTrace; use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::infer::InferCtxt; use rustc::hir::def_id::DefId; +use rustc::mir::ProjectionKind; +use rustc::mir::tcx::PlaceTy; use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; @@ -58,14 +60,15 @@ fn type_op_ascribe_user_type<'tcx>( variance, def_id, user_substs, + projs, }, ) = key.into_parts(); debug!( "type_op_ascribe_user_type(\ - mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\ + mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}, projs={:?}\ )", - mir_ty, variance, def_id, user_substs, + mir_ty, variance, def_id, user_substs, projs, ); let mut cx = AscribeUserTypeCx { @@ -73,7 +76,7 @@ fn type_op_ascribe_user_type<'tcx>( param_env, fulfill_cx, }; - cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?; + cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?; Ok(()) }) @@ -134,17 +137,30 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { variance: Variance, def_id: DefId, user_substs: UserSubsts<'tcx>, + projs: &[ProjectionKind<'tcx>], ) -> Result<(), NoSolution> { let UserSubsts { substs, user_self_ty, } = user_substs; - let ty = self.tcx().type_of(def_id); + let tcx = self.tcx(); + + let ty = tcx.type_of(def_id); let ty = self.subst(ty, substs); debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); let ty = self.normalize(ty); + let mut projected_ty = PlaceTy::from_ty(ty); + for proj in projs { + projected_ty = projected_ty.projection_ty_core( + tcx, proj, |this, field, &()| { + let ty = this.field_ty(tcx, field); + self.normalize(ty) + }); + } + let ty = projected_ty.to_ty(tcx); + self.relate(mir_ty, variance, ty)?; if let Some(UserSelfTy {