summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/check/mod.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_hir_analysis/src/check/mod.rs
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check/mod.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs153
1 files changed, 123 insertions, 30 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 4cf358732..5fa65f33c 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -73,23 +73,31 @@ pub mod wfcheck;
pub use check::check_abi;
+use std::num::NonZeroU32;
+
use check::check_mod_item_types;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_index::bit_set::BitSet;
+use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{self, TyCtxtInferExt as _};
+use rustc_infer::traits::ObligationCause;
use rustc_middle::query::Providers;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::parse::feature_err;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, BytePos, Span, Symbol};
+use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::num::NonZeroU32;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCtxt;
use crate::errors;
use crate::require_c_abi_if_c_variadic;
@@ -289,6 +297,7 @@ fn default_body_is_unstable(
&tcx.sess.parse_sess,
feature,
rustc_feature::GateIssue::Library(issue),
+ false,
);
err.emit();
@@ -320,41 +329,52 @@ fn bounds_from_generic_predicates<'tcx>(
_ => {}
}
}
- let generics = if types.is_empty() {
- "".to_string()
- } else {
- format!(
- "<{}>",
- types
- .keys()
- .filter_map(|t| match t.kind() {
- ty::Param(_) => Some(t.to_string()),
- // Avoid suggesting the following:
- // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
- _ => None,
- })
- .collect::<Vec<_>>()
- .join(", ")
- )
- };
+
let mut where_clauses = vec![];
+ let mut types_str = vec![];
for (ty, bounds) in types {
- where_clauses
- .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
- }
- for projection in &projections {
- let p = projection.skip_binder();
- // FIXME: this is not currently supported syntax, we should be looking at the `types` and
- // insert the associated types where they correspond, but for now let's be "lazy" and
- // propose this instead of the following valid resugaring:
- // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
- where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
+ if let ty::Param(_) = ty.kind() {
+ let mut bounds_str = vec![];
+ for bound in bounds {
+ let mut projections_str = vec![];
+ for projection in &projections {
+ let p = projection.skip_binder();
+ let alias_ty = p.projection_ty;
+ if bound == tcx.parent(alias_ty.def_id) && alias_ty.self_ty() == ty {
+ let name = tcx.item_name(alias_ty.def_id);
+ projections_str.push(format!("{} = {}", name, p.term));
+ }
+ }
+ let bound_def_path = tcx.def_path_str(bound);
+ if projections_str.is_empty() {
+ where_clauses.push(format!("{}: {}", ty, bound_def_path));
+ } else {
+ bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
+ }
+ }
+ if bounds_str.is_empty() {
+ types_str.push(ty.to_string());
+ } else {
+ types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
+ }
+ } else {
+ // Avoid suggesting the following:
+ // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
+ where_clauses.extend(
+ bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
+ );
+ }
}
+
+ let generics =
+ if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
+
let where_clauses = if where_clauses.is_empty() {
- String::new()
+ "".to_string()
} else {
format!(" where {}", where_clauses.join(", "))
};
+
(generics, where_clauses)
}
@@ -545,3 +565,76 @@ fn bad_non_zero_sized_fields<'tcx>(
pub fn potentially_plural_count(count: usize, word: &str) -> String {
format!("{} {}{}", count, word, pluralize!(count))
}
+
+pub fn check_function_signature<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ mut cause: ObligationCause<'tcx>,
+ fn_id: DefId,
+ expected_sig: ty::PolyFnSig<'tcx>,
+) {
+ let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
+
+ let param_env = ty::ParamEnv::empty();
+
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+
+ let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
+
+ let norm_cause = ObligationCause::misc(cause.span, local_id);
+ let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
+
+ match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
+ Ok(()) => {
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors);
+ return;
+ }
+ }
+ Err(err) => {
+ let err_ctxt = infcx.err_ctxt();
+ if fn_id.is_local() {
+ cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
+ }
+ let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
+ let mut diag = tcx.sess.create_err(failure_code);
+ err_ctxt.note_type_err(
+ &mut diag,
+ &cause,
+ None,
+ Some(infer::ValuePairs::PolySigs(ExpectedFound {
+ expected: expected_sig,
+ found: actual_sig,
+ })),
+ err,
+ false,
+ false,
+ );
+ diag.emit();
+ return;
+ }
+ }
+
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ let _ = ocx.resolve_regions_and_report_errors(local_id, &outlives_env);
+
+ fn extract_span_for_error_reporting<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ err: TypeError<'_>,
+ cause: &ObligationCause<'tcx>,
+ fn_id: LocalDefId,
+ ) -> rustc_span::Span {
+ let mut args = {
+ let node = tcx.hir().expect_owner(fn_id);
+ let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
+ decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
+ };
+
+ match err {
+ TypeError::ArgumentMutability(i)
+ | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
+ _ => cause.span(),
+ }
+ }
+}