make ascribe_user_type a TypeOp

Projection types in user annotations may contain inference variables.
This makes the normalization depend on the unification with the actual
type and thus requires a separate TypeOp to track the obligations.
Otherwise simply calling `TypeChecker::normalize` would ICE with
"unexpected ambiguity"
This commit is contained in:
Ali MJ Al-Nasrawy 2022-11-16 13:11:44 +03:00
parent 37b40e471a
commit c6a17bf8bc
15 changed files with 350 additions and 186 deletions

View file

@ -4,8 +4,8 @@ use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate};
use rustc_middle::ty::{UserSelfTy, UserSubsts};
use rustc_middle::ty::{ParamEnvAnd, Predicate};
use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
@ -50,13 +50,46 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
span: Option<Span>,
) -> Result<(), NoSolution> {
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
debug!(
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
mir_ty, def_id, user_substs
);
let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
let span = span.unwrap_or(DUMMY_SP);
match user_ty {
UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
UserType::TypeOf(def_id, user_substs) => {
relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
}
};
Ok(())
}
#[instrument(level = "debug", skip(ocx, param_env, span))]
fn relate_mir_and_user_ty<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
mir_ty: Ty<'tcx>,
user_ty: Ty<'tcx>,
) -> Result<(), NoSolution> {
let cause = ObligationCause::dummy_with_span(span);
let user_ty = ocx.normalize(&cause, param_env, user_ty);
ocx.eq(&cause, param_env, mir_ty, user_ty)?;
// FIXME(#104764): We should check well-formedness before normalization.
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
Ok(())
}
#[instrument(level = "debug", skip(ocx, param_env, span))]
fn relate_mir_and_user_substs<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
mir_ty: Ty<'tcx>,
def_id: hir::def_id::DefId,
user_substs: UserSubsts<'tcx>,
) -> Result<(), NoSolution> {
let UserSubsts { user_self_ty, substs } = user_substs;
let tcx = ocx.infcx.tcx;
let cause = ObligationCause::dummy_with_span(span);
@ -97,8 +130,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
let predicate: Predicate<'tcx> =
ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())).to_predicate(tcx);
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
}
@ -113,8 +145,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
// them? This would only be relevant if some input
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
let predicate: Predicate<'tcx> =
ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx);
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
Ok(())
}