Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
do horrors in project.rs
  • Loading branch information
BoxyUwU committed Sep 21, 2022
commit fc629fd17e7dbf6dad9b1ae9d6f08ecb754274ff
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Const, ToPredicate, Ty};
use rustc_middle::ty::{self, Const, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::Fallible;

Expand Down Expand Up @@ -147,7 +147,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
// 'static.
fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}

fn projection_equate(&mut self, projection_ty: ty::ProjectionTy<'tcx>, ty: Ty<'tcx>) {
fn projection_equate(&mut self, _projection_ty: ty::ProjectionTy<'tcx>, _ty: Ty<'tcx>) {
unreachable!()
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
}

fn defer_projection_equality(&self) -> bool {
bug!("`TypeGeneralizer` shouldn't equate projections with other kinds of types");
false
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2780,8 +2780,8 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {

fn projection_equate_obligation(
&mut self,
projection_ty: ty::ProjectionTy<'tcx>,
ty: Ty<'tcx>,
_projection_ty: ty::ProjectionTy<'tcx>,
_ty: Ty<'tcx>,
) {
unreachable!()
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/nll_relate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,6 @@ where
}

fn defer_projection_equality(&self) -> bool {
bug!("`TypeGeneralizer` shouldn't equate projections with other kinds of types");
false
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/test_type_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {

fn projection_equate_obligation(
&mut self,
projection_ty: ty::ProjectionTy<'tcx>,
ty: Ty<'tcx>,
_projection_ty: ty::ProjectionTy<'tcx>,
_ty: Ty<'tcx>,
) {
unreachable!()
}
Expand Down
11 changes: 4 additions & 7 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,13 +561,6 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
(ty::Projection(_), ty::Opaque(_, _)) | (ty::Opaque(_, _), ty::Projection(_)) => {
Err(TypeError::Sorts(expected_found(relation, a, b)))
}
// FIXME(BoxyUwU): This is isnt quite right i.e. if we have
// `<_ as Trait>::Assoc == <T as Other>::Assoc` we ideally wouldnt error because `_`
// might get inferred to something which allows normalization to `<T as Other>::Assoc`.
(&ty::Projection(proj_a), &ty::Projection(proj_b)) => {
let projection_ty = relation.relate(proj_a, proj_b)?;
Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs))
}
(&ty::Projection(proj_a), _)
if proj_a.has_infer_types_or_consts() && relation.defer_projection_equality() =>
{
Expand All @@ -580,6 +573,10 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
relation.projection_equate_obligation(proj_b, a);
Ok(a)
}
(&ty::Projection(proj_a), &ty::Projection(proj_b)) => {
let projection_ty = relation.relate(proj_a, proj_b)?;
Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs))
}

(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
if a_def_id == b_def_id =>
Expand Down
101 changes: 91 additions & 10 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
use rustc_middle::ty::DefIdTree;
Expand Down Expand Up @@ -255,6 +257,7 @@ fn project_and_unify_type<'cx, 'tcx>(
};
debug!(?normalized, ?obligations, "project_and_unify_type result");
let actual = obligation.predicate.term;

// For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs
// This allows users to omit re-mentioning all bounds on an associated type and just use an
// `impl Trait` for the assoc type to add more bounds.
Expand All @@ -267,16 +270,94 @@ fn project_and_unify_type<'cx, 'tcx>(
);
obligations.extend(new);

let defer_projection_equality =
normalized.ty().map_or(true, |normalized| match normalized.kind() {
ty::Projection(proj) => proj != &obligation.predicate.projection_ty,
_ => true,
});
match infcx
.at(&obligation.cause, obligation.param_env)
.defer_projection_equality(defer_projection_equality)
.eq(normalized, actual)
{
if let Some(ty) = normalized.ty() {
if let &ty::Projection(projection) = ty.kind() {
match opt_normalize_projection_type(
selcx,
obligation.param_env,
projection,
obligation.cause.clone(),
obligation.recursion_depth,
&mut obligations,
) {
Ok(Some(_)) => (),
Ok(None) => {
debug!("failed normalization of: {:?}", projection);
return ProjectAndUnifyResult::FailedNormalization;
}
Err(InProgress) => unreachable!(),
}

let actual = actual.ty().unwrap();
let done = match actual.kind() {
&ty::Projection(other) => {
let flipped_projection_eq = InferOk {
obligations: vec![Obligation::new(
obligation.cause.clone(),
obligation.param_env,
ty::Binder::dummy(ty::ProjectionPredicate {
projection_ty: other,
term: ty::Term::from(ty),
})
.to_predicate(selcx.tcx()),
)],
value: (),
};

match opt_normalize_projection_type(
selcx,
obligation.param_env,
other,
obligation.cause.clone(),
obligation.recursion_depth,
&mut obligations,
) {
Ok(Some(normed_other)) => match normed_other.ty().unwrap().kind() {
&ty::Projection(normed_other) => {
match opt_normalize_projection_type(
selcx,
obligation.param_env,
normed_other,
obligation.cause.clone(),
obligation.recursion_depth,
&mut obligations,
) {
Ok(Some(_)) => infcx
.at(&obligation.cause, obligation.param_env)
.trace(ty, actual)
.eq(projection, normed_other),
Ok(None) => Ok(flipped_projection_eq),
Err(InProgress) => unreachable!(),
}
}
ty::Infer(_) => {
infcx.at(&obligation.cause, obligation.param_env).eq(ty, actual)
}
_ => Err(TypeError::Sorts(ExpectedFound::new(false, ty, actual))),
},
Ok(None) => Ok(flipped_projection_eq),
Err(InProgress) => return ProjectAndUnifyResult::Recursive,
}
}
ty::Infer(_) => infcx.at(&obligation.cause, obligation.param_env).eq(ty, actual),
_ => Err(TypeError::Sorts(ExpectedFound::new(false, ty, actual))),
};
return match done {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations)
}
Err(err) => {
debug!("equating types encountered error {:?}", err);
ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes {
err,
})
}
};
}
}

match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations)
Expand Down