From 4fc06acfcb634010d8c95ae11572e05382bc7d2f Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Thu, 5 Sep 2024 11:25:40 +0000 Subject: [PATCH] Arbitrary self types v2: diagnostics in resolution. If we get past all the earlier stages of validation (in well-formedness checking and in probing) there's still a chance that resolving the self type will produce errors at the 'confirmation' stage. Add an extra note to those errors to make it clear that they were encountered while resolving the 'self' type. This is a fairly niche case and users may not encounter it often. It's arguably not worth the extra complexity required to produce this note. Opinions welcome. --- .../src/diagnostics/bound_region_errors.rs | 2 + .../src/check/compare_impl_item.rs | 4 ++ compiler/rustc_hir_analysis/src/check/mod.rs | 3 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 21 ++++++++-- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 + .../src/error_reporting/infer/mod.rs | 39 ++++++++++++++++++- .../src/error_reporting/infer/region.rs | 4 +- .../traits/fulfillment_errors.rs | 6 ++- ...lf-from-method-substs-with-receiver.stderr | 6 +++ ...ary-self-from-method-substs.feature.stderr | 5 +++ 11 files changed, 85 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 90d12ea832857..daef0d19d68c3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -18,6 +18,7 @@ use rustc_middle::ty::{ }; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::error_reporting::infer::TypeErrorRole; use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_trait_selection::traits::ObligationCtxt; use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; @@ -464,6 +465,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( *trace, infcx.tcx.param_env(generic_param_scope), TypeError::RegionsPlaceholderMismatch, + TypeErrorRole::Elsewhere, )) } else { None diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e176fc589995f..31d3ed3df3364 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::error_reporting::infer::TypeErrorRole; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; @@ -639,6 +640,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }))), terr, false, + TypeErrorRole::Elsewhere, ); return Err(diag.emit()); } @@ -1060,6 +1062,7 @@ fn report_trait_method_mismatch<'tcx>( }))), terr, false, + TypeErrorRole::Elsewhere, ); diag.emit() @@ -1852,6 +1855,7 @@ fn compare_const_predicate_entailment<'tcx>( }))), terr, false, + TypeErrorRole::Elsewhere, ); return Err(diag.emit()); }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 61e203a1ff668..a13b04acf63c2 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -92,7 +92,7 @@ use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; +use rustc_trait_selection::error_reporting::infer::{ObligationCauseExt as _, TypeErrorRole}; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; use rustc_trait_selection::traits::ObligationCtxt; use tracing::debug; @@ -651,6 +651,7 @@ pub fn check_function_signature<'tcx>( }))), err, false, + TypeErrorRole::Elsewhere, ); return Err(diag.emit()); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 6b1cceefbeea1..ebdeb461ca744 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -24,7 +24,9 @@ use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, Span, sym}; -use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt}; +use rustc_trait_selection::error_reporting::infer::{ + FailureCode, ObligationCauseExt, TypeErrorRole, +}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext}; use tracing::debug; @@ -830,6 +832,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), self.param_env, terr, + TypeErrorRole::Elsewhere, ); err.span_label( full_call_span, @@ -942,8 +945,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { - let mut err = - self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *e); + let mut err = self.err_ctxt().report_and_explain_type_error( + trace, + self.param_env, + *e, + TypeErrorRole::Elsewhere, + ); suggest_confusable(&mut err); reported = Some(err.emit()); return false; @@ -971,7 +978,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; let (provided_ty, provided_arg_span) = provided_arg_tys[provided_idx]; let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); - let mut err = self.err_ctxt().report_and_explain_type_error(trace, self.param_env, err); + let mut err = self.err_ctxt().report_and_explain_type_error( + trace, + self.param_env, + err, + TypeErrorRole::Elsewhere, + ); self.emit_coerce_suggestions( &mut err, provided_args[provided_idx], @@ -1148,6 +1160,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(self.param_env.and(trace.values)), e, true, + TypeErrorRole::Elsewhere, ); } } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index ef431c852e94b..112ffb407d407 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -531,7 +531,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Err(terr) => { if self.tcx.features().arbitrary_self_types() { self.err_ctxt() - .report_mismatched_types( + .report_mismatched_self_types( &cause, self.param_env, method_self_ty, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ee197ce07ca71..dd11b3555d92d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -35,6 +35,7 @@ use rustc_span::{BytePos, DUMMY_SP, Span}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::error_reporting::infer::TypeErrorRole; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; use tracing::debug; @@ -2371,6 +2372,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }))), terr, false, + TypeErrorRole::Elsewhere, ); diag.emit(); self.abort.set(true); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 5a62a4c3bd5fe..f9aa2e45d26bd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -92,6 +92,15 @@ pub mod nice_region_error; pub mod region; pub mod sub_relations; +/// A hint about where a type error occurred, for better diagnostics. +#[derive(Debug, PartialEq)] +pub enum TypeErrorRole { + /// This type error occurred while resolving the "self" type of a method + SelfType, + /// This type error occurred in any other context. + Elsewhere, +} + /// Makes a valid string literal from a string by escaping special characters (" and \), /// unless they are already escaped. fn escape_literal(s: &str) -> String { @@ -159,6 +168,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeTrace::types(cause, expected, actual), param_env, err, + TypeErrorRole::Elsewhere, + ) + } + + pub fn report_mismatched_self_types( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + err: TypeError<'tcx>, + ) -> Diag<'a> { + self.report_and_explain_type_error( + TypeTrace::types(cause, expected, actual), + param_env, + err, + TypeErrorRole::SelfType, ) } @@ -174,6 +200,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeTrace::consts(cause, expected, actual), param_env, err, + TypeErrorRole::Elsewhere, ) } @@ -1376,6 +1403,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { mut values: Option>>, terr: TypeError<'tcx>, prefer_label: bool, + role: TypeErrorRole, ) { let span = cause.span; @@ -1839,6 +1867,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + if role == TypeErrorRole::SelfType { + diag.note("this error occurred while resolving the `self` type of this method call"); + } + self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id()); if let Some(exp_found) = exp_found && let exp_found = TypeError::Sorts(exp_found) @@ -2026,8 +2058,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, terr: TypeError<'tcx>, + role: TypeErrorRole, ) -> Diag<'a> { - debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); + debug!( + "report_and_explain_type_error(trace={:?}, terr={:?}, role={:?})", + trace, terr, role + ); let span = trace.cause.span; let failure_code = trace.cause.as_failure_code_diag( @@ -2043,6 +2079,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(param_env.and(trace.values)), terr, false, + role, ); diag } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 9fd7dccc57ccb..9095d87442f51 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -17,8 +17,8 @@ use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol}; use rustc_type_ir::Upcast as _; use tracing::{debug, instrument}; -use super::ObligationCauseAsDiagArg; use super::nice_region_error::find_anon_type; +use super::{ObligationCauseAsDiagArg, TypeErrorRole}; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::ObligationCauseExt; use crate::errors::{ @@ -299,6 +299,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trace, self.tcx.param_env(generic_param_scope), terr, + TypeErrorRole::Elsewhere, ); match (*sub, *sup) { (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} @@ -654,6 +655,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trace, self.tcx.param_env(generic_param_scope), terr, + TypeErrorRole::Elsewhere, ); } _ => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4fb02f609438e..1a712285c1ac6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -38,7 +38,7 @@ use super::{ UnsatisfiedConst, }; use crate::error_reporting::TypeErrCtxt; -use crate::error_reporting::infer::TyCategory; +use crate::error_reporting::infer::{TyCategory, TypeErrorRole}; use crate::error_reporting::traits::report_dyn_incompatibility; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, @@ -727,6 +727,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { None, TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)), false, + TypeErrorRole::Elsewhere ); diag } @@ -1455,6 +1456,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }), err, false, + TypeErrorRole::Elsewhere, ); self.note_obligation_cause(&mut diag, obligation); diag.emit() @@ -2741,6 +2743,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeTrace::trait_refs(&cause, expected_trait_ref, found_trait_ref), obligation.param_env, terr, + TypeErrorRole::Elsewhere, ) } @@ -2832,6 +2835,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeTrace::trait_refs(&obligation.cause, expected_trait_ref, found_trait_ref), obligation.param_env, ty::error::TypeError::Mismatch, + TypeErrorRole::Elsewhere, )); } if found.len() != expected.len() { diff --git a/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr index 9af2a08f3712d..225bc1884cc6a 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr @@ -39,12 +39,16 @@ error[E0308]: mismatched types | LL | assert_eq!(foo.a::<&Foo>(), 2); | ^^^ expected `&Foo`, found `Foo` + | + = note: this error occurred while resolving the `self` type of this method call error[E0308]: mismatched types --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:53:16 | LL | assert_eq!(foo.b::<&Foo>(), 1); | ^^^ expected `&Foo`, found `Foo` + | + = note: this error occurred while resolving the `self` type of this method call error[E0308]: mismatched types --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:60:16 @@ -54,6 +58,7 @@ LL | assert_eq!(smart_ptr.a::<&Foo>(), 2); | = note: expected reference `&Foo` found struct `SmartPtr<'_, Foo, >` + = note: this error occurred while resolving the `self` type of this method call error[E0308]: mismatched types --> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:62:16 @@ -63,6 +68,7 @@ LL | assert_eq!(smart_ptr.b::<&Foo>(), 1); | = note: expected reference `&Foo` found struct `SmartPtr<'_, Foo, >` + = note: this error occurred while resolving the `self` type of this method call error: aborting due to 8 previous errors diff --git a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr index 6e864f44aa348..fca7b5dacc0a6 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr @@ -57,6 +57,8 @@ error[E0308]: mismatched types | LL | foo.get::<&Foo>(); | ^^^ expected `&Foo`, found `Foo` + | + = note: this error occurred while resolving the `self` type of this method call error[E0308]: mismatched types --> $DIR/arbitrary-self-from-method-substs.rs:78:5 @@ -66,6 +68,7 @@ LL | foo.get::>(); | = note: expected struct `Rc` found struct `Foo` + = note: this error occurred while resolving the `self` type of this method call error[E0308]: mismatched types --> $DIR/arbitrary-self-from-method-substs.rs:84:5 @@ -75,6 +78,7 @@ LL | smart_ptr.get::>(); | = note: expected struct `SmartPtr2<'_, Foo>` found struct `SmartPtr<'_, Foo>` + = note: this error occurred while resolving the `self` type of this method call error[E0308]: mismatched types --> $DIR/arbitrary-self-from-method-substs.rs:86:5 @@ -84,6 +88,7 @@ LL | smart_ptr.get::<&Foo>(); | = note: expected reference `&Foo` found struct `SmartPtr<'_, Foo, >` + = note: this error occurred while resolving the `self` type of this method call error[E0271]: type mismatch resolving `::Receiver == Foo` --> $DIR/arbitrary-self-from-method-substs.rs:92:9