blob: aca16950223c5d1d48c985967d7279f5db97cfea [file] [log] [blame]
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
use crate::traits::ObligationCtxt;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_infer::traits::Obligation;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserArgs, UserSelfTy, UserType};
pub use rustc_middle::traits::query::type_op::AscribeUserType;
use rustc_span::{Span, DUMMY_SP};
impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
type QueryResponse = ();
fn try_fast_path(
_tcx: TyCtxt<'tcx>,
_key: &ParamEnvAnd<'tcx, Self>,
) -> Option<Self::QueryResponse> {
None
}
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
tcx.type_op_ascribe_user_type(canonicalized)
}
fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
type_op_ascribe_user_type_with_span(ocx, key, None)
}
}
/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
/// this query can be re-run to better track the span of the obligation cause, and improve the error
/// message. Do not call directly unless you're in that very specific context.
pub fn type_op_ascribe_user_type_with_span<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
span: Option<Span>,
) -> Result<(), NoSolution> {
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_args) => {
relate_mir_and_user_args(ocx, param_env, span, mir_ty, def_id, user_args)?
}
};
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);
ocx.register_obligation(Obligation::new(
ocx.infcx.tcx,
cause.clone(),
param_env,
ty::ClauseKind::WellFormed(user_ty.into()),
));
let user_ty = ocx.normalize(&cause, param_env, user_ty);
ocx.eq(&cause, param_env, mir_ty, user_ty)?;
Ok(())
}
#[instrument(level = "debug", skip(ocx, param_env, span))]
fn relate_mir_and_user_args<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
mir_ty: Ty<'tcx>,
def_id: DefId,
user_args: UserArgs<'tcx>,
) -> Result<(), NoSolution> {
let UserArgs { user_self_ty, args } = user_args;
let tcx = ocx.infcx.tcx;
let cause = ObligationCause::dummy_with_span(span);
let ty = tcx.type_of(def_id).instantiate(tcx, args);
let ty = ocx.normalize(&cause, param_env, ty);
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
ocx.eq(&cause, param_env, mir_ty, ty)?;
// Prove the predicates coming along with `def_id`.
//
// Also, normalize the `instantiated_predicates`
// because otherwise we wind up with duplicate "type
// outlives" error messages.
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
debug!(?instantiated_predicates);
for (instantiated_predicate, predicate_span) in instantiated_predicates {
let span = if span == DUMMY_SP { predicate_span } else { span };
let cause = ObligationCause::new(
span,
CRATE_DEF_ID,
ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
);
let instantiated_predicate =
ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
}
// Now prove the well-formedness of `def_id` with `args`.
// Note for some items, proving the WF of `ty` is not sufficient because the
// well-formedness of an item may depend on the WF of gneneric args not present in the
// item's type. Currently this is true for associated consts, e.g.:
// ```rust
// impl<T> MyTy<T> {
// const CONST: () = { /* arbitrary code that depends on T being WF */ };
// }
// ```
for arg in args {
ocx.register_obligation(Obligation::new(
tcx,
cause.clone(),
param_env,
ty::ClauseKind::WellFormed(arg),
));
}
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
ocx.register_obligation(Obligation::new(
tcx,
cause.clone(),
param_env,
ty::ClauseKind::WellFormed(self_ty.into()),
));
let self_ty = ocx.normalize(&cause, param_env, self_ty);
let impl_self_ty = tcx.type_of(impl_def_id).instantiate(tcx, args);
let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
}
Ok(())
}