mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Introduce TypeErrCtxt
TypeErrCtxt optionally has a TypeckResults so that InferCtxt doesn't need to.
This commit is contained in:
parent
5854680388
commit
4a68373217
@ -56,7 +56,7 @@ impl<'tcx> UniverseInfo<'tcx> {
|
||||
) {
|
||||
match self.0 {
|
||||
UniverseInfoInner::RelateTys { expected, found } => {
|
||||
let err = mbcx.infcx.report_mismatched_types(
|
||||
let err = mbcx.infcx.err_ctxt().report_mismatched_types(
|
||||
&cause,
|
||||
expected,
|
||||
found,
|
||||
@ -449,42 +449,38 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
||||
})?;
|
||||
|
||||
debug!(?sub_region, "cause = {:#?}", cause);
|
||||
let nice_error = match (error_region, *sub_region) {
|
||||
(Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
region_var_origin(vid),
|
||||
cause.clone(),
|
||||
error_region,
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
vec![],
|
||||
),
|
||||
),
|
||||
(Some(error_region), _) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
|
||||
let error = match (error_region, *sub_region) {
|
||||
(Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
region_var_origin(vid),
|
||||
cause.clone(),
|
||||
error_region,
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
vec![],
|
||||
),
|
||||
(Some(error_region), _) => {
|
||||
RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
|
||||
}
|
||||
// Note universe here is wrong...
|
||||
(None, ty::ReVar(vid)) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::UpperBoundUniverseConflict(
|
||||
vid,
|
||||
region_var_origin(vid),
|
||||
universe_of_region(vid),
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
),
|
||||
),
|
||||
(None, _) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
|
||||
(None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
|
||||
vid,
|
||||
region_var_origin(vid),
|
||||
universe_of_region(vid),
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
),
|
||||
(None, _) => {
|
||||
RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
|
||||
}
|
||||
};
|
||||
nice_error.try_report_from_nll().or_else(|| {
|
||||
NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
|
||||
if let SubregionOrigin::Subtype(trace) = cause {
|
||||
Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch))
|
||||
Some(
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(lower_bound_region) = lower_bound_region {
|
||||
let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
|
||||
let origin = RelateParamBound(type_test_span, generic_ty, None);
|
||||
self.buffer_error(self.infcx.construct_generic_bound_failure(
|
||||
self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure(
|
||||
self.body.source.def_id().expect_local(),
|
||||
type_test_span,
|
||||
Some(origin),
|
||||
@ -365,7 +365,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
// Check if we can use one of the "nice region errors".
|
||||
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
|
||||
let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
|
||||
let infer_err = self.infcx.err_ctxt();
|
||||
let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f);
|
||||
if let Some(diag) = nice.try_report_from_nll() {
|
||||
self.buffer_error(diag);
|
||||
return;
|
||||
|
@ -13,7 +13,7 @@ use rustc_middle::ty::{
|
||||
self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::TraitEngineExt as _;
|
||||
|
||||
use crate::session_diagnostics::ConstNotUsedTraitAlias;
|
||||
@ -299,6 +299,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
Err(err) => {
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
|
||||
@ -325,7 +326,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
if errors.is_empty() {
|
||||
definition_ty
|
||||
} else {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
self.tcx.ty_error()
|
||||
}
|
||||
},
|
||||
|
@ -14,7 +14,7 @@ use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
|
||||
use rustc_mir_dataflow::{self, Analysis};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt,
|
||||
};
|
||||
@ -775,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
let errors = fulfill_cx.select_all_or_error(&infcx);
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -837,7 +837,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
// as we are going to error again anyways.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
if let Err(e) = implsrc {
|
||||
infcx.report_selection_error(
|
||||
infcx.err_ctxt().report_selection_error(
|
||||
obligation.clone(),
|
||||
&obligation,
|
||||
&e,
|
||||
|
@ -29,7 +29,7 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
use rustc_ty_utils::representability::{self, Representability};
|
||||
|
||||
@ -760,7 +760,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
}
|
||||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
|
@ -61,7 +61,7 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, BytePos, DesugaringKind, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
@ -702,7 +702,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
|
||||
// Object safety violations or miscellaneous.
|
||||
Err(err) => {
|
||||
self.report_selection_error(obligation.clone(), &obligation, &err, false);
|
||||
self.err_ctxt().report_selection_error(
|
||||
obligation.clone(),
|
||||
&obligation,
|
||||
&err,
|
||||
false,
|
||||
);
|
||||
// Treat this like an obligation and follow through
|
||||
// with the unsizing - the lack of a coercion should
|
||||
// be silent, as it causes a type mismatch later.
|
||||
@ -1549,7 +1554,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
err = fcx.report_mismatched_types(
|
||||
err = fcx.err_ctxt().report_mismatched_types(
|
||||
cause,
|
||||
expected,
|
||||
found,
|
||||
@ -1629,7 +1634,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
expression: Option<&'tcx hir::Expr<'tcx>>,
|
||||
blk_id: Option<hir::HirId>,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
|
||||
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
|
||||
|
||||
let mut pointing_at_return_type = false;
|
||||
let mut fn_output = None;
|
||||
|
@ -19,7 +19,7 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
|
||||
@ -395,7 +395,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||
_ => {}
|
||||
}
|
||||
|
||||
infcx.note_type_err(
|
||||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
|
||||
@ -415,7 +415,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
let reported = infcx.report_fulfillment_errors(&errors, None, false);
|
||||
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
@ -508,7 +508,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
|
||||
trait_m.name
|
||||
);
|
||||
let hir = tcx.hir();
|
||||
infcx.note_type_err(
|
||||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
hir.get_if_local(impl_m.def_id)
|
||||
@ -530,7 +530,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
|
||||
// RPITs.
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
let reported = infcx.report_fulfillment_errors(&errors, None, false);
|
||||
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
@ -1382,7 +1382,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
|
||||
}
|
||||
});
|
||||
|
||||
infcx.note_type_err(
|
||||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
trait_c_span.map(|span| (span, "type in trait".to_owned())),
|
||||
@ -1401,7 +1401,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
return Err(infcx.report_fulfillment_errors(&errors, None, false));
|
||||
return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
|
||||
}
|
||||
|
||||
// FIXME return `ErrorReported` if region obligations error?
|
||||
@ -1522,7 +1522,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
let reported = infcx.report_fulfillment_errors(&errors, None, false);
|
||||
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
@ -1751,7 +1751,7 @@ pub fn check_type_bounds<'tcx>(
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
let reported = infcx.report_fulfillment_errors(&errors, None, false);
|
||||
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
@ -1769,6 +1769,7 @@ pub fn check_type_bounds<'tcx>(
|
||||
let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
for (key, value) in constraints {
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(
|
||||
value.hidden_type.span,
|
||||
|
@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.register_predicates(obligations);
|
||||
None
|
||||
}
|
||||
Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
|
||||
Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.register_predicates(obligations);
|
||||
None
|
||||
}
|
||||
Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
|
||||
Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let expr = expr.peel_drop_temps();
|
||||
let cause = self.misc(expr.span);
|
||||
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
|
||||
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
|
||||
let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
|
||||
|
||||
let is_insufficiently_polymorphic =
|
||||
matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
|
||||
|
@ -1649,13 +1649,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Err(_) => {
|
||||
// This should never happen, since we're just subtyping the
|
||||
// remaining_fields, but it's fine to emit this, I guess.
|
||||
self.report_mismatched_types(
|
||||
&cause,
|
||||
target_ty,
|
||||
fru_ty,
|
||||
FieldMisMatch(variant.name, ident.name),
|
||||
)
|
||||
.emit();
|
||||
self.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&cause,
|
||||
target_ty,
|
||||
fru_ty,
|
||||
FieldMisMatch(variant.name, ident.name),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1942,7 +1943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.set_tainted_by_errors();
|
||||
return;
|
||||
}
|
||||
let mut err = self.type_error_struct_with_diag(
|
||||
let mut err = self.err_ctxt().type_error_struct_with_diag(
|
||||
field.ident.span,
|
||||
|actual| match ty.kind() {
|
||||
ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!(
|
||||
|
@ -32,7 +32,7 @@ use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
|
||||
};
|
||||
@ -615,7 +615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
|
||||
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
|
||||
self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -629,7 +629,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if !result.is_empty() {
|
||||
mutate_fulfillment_errors(&mut result);
|
||||
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
|
||||
self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
|
||||
self.err_ctxt().report_fulfillment_errors(
|
||||
&result,
|
||||
self.inh.body_id,
|
||||
fallback_has_occurred,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1466,7 +1470,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
} else {
|
||||
if !self.is_tainted_by_errors() {
|
||||
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
|
||||
self.err_ctxt()
|
||||
.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
|
||||
.emit();
|
||||
}
|
||||
let err = self.tcx.ty_error();
|
||||
|
@ -650,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if tys.len() == 1 {
|
||||
// A tuple wrap suggestion actually occurs within,
|
||||
// so don't do anything special here.
|
||||
err = self.report_and_explain_type_error(
|
||||
err = self.err_ctxt().report_and_explain_type_error(
|
||||
TypeTrace::types(
|
||||
&self.misc(*lo),
|
||||
true,
|
||||
@ -742,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let cause = &self.misc(provided_span);
|
||||
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
|
||||
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
|
||||
self.report_and_explain_type_error(trace, *e).emit();
|
||||
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
||||
return true;
|
||||
}
|
||||
false
|
||||
@ -766,7 +766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
|
||||
let cause = &self.misc(provided_arg_span);
|
||||
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
|
||||
let mut err = self.report_and_explain_type_error(trace, *err);
|
||||
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
|
||||
self.emit_coerce_suggestions(
|
||||
&mut err,
|
||||
&provided_args[*provided_idx],
|
||||
@ -840,7 +840,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let cause = &self.misc(provided_span);
|
||||
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
|
||||
if let Some(e) = error {
|
||||
self.note_type_err(
|
||||
self.err_ctxt().note_type_err(
|
||||
&mut err,
|
||||
&trace.cause,
|
||||
None,
|
||||
@ -1474,7 +1474,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&mut |err| {
|
||||
if let Some(expected_ty) = expected.only_has_type(self) {
|
||||
if !self.consider_removing_semicolon(blk, expected_ty, err) {
|
||||
self.consider_returning_binding(blk, expected_ty, err);
|
||||
self.err_ctxt().consider_returning_binding(
|
||||
blk,
|
||||
expected_ty,
|
||||
err,
|
||||
);
|
||||
}
|
||||
if expected_ty == self.tcx.types.bool {
|
||||
// If this is caused by a missing `let` in a `while let`,
|
||||
|
@ -13,6 +13,7 @@ use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
@ -168,6 +169,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self.tcx.sess
|
||||
}
|
||||
|
||||
/// Creates an `TypeErrCtxt` with a reference to the in-progress
|
||||
/// `TypeckResults` which is used for diagnostics.
|
||||
/// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
|
||||
///
|
||||
/// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
|
||||
pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
|
||||
TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
|
||||
}
|
||||
|
||||
pub fn errors_reported_since_creation(&self) -> bool {
|
||||
self.tcx.sess.err_count() > self.err_count_on_creation
|
||||
}
|
||||
|
@ -1037,7 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// We'll later suggest `.as_ref` when noting the type error,
|
||||
// so skip if we will suggest that instead.
|
||||
if self.should_suggest_as_ref(expected_ty, expr_ty).is_some() {
|
||||
if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1187,7 +1187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
|
||||
if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) {
|
||||
if let StatementAsExpression::NeedsBoxing = boxed {
|
||||
err.span_suggestion_verbose(
|
||||
span_semi,
|
||||
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// A temporary returned by `Inherited::build(...)`. This is necessary
|
||||
/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
|
||||
/// for multiple `InferCtxt` to share the same `typeck_results`
|
||||
/// without using `Rc` or something similar.
|
||||
pub struct InheritedBuilder<'tcx> {
|
||||
infcx: infer::InferCtxtBuilder<'tcx>,
|
||||
|
@ -22,7 +22,7 @@ use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
|
||||
use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
|
||||
@ -855,8 +855,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Avoid crashing.
|
||||
return (None, None);
|
||||
}
|
||||
let OnUnimplementedNote { message, label, .. } =
|
||||
self.on_unimplemented_note(trait_ref, &obligation);
|
||||
let OnUnimplementedNote { message, label, .. } = self
|
||||
.err_ctxt()
|
||||
.on_unimplemented_note(trait_ref, &obligation);
|
||||
(message, label)
|
||||
})
|
||||
.unwrap_or((None, None))
|
||||
|
@ -18,7 +18,7 @@ use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
|
||||
@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.suggest_restricting_param_bound(
|
||||
self.err_ctxt().suggest_restricting_param_bound(
|
||||
&mut err,
|
||||
trait_pred,
|
||||
output_associated_item,
|
||||
@ -662,7 +662,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
error.obligation.predicate.to_opt_poly_trait_pred()
|
||||
});
|
||||
for pred in predicates {
|
||||
self.suggest_restricting_param_bound(
|
||||
self.err_ctxt().suggest_restricting_param_bound(
|
||||
&mut err,
|
||||
pred,
|
||||
None,
|
||||
|
@ -22,7 +22,7 @@ use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_trait_selection::autoderef::Autoderef;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
@ -104,7 +104,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
|
||||
f(&mut wfcx);
|
||||
let errors = wfcx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1677,7 +1677,7 @@ fn receiver_is_valid<'tcx>(
|
||||
// `self: Self` is always valid.
|
||||
if can_eq_self(receiver_ty) {
|
||||
if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
|
||||
infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
|
||||
infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1709,7 +1709,10 @@ fn receiver_is_valid<'tcx>(
|
||||
if let Err(err) =
|
||||
wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
|
||||
{
|
||||
infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit();
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(&cause, self_ty, potential_self_ty, err)
|
||||
.emit();
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -720,6 +720,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
||||
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) {
|
||||
if !self.tcx.sess.has_errors().is_some() {
|
||||
self.infcx
|
||||
.err_ctxt()
|
||||
.emit_inference_failure_err(
|
||||
Some(self.body.id()),
|
||||
self.span.to_span(self.tcx),
|
||||
|
@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
|
||||
use rustc_trait_selection::traits::predicate_for_trait_def;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
@ -324,7 +324,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
|
||||
}),
|
||||
);
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions.
|
||||
@ -377,6 +377,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
||||
mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
|
||||
if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&cause,
|
||||
mk_ptr(mt_b.ty),
|
||||
@ -576,7 +577,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
||||
);
|
||||
let errors = traits::fully_solve_obligation(&infcx, predicate);
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions.
|
||||
|
@ -77,7 +77,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
|
||||
|
||||
@ -153,7 +153,7 @@ fn get_impl_substs<'tcx>(
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
ocx.infcx.report_fulfillment_errors(&errors, None, false);
|
||||
ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ use rustc_middle::util;
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_span::{symbol::sym, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
use std::iter;
|
||||
@ -146,7 +146,7 @@ fn require_same_types<'tcx>(
|
||||
let errors = match infcx.at(cause, param_env).eq(expected, actual) {
|
||||
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
|
||||
Err(err) => {
|
||||
infcx.report_mismatched_types(cause, expected, actual, err).emit();
|
||||
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@ -154,7 +154,7 @@ fn require_same_types<'tcx>(
|
||||
match &errors[..] {
|
||||
[] => true,
|
||||
errors => {
|
||||
infcx.report_fulfillment_errors(errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -318,7 +318,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
||||
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
error = true;
|
||||
}
|
||||
});
|
||||
|
@ -75,7 +75,7 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::ops::ControlFlow;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
use std::{cmp, fmt, iter};
|
||||
|
||||
mod note;
|
||||
@ -85,6 +85,31 @@ pub use need_type_info::TypeAnnotationNeeded;
|
||||
|
||||
pub mod nice_region_error;
|
||||
|
||||
/// A helper for building type related errors. The `typeck_results`
|
||||
/// field is only populated during an in-progress typeck.
|
||||
/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`.
|
||||
pub struct TypeErrCtxt<'a, 'tcx> {
|
||||
pub infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
|
||||
}
|
||||
|
||||
impl TypeErrCtxt<'_, '_> {
|
||||
/// This is just to avoid a potential footgun of accidentally
|
||||
/// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
|
||||
#[deprecated(note = "you already have a `TypeErrCtxt`")]
|
||||
#[allow(unused)]
|
||||
pub fn err_ctxt(&self) -> ! {
|
||||
bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Deref for TypeErrCtxt<'a, 'tcx> {
|
||||
type Target = InferCtxt<'a, 'tcx>;
|
||||
fn deref(&self) -> &InferCtxt<'a, 'tcx> {
|
||||
&self.infcx
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn note_and_explain_region<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
@ -304,7 +329,39 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
||||
err
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
impl<'tcx> InferCtxt<'_, 'tcx> {
|
||||
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
|
||||
if let ty::Opaque(def_id, substs) = ty.kind() {
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
|
||||
let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
|
||||
|
||||
for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
|
||||
let predicate = predicate.subst(self.tcx, substs);
|
||||
let output = predicate
|
||||
.kind()
|
||||
.map_bound(|kind| match kind {
|
||||
ty::PredicateKind::Projection(projection_predicate)
|
||||
if projection_predicate.projection_ty.item_def_id == item_def_id =>
|
||||
{
|
||||
projection_predicate.term.ty()
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.transpose();
|
||||
if output.is_some() {
|
||||
// We don't account for multiple `Future::Output = Ty` constraints.
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
pub fn report_region_errors(
|
||||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
@ -578,13 +635,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
{
|
||||
// don't show type `_`
|
||||
if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
||||
&& let ty::Adt(def, substs) = ty.kind()
|
||||
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
||||
&& let ty::Adt(def, substs) = ty.kind()
|
||||
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
||||
{
|
||||
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
|
||||
} else {
|
||||
err.span_label(span, format!("this expression has type `{}`", ty));
|
||||
}
|
||||
err.span_label(span, format!("this expression has type `{}`", ty));
|
||||
}
|
||||
}
|
||||
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
|
||||
&& ty.is_box() && ty.boxed_ty() == found
|
||||
@ -620,8 +677,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
||||
self.in_progress_typeck_results.and_then(|typeck_results| {
|
||||
typeck_results.borrow().expr_ty_opt(arg_expr)
|
||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
||||
typeck_results.expr_ty_opt(arg_expr)
|
||||
})
|
||||
} else {
|
||||
bug!("try desugaring w/out call expr as scrutinee");
|
||||
@ -727,10 +784,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
_ => {
|
||||
if let ObligationCauseCode::BindingObligation(_, span)
|
||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
|
||||
= cause.code().peel_derives()
|
||||
= cause.code().peel_derives()
|
||||
&& let TypeError::RegionsPlaceholderMismatch = terr
|
||||
{
|
||||
err.span_note(*span, "the lifetime requirement is introduced here");
|
||||
err.span_note( * span,
|
||||
"the lifetime requirement is introduced here");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1954,36 +2012,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
|
||||
if let ty::Opaque(def_id, substs) = ty.kind() {
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
|
||||
let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
|
||||
|
||||
for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
|
||||
let predicate = predicate.subst(self.tcx, substs);
|
||||
let output = predicate
|
||||
.kind()
|
||||
.map_bound(|kind| match kind {
|
||||
ty::PredicateKind::Projection(projection_predicate)
|
||||
if projection_predicate.projection_ty.item_def_id == item_def_id =>
|
||||
{
|
||||
projection_predicate.term.ty()
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.transpose();
|
||||
if output.is_some() {
|
||||
// We don't account for multiple `Future::Output = Ty` constraints.
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// A possible error is to forget to add `.await` when using futures:
|
||||
///
|
||||
/// ```compile_fail,E0308
|
||||
@ -2431,7 +2459,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
origin: Option<SubregionOrigin<'tcx>>,
|
||||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
// Attempt to obtain the span of the parameter so we can
|
||||
// suggest adding an explicit lifetime bound to it.
|
||||
let generics = self.tcx.generics_of(generic_param_scope);
|
||||
@ -3111,7 +3139,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
|
||||
_ => rustc_span::DUMMY_SP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
/// Be helpful when the user wrote `{... expr; }` and taking the `;` off
|
||||
/// is enough to fix the error.
|
||||
pub fn could_remove_semicolon(
|
||||
@ -3128,7 +3158,7 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
|
||||
let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
|
||||
return None;
|
||||
};
|
||||
let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?;
|
||||
let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
|
||||
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
|
||||
_ if last_expr_ty.references_error() => return None,
|
||||
_ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
|
||||
@ -3211,8 +3241,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
|
||||
let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
|
||||
if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
|
||||
&& let Some(pat_ty) = self
|
||||
.in_progress_typeck_results
|
||||
.and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id))
|
||||
.typeck_results
|
||||
.as_ref()
|
||||
.and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
|
||||
{
|
||||
let pat_ty = self.resolve_vars_if_possible(pat_ty);
|
||||
if self.same_type_modulo_infer(pat_ty, expected_ty)
|
||||
|
@ -2,6 +2,7 @@ use crate::errors::{
|
||||
AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
|
||||
SourceKindMultiSuggestion, SourceKindSubdiag,
|
||||
};
|
||||
use crate::infer::error_reporting::TypeErrCtxt;
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_errors::IntoDiagnostic;
|
||||
@ -317,7 +318,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used as a fallback in [InferCtxt::emit_inference_failure_err]
|
||||
/// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err]
|
||||
/// in case we weren't able to get a better error.
|
||||
fn bad_inference_failure_err(
|
||||
&self,
|
||||
@ -364,7 +365,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
pub fn emit_inference_failure_err(
|
||||
&self,
|
||||
body_id: Option<hir::BodyId>,
|
||||
@ -376,14 +379,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let arg = self.resolve_vars_if_possible(arg);
|
||||
let arg_data = self.extract_inference_diagnostics_data(arg, None);
|
||||
|
||||
let Some(typeck_results) = self.in_progress_typeck_results else {
|
||||
let Some(typeck_results) = &self.typeck_results else {
|
||||
// If we don't have any typeck results we're outside
|
||||
// of a body, so we won't be able to get better info
|
||||
// here.
|
||||
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
|
||||
};
|
||||
let typeck_results = typeck_results.borrow();
|
||||
let typeck_results = &typeck_results;
|
||||
|
||||
let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
|
||||
if let Some(body_id) = body_id {
|
||||
@ -563,7 +564,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'_, 'tcx> {
|
||||
pub fn need_type_info_err_in_generator(
|
||||
&self,
|
||||
kind: hir::GeneratorKind,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::infer::error_reporting::TypeErrCtxt;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::source_map::Span;
|
||||
@ -19,34 +19,34 @@ pub use find_anon_type::find_anon_type;
|
||||
pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor};
|
||||
pub use util::find_param_with_region;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
|
||||
impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> {
|
||||
pub fn try_report_nice_region_error(&'cx self, error: &RegionResolutionError<'tcx>) -> bool {
|
||||
NiceRegionError::new(self, error.clone()).try_report().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NiceRegionError<'cx, 'tcx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
cx: &'cx TypeErrCtxt<'cx, 'tcx>,
|
||||
error: Option<RegionResolutionError<'tcx>>,
|
||||
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
|
||||
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
|
||||
Self { infcx, error: Some(error), regions: None }
|
||||
pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
|
||||
Self { cx, error: Some(error), regions: None }
|
||||
}
|
||||
|
||||
pub fn new_from_span(
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
cx: &'cx TypeErrCtxt<'cx, 'tcx>,
|
||||
span: Span,
|
||||
sub: ty::Region<'tcx>,
|
||||
sup: ty::Region<'tcx>,
|
||||
) -> Self {
|
||||
Self { infcx, error: None, regions: Some((span, sub, sup)) }
|
||||
Self { cx, error: None, regions: Some((span, sub, sup)) }
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
self.cx.tcx
|
||||
}
|
||||
|
||||
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
|
@ -226,12 +226,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
||||
false
|
||||
};
|
||||
|
||||
let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef {
|
||||
let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: expected_substs,
|
||||
});
|
||||
let actual_trait_ref = self
|
||||
.infcx
|
||||
.cx
|
||||
.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
|
||||
|
||||
// Search the expected and actual trait references to see (a)
|
||||
|
@ -486,7 +486,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
tcx,
|
||||
ctxt.param_env,
|
||||
ctxt.assoc_item.def_id,
|
||||
self.infcx.resolve_vars_if_possible(ctxt.substs),
|
||||
self.cx.resolve_vars_if_possible(ctxt.substs),
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
|
@ -84,12 +84,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
|
||||
let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
|
||||
let expected = self
|
||||
.infcx
|
||||
.cx
|
||||
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
|
||||
.name;
|
||||
let found_highlight = HighlightBuilder::build(self.tcx(), found);
|
||||
let found =
|
||||
self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
|
||||
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
|
||||
|
||||
err.span_label(sp, &format!("found `{}`", found));
|
||||
err.span_label(trait_sp, &format!("expected `{}`", expected));
|
||||
|
@ -130,7 +130,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
let ret_ty = fn_ty.fn_sig(self.tcx()).output();
|
||||
let span = hir_sig.decl.output.span();
|
||||
let future_output = if hir_sig.header.is_async() {
|
||||
ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
|
||||
ret_ty.map_bound(|ty| self.cx.get_impl_future_output_ty(ty)).transpose()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::errors::RegionOriginNote;
|
||||
use crate::infer::error_reporting::note_and_explain_region;
|
||||
use crate::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
||||
use crate::infer::{self, SubregionOrigin};
|
||||
use rustc_errors::{
|
||||
fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
};
|
||||
@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Region};
|
||||
|
||||
use super::ObligationCauseAsDiagArg;
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
|
||||
match *origin {
|
||||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||
|
@ -40,6 +40,7 @@ use std::cell::{Cell, Ref, RefCell};
|
||||
use std::fmt;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
use self::error_reporting::TypeErrCtxt;
|
||||
use self::free_regions::RegionRelations;
|
||||
use self::lexical_region_resolve::LexicalRegionResolutions;
|
||||
use self::outlives::env::OutlivesEnvironment;
|
||||
@ -701,6 +702,12 @@ pub struct CombinedSnapshot<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
/// Creates a `TypeErrCtxt` for emitting various inference errors.
|
||||
/// During typeck, use `FnCtxt::infer_err` instead.
|
||||
pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
|
||||
TypeErrCtxt { infcx: self, typeck_results: None }
|
||||
}
|
||||
|
||||
/// calls `tcx.try_unify_abstract_consts` after
|
||||
/// canonicalizing the consts.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
@ -1343,32 +1350,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
|
||||
errors
|
||||
}
|
||||
|
||||
/// Process the region constraints and report any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
///
|
||||
/// Make sure to call [`InferCtxt::process_registered_region_obligations`]
|
||||
/// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
|
||||
/// to do both of these operations together.
|
||||
pub fn resolve_regions_and_report_errors(
|
||||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) {
|
||||
let errors = self.resolve_regions(outlives_env);
|
||||
|
||||
if !self.is_tainted_by_errors() {
|
||||
// As a heuristic, just skip reporting region errors
|
||||
// altogether if other errors have been reported while
|
||||
// this infcx was in use. This is totally hokey but
|
||||
// otherwise we have a hard time separating legit region
|
||||
// errors from silly ones.
|
||||
self.report_region_errors(generic_param_scope, &errors);
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtains (and clears) the current set of region
|
||||
/// constraints. The inference context is still usable: further
|
||||
/// unifications will simply add new constraints.
|
||||
@ -1524,59 +1505,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
resolve::fully_resolve(self, value)
|
||||
}
|
||||
|
||||
// [Note-Type-error-reporting]
|
||||
// An invariant is that anytime the expected or actual type is Error (the special
|
||||
// error type, meaning that an error occurred when typechecking this expression),
|
||||
// this is a derived error. The error cascaded from another error (that was already
|
||||
// reported), so it's not useful to display it to the user.
|
||||
// The following methods implement this logic.
|
||||
// They check if either the actual or expected type is Error, and don't print the error
|
||||
// in this case. The typechecker should only ever report type errors involving mismatched
|
||||
// types using one of these methods, and should not call span_err directly for such
|
||||
// errors.
|
||||
|
||||
pub fn type_error_struct_with_diag<M>(
|
||||
&self,
|
||||
sp: Span,
|
||||
mk_diag: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
|
||||
where
|
||||
M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
{
|
||||
let actual_ty = self.resolve_vars_if_possible(actual_ty);
|
||||
debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
|
||||
|
||||
let mut err = mk_diag(self.ty_to_string(actual_ty));
|
||||
|
||||
// Don't report an error if actual type is `Error`.
|
||||
if actual_ty.references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub fn report_mismatched_types(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
err: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
|
||||
}
|
||||
|
||||
pub fn report_mismatched_consts(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
expected: ty::Const<'tcx>,
|
||||
actual: ty::Const<'tcx>,
|
||||
err: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
|
||||
}
|
||||
|
||||
pub fn replace_bound_vars_with_fresh_vars<T>(
|
||||
&self,
|
||||
span: Span,
|
||||
@ -1816,6 +1744,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
/// Process the region constraints and report any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
///
|
||||
/// Make sure to call [`InferCtxt::process_registered_region_obligations`]
|
||||
/// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
|
||||
/// to do both of these operations together.
|
||||
pub fn resolve_regions_and_report_errors(
|
||||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) {
|
||||
let errors = self.resolve_regions(outlives_env);
|
||||
|
||||
if !self.is_tainted_by_errors() {
|
||||
// As a heuristic, just skip reporting region errors
|
||||
// altogether if other errors have been reported while
|
||||
// this infcx was in use. This is totally hokey but
|
||||
// otherwise we have a hard time separating legit region
|
||||
// errors from silly ones.
|
||||
self.report_region_errors(generic_param_scope, &errors);
|
||||
}
|
||||
}
|
||||
|
||||
// [Note-Type-error-reporting]
|
||||
// An invariant is that anytime the expected or actual type is Error (the special
|
||||
// error type, meaning that an error occurred when typechecking this expression),
|
||||
// this is a derived error. The error cascaded from another error (that was already
|
||||
// reported), so it's not useful to display it to the user.
|
||||
// The following methods implement this logic.
|
||||
// They check if either the actual or expected type is Error, and don't print the error
|
||||
// in this case. The typechecker should only ever report type errors involving mismatched
|
||||
// types using one of these methods, and should not call span_err directly for such
|
||||
// errors.
|
||||
|
||||
pub fn type_error_struct_with_diag<M>(
|
||||
&self,
|
||||
sp: Span,
|
||||
mk_diag: M,
|
||||
actual_ty: Ty<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
|
||||
where
|
||||
M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
{
|
||||
let actual_ty = self.resolve_vars_if_possible(actual_ty);
|
||||
debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
|
||||
|
||||
let mut err = mk_diag(self.ty_to_string(actual_ty));
|
||||
|
||||
// Don't report an error if actual type is `Error`.
|
||||
if actual_ty.references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub fn report_mismatched_types(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
err: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
|
||||
}
|
||||
|
||||
pub fn report_mismatched_consts(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
expected: ty::Const<'tcx>,
|
||||
actual: ty::Const<'tcx>,
|
||||
err: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
|
||||
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -183,7 +183,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
outlives_env.param_env,
|
||||
);
|
||||
|
||||
self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
|
||||
self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
use std::mem;
|
||||
|
||||
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
|
||||
pub struct Sub<'combine, 'infcx, 'tcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
pub struct Sub<'combine, 'a, 'tcx> {
|
||||
fields: &'combine mut CombineFields<'a, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
// general routines.
|
||||
|
||||
use crate::infer::{DefiningAnchor, TyCtxtInferExt};
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::{
|
||||
ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
|
||||
Unimplemented,
|
||||
@ -69,7 +69,7 @@ pub fn codegen_select_candidate<'tcx>(
|
||||
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
|
||||
for err in errors {
|
||||
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
|
||||
infcx.report_overflow_error_cycle(&cycle);
|
||||
infcx.err_ctxt().report_overflow_error_cycle(&cycle);
|
||||
}
|
||||
}
|
||||
return Err(CodegenObligationError::FulfillmentError);
|
||||
|
@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::GenericParam;
|
||||
use rustc_hir::Item;
|
||||
use rustc_hir::Node;
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::TypeTrace;
|
||||
use rustc_infer::traits::TraitEngine;
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
@ -32,6 +33,8 @@ use rustc_middle::ty::{
|
||||
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
|
||||
TypeVisitable,
|
||||
};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{ExpnKind, Span, DUMMY_SP};
|
||||
use std::fmt;
|
||||
@ -41,8 +44,8 @@ use std::ops::ControlFlow;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use crate::traits::query::normalize::AtExt as _;
|
||||
use crate::traits::specialize::to_pretty_impl_header;
|
||||
use on_unimplemented::InferCtxtExt as _;
|
||||
use suggestions::InferCtxtExt as _;
|
||||
use on_unimplemented::TypeErrCtxtExt as _;
|
||||
use suggestions::TypeErrCtxtExt as _;
|
||||
|
||||
pub use rustc_infer::traits::error_reporting::*;
|
||||
|
||||
@ -63,34 +66,6 @@ pub struct ImplCandidate<'tcx> {
|
||||
}
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
&self,
|
||||
errors: &[FulfillmentError<'tcx>],
|
||||
body_id: Option<hir::BodyId>,
|
||||
fallback_has_occurred: bool,
|
||||
) -> ErrorGuaranteed;
|
||||
|
||||
fn report_overflow_error<T>(
|
||||
&self,
|
||||
obligation: &Obligation<'tcx, T>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> !
|
||||
where
|
||||
T: fmt::Display + TypeFoldable<'tcx>;
|
||||
|
||||
fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
|
||||
|
||||
/// The `root_obligation` parameter should be the `root_obligation` field
|
||||
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
||||
/// then it should be the same as `obligation`.
|
||||
fn report_selection_error(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
root_obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>,
|
||||
fallback_has_occurred: bool,
|
||||
);
|
||||
|
||||
/// Given some node representing a fn-like thing in the HIR map,
|
||||
/// returns a span and `ArgKind` information that describes the
|
||||
/// arguments it expects. This can be supplied to
|
||||
@ -121,7 +96,281 @@ pub trait InferCtxtExt<'tcx> {
|
||||
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
&self,
|
||||
errors: &[FulfillmentError<'tcx>],
|
||||
body_id: Option<hir::BodyId>,
|
||||
fallback_has_occurred: bool,
|
||||
) -> ErrorGuaranteed;
|
||||
|
||||
fn report_overflow_error<T>(
|
||||
&self,
|
||||
obligation: &Obligation<'tcx, T>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> !
|
||||
where
|
||||
T: fmt::Display + TypeFoldable<'tcx>;
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
|
||||
|
||||
fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
|
||||
|
||||
/// The `root_obligation` parameter should be the `root_obligation` field
|
||||
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
||||
/// then it should be the same as `obligation`.
|
||||
fn report_selection_error(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
root_obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>,
|
||||
fallback_has_occurred: bool,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'_, 'tcx> {
|
||||
/// Given some node representing a fn-like thing in the HIR map,
|
||||
/// returns a span and `ArgKind` information that describes the
|
||||
/// arguments it expects. This can be supplied to
|
||||
/// `report_arg_count_mismatch`.
|
||||
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
|
||||
let sm = self.tcx.sess.source_map();
|
||||
let hir = self.tcx.hir();
|
||||
Some(match node {
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
|
||||
..
|
||||
}) => (
|
||||
fn_decl_span,
|
||||
hir.body(body)
|
||||
.params
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
|
||||
*arg.pat
|
||||
{
|
||||
Some(ArgKind::Tuple(
|
||||
Some(span),
|
||||
args.iter()
|
||||
.map(|pat| {
|
||||
sm.span_to_snippet(pat.span)
|
||||
.ok()
|
||||
.map(|snippet| (snippet, "_".to_owned()))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?,
|
||||
))
|
||||
} else {
|
||||
let name = sm.span_to_snippet(arg.pat.span).ok()?;
|
||||
Some(ArgKind::Arg(name, "_".to_owned()))
|
||||
}
|
||||
})
|
||||
.collect::<Option<Vec<ArgKind>>>()?,
|
||||
),
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
|
||||
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
|
||||
| Node::TraitItem(&hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(ref sig, _), ..
|
||||
}) => (
|
||||
sig.span,
|
||||
sig.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| match arg.kind {
|
||||
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
||||
Some(arg.span),
|
||||
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
||||
),
|
||||
_ => ArgKind::empty(),
|
||||
})
|
||||
.collect::<Vec<ArgKind>>(),
|
||||
),
|
||||
Node::Ctor(ref variant_data) => {
|
||||
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
|
||||
(span, vec![ArgKind::empty(); variant_data.fields().len()])
|
||||
}
|
||||
_ => panic!("non-FnLike node found: {:?}", node),
|
||||
})
|
||||
}
|
||||
|
||||
/// Reports an error when the number of arguments needed by a
|
||||
/// trait match doesn't match the number that the expression
|
||||
/// provides.
|
||||
fn report_arg_count_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected_args: Vec<ArgKind>,
|
||||
found_args: Vec<ArgKind>,
|
||||
is_closure: bool,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let kind = if is_closure { "closure" } else { "function" };
|
||||
|
||||
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
|
||||
let arg_length = arguments.len();
|
||||
let distinct = matches!(other, &[ArgKind::Tuple(..)]);
|
||||
match (arg_length, arguments.get(0)) {
|
||||
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
|
||||
format!("a single {}-tuple as argument", fields.len())
|
||||
}
|
||||
_ => format!(
|
||||
"{} {}argument{}",
|
||||
arg_length,
|
||||
if distinct && arg_length > 1 { "distinct " } else { "" },
|
||||
pluralize!(arg_length)
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
let expected_str = args_str(&expected_args, &found_args);
|
||||
let found_str = args_str(&found_args, &expected_args);
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0593,
|
||||
"{} is expected to take {}, but it takes {}",
|
||||
kind,
|
||||
expected_str,
|
||||
found_str,
|
||||
);
|
||||
|
||||
err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
|
||||
|
||||
if let Some(found_span) = found_span {
|
||||
err.span_label(found_span, format!("takes {}", found_str));
|
||||
|
||||
// move |_| { ... }
|
||||
// ^^^^^^^^-- def_span
|
||||
//
|
||||
// move |_| { ... }
|
||||
// ^^^^^-- prefix
|
||||
let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
|
||||
// move |_| { ... }
|
||||
// ^^^-- pipe_span
|
||||
let pipe_span =
|
||||
if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
|
||||
|
||||
// Suggest to take and ignore the arguments with expected_args_length `_`s if
|
||||
// found arguments is empty (assume the user just wants to ignore args in this case).
|
||||
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
|
||||
if found_args.is_empty() && is_closure {
|
||||
let underscores = vec!["_"; expected_args.len()].join(", ");
|
||||
err.span_suggestion_verbose(
|
||||
pipe_span,
|
||||
&format!(
|
||||
"consider changing the closure to take and ignore the expected argument{}",
|
||||
pluralize!(expected_args.len())
|
||||
),
|
||||
format!("|{}|", underscores),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
|
||||
if fields.len() == expected_args.len() {
|
||||
let sugg = fields
|
||||
.iter()
|
||||
.map(|(name, _)| name.to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
err.span_suggestion_verbose(
|
||||
found_span,
|
||||
"change the closure to take multiple arguments instead of a single tuple",
|
||||
format!("|{}|", sugg),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
|
||||
&& fields.len() == found_args.len()
|
||||
&& is_closure
|
||||
{
|
||||
let sugg = format!(
|
||||
"|({}){}|",
|
||||
found_args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
ArgKind::Arg(name, _) => name.to_owned(),
|
||||
_ => "_".to_owned(),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
// add type annotations if available
|
||||
if found_args.iter().any(|arg| match arg {
|
||||
ArgKind::Arg(_, ty) => ty != "_",
|
||||
_ => false,
|
||||
}) {
|
||||
format!(
|
||||
": ({})",
|
||||
fields
|
||||
.iter()
|
||||
.map(|(_, ty)| ty.to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
found_span,
|
||||
"change the closure to accept a tuple instead of individual arguments",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn type_implements_fn_trait(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
|
||||
self.commit_if_ok(|_| {
|
||||
for trait_def_id in [
|
||||
self.tcx.lang_items().fn_trait(),
|
||||
self.tcx.lang_items().fn_mut_trait(),
|
||||
self.tcx.lang_items().fn_once_trait(),
|
||||
] {
|
||||
let Some(trait_def_id) = trait_def_id else { continue };
|
||||
// Make a fresh inference variable so we can determine what the substitutions
|
||||
// of the trait are.
|
||||
let var = self.next_ty_var(TypeVariableOrigin {
|
||||
span: DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
});
|
||||
let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
|
||||
let obligation = Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty.rebind(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(trait_def_id, substs),
|
||||
constness,
|
||||
polarity,
|
||||
})
|
||||
.to_predicate(self.tcx),
|
||||
);
|
||||
let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
|
||||
fulfill_cx.register_predicate_obligation(self, obligation);
|
||||
if fulfill_cx.select_all_or_error(self).is_empty() {
|
||||
return Ok((
|
||||
ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
|
||||
.expect("expected to map DefId to ClosureKind"),
|
||||
ty.rebind(self.resolve_vars_if_possible(var)),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Err(())
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
&self,
|
||||
errors: &[FulfillmentError<'tcx>],
|
||||
@ -251,6 +500,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
bug!();
|
||||
}
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
|
||||
let suggested_limit = match self.tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
err.help(&format!(
|
||||
"consider increasing the recursion limit by adding a \
|
||||
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
|
||||
suggested_limit,
|
||||
self.tcx.crate_name(LOCAL_CRATE),
|
||||
));
|
||||
}
|
||||
|
||||
/// Reports that a cycle was detected which led to overflow and halts
|
||||
/// compilation. This is equivalent to `report_overflow_error` except
|
||||
/// that we can give a more helpful error message (and, in particular,
|
||||
@ -498,7 +760,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
|
||||
Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
|
||||
Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
|
||||
self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
|
||||
}
|
||||
|
||||
@ -606,11 +868,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// Try to report a help message
|
||||
if is_fn_trait
|
||||
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
|
||||
obligation.param_env,
|
||||
trait_ref.self_ty(),
|
||||
trait_predicate.skip_binder().constness,
|
||||
trait_predicate.skip_binder().polarity,
|
||||
)
|
||||
obligation.param_env,
|
||||
trait_ref.self_ty(),
|
||||
trait_predicate.skip_binder().constness,
|
||||
trait_predicate.skip_binder().polarity,
|
||||
)
|
||||
{
|
||||
// If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
|
||||
// suggestion to add trait bounds for the type, since we only typically implement
|
||||
@ -840,12 +1102,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
|
||||
// Additional context information explaining why the closure only implements
|
||||
// a particular trait.
|
||||
if let Some(typeck_results) = self.in_progress_typeck_results {
|
||||
if let Some(typeck_results) = &self.typeck_results {
|
||||
let hir_id = self
|
||||
.tcx
|
||||
.hir()
|
||||
.local_def_id_to_hir_id(closure_def_id.expect_local());
|
||||
let typeck_results = typeck_results.borrow();
|
||||
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
|
||||
(ty::ClosureKind::FnOnce, Some((span, place))) => {
|
||||
err.span_label(
|
||||
@ -1088,250 +1349,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Given some node representing a fn-like thing in the HIR map,
|
||||
/// returns a span and `ArgKind` information that describes the
|
||||
/// arguments it expects. This can be supplied to
|
||||
/// `report_arg_count_mismatch`.
|
||||
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
|
||||
let sm = self.tcx.sess.source_map();
|
||||
let hir = self.tcx.hir();
|
||||
Some(match node {
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
|
||||
..
|
||||
}) => (
|
||||
fn_decl_span,
|
||||
hir.body(body)
|
||||
.params
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
|
||||
*arg.pat
|
||||
{
|
||||
Some(ArgKind::Tuple(
|
||||
Some(span),
|
||||
args.iter()
|
||||
.map(|pat| {
|
||||
sm.span_to_snippet(pat.span)
|
||||
.ok()
|
||||
.map(|snippet| (snippet, "_".to_owned()))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?,
|
||||
))
|
||||
} else {
|
||||
let name = sm.span_to_snippet(arg.pat.span).ok()?;
|
||||
Some(ArgKind::Arg(name, "_".to_owned()))
|
||||
}
|
||||
})
|
||||
.collect::<Option<Vec<ArgKind>>>()?,
|
||||
),
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
|
||||
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
|
||||
| Node::TraitItem(&hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(ref sig, _), ..
|
||||
}) => (
|
||||
sig.span,
|
||||
sig.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| match arg.kind {
|
||||
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
||||
Some(arg.span),
|
||||
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
||||
),
|
||||
_ => ArgKind::empty(),
|
||||
})
|
||||
.collect::<Vec<ArgKind>>(),
|
||||
),
|
||||
Node::Ctor(ref variant_data) => {
|
||||
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
|
||||
(span, vec![ArgKind::empty(); variant_data.fields().len()])
|
||||
}
|
||||
_ => panic!("non-FnLike node found: {:?}", node),
|
||||
})
|
||||
}
|
||||
|
||||
/// Reports an error when the number of arguments needed by a
|
||||
/// trait match doesn't match the number that the expression
|
||||
/// provides.
|
||||
fn report_arg_count_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected_args: Vec<ArgKind>,
|
||||
found_args: Vec<ArgKind>,
|
||||
is_closure: bool,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let kind = if is_closure { "closure" } else { "function" };
|
||||
|
||||
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
|
||||
let arg_length = arguments.len();
|
||||
let distinct = matches!(other, &[ArgKind::Tuple(..)]);
|
||||
match (arg_length, arguments.get(0)) {
|
||||
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
|
||||
format!("a single {}-tuple as argument", fields.len())
|
||||
}
|
||||
_ => format!(
|
||||
"{} {}argument{}",
|
||||
arg_length,
|
||||
if distinct && arg_length > 1 { "distinct " } else { "" },
|
||||
pluralize!(arg_length)
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
let expected_str = args_str(&expected_args, &found_args);
|
||||
let found_str = args_str(&found_args, &expected_args);
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0593,
|
||||
"{} is expected to take {}, but it takes {}",
|
||||
kind,
|
||||
expected_str,
|
||||
found_str,
|
||||
);
|
||||
|
||||
err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
|
||||
|
||||
if let Some(found_span) = found_span {
|
||||
err.span_label(found_span, format!("takes {}", found_str));
|
||||
|
||||
// move |_| { ... }
|
||||
// ^^^^^^^^-- def_span
|
||||
//
|
||||
// move |_| { ... }
|
||||
// ^^^^^-- prefix
|
||||
let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
|
||||
// move |_| { ... }
|
||||
// ^^^-- pipe_span
|
||||
let pipe_span =
|
||||
if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
|
||||
|
||||
// Suggest to take and ignore the arguments with expected_args_length `_`s if
|
||||
// found arguments is empty (assume the user just wants to ignore args in this case).
|
||||
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
|
||||
if found_args.is_empty() && is_closure {
|
||||
let underscores = vec!["_"; expected_args.len()].join(", ");
|
||||
err.span_suggestion_verbose(
|
||||
pipe_span,
|
||||
&format!(
|
||||
"consider changing the closure to take and ignore the expected argument{}",
|
||||
pluralize!(expected_args.len())
|
||||
),
|
||||
format!("|{}|", underscores),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
|
||||
if fields.len() == expected_args.len() {
|
||||
let sugg = fields
|
||||
.iter()
|
||||
.map(|(name, _)| name.to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
err.span_suggestion_verbose(
|
||||
found_span,
|
||||
"change the closure to take multiple arguments instead of a single tuple",
|
||||
format!("|{}|", sugg),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
|
||||
&& fields.len() == found_args.len()
|
||||
&& is_closure
|
||||
{
|
||||
let sugg = format!(
|
||||
"|({}){}|",
|
||||
found_args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
ArgKind::Arg(name, _) => name.to_owned(),
|
||||
_ => "_".to_owned(),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
// add type annotations if available
|
||||
if found_args.iter().any(|arg| match arg {
|
||||
ArgKind::Arg(_, ty) => ty != "_",
|
||||
_ => false,
|
||||
}) {
|
||||
format!(
|
||||
": ({})",
|
||||
fields
|
||||
.iter()
|
||||
.map(|(_, ty)| ty.to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
found_span,
|
||||
"change the closure to accept a tuple instead of individual arguments",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn type_implements_fn_trait(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
|
||||
self.commit_if_ok(|_| {
|
||||
for trait_def_id in [
|
||||
self.tcx.lang_items().fn_trait(),
|
||||
self.tcx.lang_items().fn_mut_trait(),
|
||||
self.tcx.lang_items().fn_once_trait(),
|
||||
] {
|
||||
let Some(trait_def_id) = trait_def_id else { continue };
|
||||
// Make a fresh inference variable so we can determine what the substitutions
|
||||
// of the trait are.
|
||||
let var = self.next_ty_var(TypeVariableOrigin {
|
||||
span: DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
});
|
||||
let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
|
||||
let obligation = Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty.rebind(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(trait_def_id, substs),
|
||||
constness,
|
||||
polarity,
|
||||
})
|
||||
.to_predicate(self.tcx),
|
||||
);
|
||||
let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
|
||||
fulfill_cx.register_predicate_obligation(self, obligation);
|
||||
if fulfill_cx.select_all_or_error(self).is_empty() {
|
||||
return Ok((
|
||||
ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
|
||||
.expect("expected to map DefId to ClosureKind"),
|
||||
ty.rebind(self.resolve_vars_if_possible(var)),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Err(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
trait InferCtxtPrivExt<'hir, 'tcx> {
|
||||
trait InferCtxtPrivExt<'tcx> {
|
||||
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
|
||||
// `error` occurring implies that `cond` occurs.
|
||||
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
|
||||
@ -1430,13 +1450,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
);
|
||||
|
||||
fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>);
|
||||
fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
|
||||
|
||||
fn maybe_indirection_for_unsized(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
item: &'hir Item<'hir>,
|
||||
param: &'hir GenericParam<'hir>,
|
||||
item: &'tcx Item<'tcx>,
|
||||
param: &'tcx GenericParam<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn is_recursive_obligation(
|
||||
@ -1446,7 +1466,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
|
||||
// `error` occurring implies that `cond` occurs.
|
||||
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
|
||||
@ -2581,12 +2601,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn maybe_suggest_unsized_generics<'hir>(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
node: Node<'hir>,
|
||||
) {
|
||||
fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) {
|
||||
let Some(generics) = node.generics() else {
|
||||
return;
|
||||
};
|
||||
@ -2637,11 +2652,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
fn maybe_indirection_for_unsized<'hir>(
|
||||
fn maybe_indirection_for_unsized(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
item: &'hir Item<'hir>,
|
||||
param: &'hir GenericParam<'hir>,
|
||||
item: &Item<'tcx>,
|
||||
param: &GenericParam<'tcx>,
|
||||
) -> bool {
|
||||
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
|
||||
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{
|
||||
ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
|
||||
};
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::SubstsRef;
|
||||
@ -11,7 +11,7 @@ use std::iter;
|
||||
|
||||
use super::InferCtxtPrivExt;
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
/*private*/
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
@ -29,7 +29,7 @@ pub trait InferCtxtExt<'tcx> {
|
||||
) -> OnUnimplementedNote;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
@ -20,6 +20,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::hir::map;
|
||||
use rustc_middle::ty::{
|
||||
@ -28,8 +29,6 @@ use rustc_middle::ty::{
|
||||
ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
|
||||
};
|
||||
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
@ -168,7 +167,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
|
||||
}
|
||||
|
||||
// This trait is public to expose the diagnostics methods to clippy.
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
fn suggest_restricting_param_bound(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
@ -296,8 +295,6 @@ pub trait InferCtxtExt<'tcx> {
|
||||
) where
|
||||
T: fmt::Display;
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
|
||||
|
||||
/// Suggest to await before try: future? => future.await?
|
||||
fn suggest_await_before_try(
|
||||
&self,
|
||||
@ -461,7 +458,7 @@ fn suggest_restriction<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
fn suggest_restricting_param_bound(
|
||||
&self,
|
||||
mut err: &mut Diagnostic,
|
||||
@ -675,9 +672,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// It only make sense when suggesting dereferences for arguments
|
||||
let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code()
|
||||
else { return false; };
|
||||
let Some(typeck_results) = self.in_progress_typeck_results
|
||||
let Some(typeck_results) = &self.typeck_results
|
||||
else { return false; };
|
||||
let typeck_results = typeck_results.borrow();
|
||||
let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id)
|
||||
else { return false; };
|
||||
let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)
|
||||
@ -1176,8 +1172,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
&format!("this call returns `{}`", pred.self_ty()),
|
||||
);
|
||||
}
|
||||
if let Some(typeck_results) =
|
||||
self.in_progress_typeck_results.map(|t| t.borrow())
|
||||
if let Some(typeck_results) = &self.typeck_results
|
||||
&& let ty = typeck_results.expr_ty_adjusted(base)
|
||||
&& let ty::FnDef(def_id, _substs) = ty.kind()
|
||||
&& let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
|
||||
@ -1300,8 +1295,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
&& let Some(stmt) = blk.stmts.last()
|
||||
&& let hir::StmtKind::Semi(expr) = stmt.kind
|
||||
// Only suggest this if the expression behind the semicolon implements the predicate
|
||||
&& let Some(typeck_results) = self.in_progress_typeck_results
|
||||
&& let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
|
||||
&& let Some(typeck_results) = &self.typeck_results
|
||||
&& let Some(ty) = typeck_results.expr_ty_opt(expr)
|
||||
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
|
||||
))
|
||||
@ -1390,7 +1385,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
visitor.visit_body(&body);
|
||||
|
||||
let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
|
||||
let typeck_results = self.typeck_results.as_ref().unwrap();
|
||||
let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
|
||||
|
||||
let ret_types = visitor
|
||||
@ -1573,7 +1568,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// Point at all the `return`s in the function as they have failed trait bounds.
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
visitor.visit_body(&body);
|
||||
let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
|
||||
let typeck_results = self.typeck_results.as_ref().unwrap();
|
||||
for expr in &visitor.returns {
|
||||
if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
|
||||
let ty = self.resolve_vars_if_possible(returned_ty);
|
||||
@ -1841,12 +1836,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
|
||||
let span = self.tcx.def_span(generator_did);
|
||||
|
||||
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
|
||||
let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
|
||||
debug!(
|
||||
?generator_did,
|
||||
?generator_did_root,
|
||||
in_progress_typeck_results.hir_owner = ?in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
|
||||
typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner),
|
||||
?span,
|
||||
);
|
||||
|
||||
@ -1901,7 +1895,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// type-checking; otherwise, get them by performing a query. This is needed to avoid
|
||||
// cycles. If we can't use resolved types because the generator comes from another crate,
|
||||
// we still provide a targeted error but without all the relevant spans.
|
||||
let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
|
||||
let generator_data: Option<GeneratorData<'tcx, '_>> = match &self.typeck_results {
|
||||
Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
|
||||
Some(GeneratorData::Local(&t))
|
||||
}
|
||||
@ -2707,10 +2701,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) =
|
||||
hir.find(arg_hir_id)
|
||||
{
|
||||
let in_progress_typeck_results =
|
||||
self.in_progress_typeck_results.map(|t| t.borrow());
|
||||
let parent_id = hir.get_parent_item(arg_hir_id);
|
||||
let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
|
||||
let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
|
||||
Some(t) if t.hir_owner == parent_id => t,
|
||||
_ => self.tcx.typeck(parent_id.def_id),
|
||||
};
|
||||
@ -2797,19 +2789,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
|
||||
let suggested_limit = match self.tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
err.help(&format!(
|
||||
"consider increasing the recursion limit by adding a \
|
||||
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
|
||||
suggested_limit,
|
||||
self.tcx.crate_name(LOCAL_CRATE),
|
||||
));
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
|
||||
)]
|
||||
|
@ -7,7 +7,7 @@ use rustc_hir as hir;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
|
||||
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CopyImplementationError<'tcx> {
|
||||
@ -70,7 +70,7 @@ pub fn can_type_implement_copy<'tcx>(
|
||||
}
|
||||
}
|
||||
Err(errors) => {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ pub mod wf;
|
||||
use crate::errors::DumpVTableEntries;
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
@ -238,7 +238,7 @@ fn do_normalize_predicates<'tcx>(
|
||||
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
|
||||
Ok(predicates) => predicates,
|
||||
Err(errors) => {
|
||||
let reported = infcx.report_fulfillment_errors(&errors, None, false);
|
||||
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||
return Err(reported);
|
||||
}
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use crate::traits::select::ProjectionMatchesProjection;
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
@ -513,7 +513,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||
self.param_env,
|
||||
ty,
|
||||
);
|
||||
self.selcx.infcx().report_overflow_error(&obligation, true);
|
||||
self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
|
||||
}
|
||||
|
||||
let substs = substs.fold_with(self);
|
||||
@ -569,7 +569,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||
self.param_env,
|
||||
ty,
|
||||
);
|
||||
self.selcx.infcx().report_overflow_error(&obligation, true);
|
||||
self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
|
||||
}
|
||||
debug!(
|
||||
?self.depth,
|
||||
|
@ -5,7 +5,7 @@
|
||||
use crate::infer::at::At;
|
||||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
@ -213,7 +213,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||
self.param_env,
|
||||
ty,
|
||||
);
|
||||
self.infcx.report_overflow_error(&obligation, true);
|
||||
self.infcx.err_ctxt().report_overflow_error(&obligation, true);
|
||||
}
|
||||
|
||||
let generic_ty = self.tcx().bound_type_of(def_id);
|
||||
|
@ -20,7 +20,7 @@ use super::{
|
||||
};
|
||||
|
||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::project::ProjectAndUnifyResult;
|
||||
use crate::traits::project::ProjectionCacheKeyExt;
|
||||
use crate::traits::ProjectionCacheKey;
|
||||
@ -1095,7 +1095,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
ErrorGuaranteed::unchecked_claim_error_was_emitted(),
|
||||
));
|
||||
}
|
||||
self.infcx.report_overflow_error(error_obligation, true);
|
||||
self.infcx.err_ctxt().report_overflow_error(error_obligation, true);
|
||||
}
|
||||
TraitQueryMode::Canonical => {
|
||||
return Err(OverflowError::Canonical);
|
||||
|
@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, FulfillmentError};
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
||||
|db| {
|
||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
for FulfillmentError { obligation, .. } in send_errors {
|
||||
infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
|
||||
infcx.err_ctxt().maybe_note_obligation_cause_for_async_await(db, &obligation);
|
||||
if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() {
|
||||
db.note(&format!(
|
||||
"`{}` doesn't implement `{}`",
|
||||
|
Loading…
Reference in New Issue
Block a user