Introduce TypeErrCtxt
TypeErrCtxt optionally has a TypeckResults so that InferCtxt doesn't need to.
This commit is contained in:
parent
5854680388
commit
4a68373217
42 changed files with 655 additions and 589 deletions
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue