Move trait selection error reporting to its own top-level module
This commit is contained in:
@@ -30,8 +30,8 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::error_reporting::suggest_new_overflow_limit;
|
||||
use super::ObligationCtxt;
|
||||
use crate::error_reporting::traits::suggest_new_overflow_limit;
|
||||
|
||||
pub struct OverlapResult<'tcx> {
|
||||
pub impl_header: ty::ImplHeader<'tcx>,
|
||||
|
||||
@@ -3,10 +3,10 @@ use std::fmt::Debug;
|
||||
|
||||
use super::{FromSolverError, TraitEngine};
|
||||
use super::{FulfillmentContext, ScrubbedTraitError};
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
|
||||
use crate::solve::NextSolverError;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::fulfill::OldSolverError;
|
||||
use crate::traits::NormalizeExt;
|
||||
use crate::traits::StructurallyNormalizeExt;
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
|
||||
use rustc_infer::traits::util::elaborate;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CandidateSource {
|
||||
DefId(DefId),
|
||||
ParamEnv(Span),
|
||||
}
|
||||
|
||||
pub fn compute_applicable_impls_for_diagnostics<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
) -> Vec<CandidateSource> {
|
||||
let tcx = infcx.tcx;
|
||||
let param_env = obligation.param_env;
|
||||
|
||||
let predicate_polarity = obligation.predicate.skip_binder().polarity;
|
||||
|
||||
let impl_may_apply = |impl_def_id| {
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
|
||||
let obligation_trait_ref = ocx.normalize(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
placeholder_obligation.trait_ref,
|
||||
);
|
||||
|
||||
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
|
||||
let impl_trait_ref =
|
||||
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
|
||||
let impl_trait_ref =
|
||||
ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
|
||||
|
||||
if let Err(_) =
|
||||
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
|
||||
let impl_polarity = impl_trait_header.polarity;
|
||||
|
||||
match (impl_polarity, predicate_polarity) {
|
||||
(ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
|
||||
| (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
let obligations = tcx
|
||||
.predicates_of(impl_def_id)
|
||||
.instantiate(tcx, impl_args)
|
||||
.into_iter()
|
||||
.map(|(predicate, _)| {
|
||||
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
|
||||
})
|
||||
// Kinda hacky, but let's just throw away obligations that overflow.
|
||||
// This may reduce the accuracy of this check (if the obligation guides
|
||||
// inference or it actually resulted in error after others are processed)
|
||||
// ... but this is diagnostics code.
|
||||
.filter(|obligation| {
|
||||
infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok()
|
||||
});
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
ocx.select_where_possible().is_empty()
|
||||
})
|
||||
};
|
||||
|
||||
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
|
||||
let obligation_trait_ref = ocx.normalize(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
placeholder_obligation.trait_ref,
|
||||
);
|
||||
|
||||
let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
poly_trait_predicate,
|
||||
);
|
||||
let param_env_trait_ref =
|
||||
ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
|
||||
|
||||
if let Err(_) = ocx.eq(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
obligation_trait_ref,
|
||||
param_env_trait_ref,
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ocx.select_where_possible().is_empty()
|
||||
})
|
||||
};
|
||||
|
||||
let mut ambiguities = Vec::new();
|
||||
|
||||
tcx.for_each_relevant_impl(
|
||||
obligation.predicate.def_id(),
|
||||
obligation.predicate.skip_binder().trait_ref.self_ty(),
|
||||
|impl_def_id| {
|
||||
if infcx.probe(|_| impl_may_apply(impl_def_id)) {
|
||||
ambiguities.push(CandidateSource::DefId(impl_def_id))
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let predicates =
|
||||
tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
|
||||
for (pred, span) in elaborate(tcx, predicates.into_iter()) {
|
||||
let kind = pred.kind();
|
||||
if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
|
||||
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
|
||||
{
|
||||
if kind.rebind(trait_pred.trait_ref)
|
||||
== ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
|
||||
{
|
||||
ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
|
||||
} else {
|
||||
ambiguities.push(CandidateSource::ParamEnv(span))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ambiguities
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Node;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use super::ArgKind;
|
||||
|
||||
pub use rustc_infer::traits::error_reporting::*;
|
||||
|
||||
#[extension(pub trait InferCtxtExt<'tcx>)]
|
||||
impl<'tcx> 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, 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_arg_span, .. }),
|
||||
..
|
||||
}) => (
|
||||
fn_decl_span,
|
||||
fn_arg_span,
|
||||
hir.body(body)
|
||||
.params
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let hir::Pat { kind: hir::PatKind::Tuple(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,
|
||||
None,
|
||||
sig.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| match arg.kind {
|
||||
hir::TyKind::Tup(tys) => ArgKind::Tuple(
|
||||
Some(arg.span),
|
||||
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
||||
),
|
||||
_ => ArgKind::empty(),
|
||||
})
|
||||
.collect::<Vec<ArgKind>>(),
|
||||
),
|
||||
Node::Ctor(variant_data) => {
|
||||
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
|
||||
(span, None, 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,
|
||||
closure_arg_span: Option<Span>,
|
||||
) -> Diag<'_> {
|
||||
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(_, 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_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0593,
|
||||
"{} is expected to take {}, but it takes {}",
|
||||
kind,
|
||||
expected_str,
|
||||
found_str,
|
||||
);
|
||||
|
||||
err.span_label(span, format!("expected {kind} that takes {expected_str}"));
|
||||
|
||||
if let Some(found_span) = found_span {
|
||||
err.span_label(found_span, format!("takes {found_str}"));
|
||||
|
||||
// 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(
|
||||
closure_arg_span.unwrap_or(found_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
|
||||
}
|
||||
|
||||
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
|
||||
/// in that order, and returns the generic type corresponding to the
|
||||
/// argument of that trait (corresponding to the closure arguments).
|
||||
fn type_implements_fn_trait(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
polarity: ty::PredicatePolarity,
|
||||
) -> 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 generic parameters
|
||||
// of the trait are.
|
||||
let var = self.next_ty_var(DUMMY_SP);
|
||||
// FIXME(effects)
|
||||
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
|
||||
let obligation = Obligation::new(
|
||||
self.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty.rebind(ty::TraitPredicate { trait_ref, polarity }),
|
||||
);
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
ocx.register_obligation(obligation);
|
||||
if ocx.select_all_or_error().is_empty() {
|
||||
return Ok((
|
||||
self.tcx
|
||||
.fn_trait_kind_from_def_id(trait_def_id)
|
||||
.expect("expected to map DefId to ClosureKind"),
|
||||
ty.rebind(self.resolve_vars_if_possible(var)),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Err(())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
// ignore-tidy-filelength :(
|
||||
|
||||
pub mod ambiguity;
|
||||
mod infer_ctxt_ext;
|
||||
pub mod on_unimplemented;
|
||||
pub mod suggestions;
|
||||
mod type_err_ctxt_ext;
|
||||
|
||||
use super::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub use self::infer_ctxt_ext::*;
|
||||
pub use self::type_err_ctxt_ext::*;
|
||||
|
||||
// When outputting impl candidates, prefer showing those that are more similar.
|
||||
//
|
||||
// We also compare candidates after skipping lifetimes, which has a lower
|
||||
// priority than exact matches.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum CandidateSimilarity {
|
||||
Exact { ignoring_lifetimes: bool },
|
||||
Fuzzy { ignoring_lifetimes: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ImplCandidate<'tcx> {
|
||||
pub trait_ref: ty::TraitRef<'tcx>,
|
||||
pub similarity: CandidateSimilarity,
|
||||
impl_def_id: DefId,
|
||||
}
|
||||
|
||||
enum GetSafeTransmuteErrorAndReason {
|
||||
Silent,
|
||||
Error { err_msg: String, safe_transmute_explanation: Option<String> },
|
||||
}
|
||||
|
||||
struct UnsatisfiedConst(pub bool);
|
||||
|
||||
/// Crude way of getting back an `Expr` from a `Span`.
|
||||
pub struct FindExprBySpan<'hir> {
|
||||
pub span: Span,
|
||||
pub result: Option<&'hir hir::Expr<'hir>>,
|
||||
pub ty_result: Option<&'hir hir::Ty<'hir>>,
|
||||
pub include_closures: bool,
|
||||
pub tcx: TyCtxt<'hir>,
|
||||
}
|
||||
|
||||
impl<'hir> FindExprBySpan<'hir> {
|
||||
pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
|
||||
Self { span, result: None, ty_result: None, tcx, include_closures: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for FindExprBySpan<'v> {
|
||||
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
if self.span == ex.span {
|
||||
self.result = Some(ex);
|
||||
} else {
|
||||
if let hir::ExprKind::Closure(..) = ex.kind
|
||||
&& self.include_closures
|
||||
&& let closure_header_sp = self.span.with_hi(ex.span.hi())
|
||||
&& closure_header_sp == ex.span
|
||||
{
|
||||
self.result = Some(ex);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, ex);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||
if self.span == ty.span {
|
||||
self.ty_result = Some(ty);
|
||||
} else {
|
||||
hir::intravisit::walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
|
||||
/// `param: ?Sized` would be a valid constraint.
|
||||
struct FindTypeParam {
|
||||
param: rustc_span::Symbol,
|
||||
invalid_spans: Vec<Span>,
|
||||
nested: bool,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for FindTypeParam {
|
||||
fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
|
||||
// Skip where-clauses, to avoid suggesting indirection for type parameters found there.
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
|
||||
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
|
||||
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
|
||||
// valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
|
||||
// obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
|
||||
// and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
|
||||
// in that case should make what happened clear enough.
|
||||
match ty.kind {
|
||||
hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, path))
|
||||
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
|
||||
{
|
||||
if !self.nested {
|
||||
debug!(?ty, "FindTypeParam::visit_ty");
|
||||
self.invalid_spans.push(ty.span);
|
||||
}
|
||||
}
|
||||
hir::TyKind::Path(_) => {
|
||||
let prev = self.nested;
|
||||
self.nested = true;
|
||||
hir::intravisit::walk_ty(self, ty);
|
||||
self.nested = prev;
|
||||
}
|
||||
_ => {
|
||||
hir::intravisit::walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Summarizes information
|
||||
#[derive(Clone)]
|
||||
pub enum ArgKind {
|
||||
/// An argument of non-tuple type. Parameters are (name, ty)
|
||||
Arg(String, String),
|
||||
|
||||
/// An argument of tuple type. For a "found" argument, the span is
|
||||
/// the location in the source of the pattern. For an "expected"
|
||||
/// argument, it will be None. The vector is a list of (name, ty)
|
||||
/// strings for the components of the tuple.
|
||||
Tuple(Option<Span>, Vec<(String, String)>),
|
||||
}
|
||||
|
||||
impl ArgKind {
|
||||
fn empty() -> ArgKind {
|
||||
ArgKind::Arg("_".to_owned(), "_".to_owned())
|
||||
}
|
||||
|
||||
/// Creates an `ArgKind` from the expected type of an
|
||||
/// argument. It has no name (`_`) and an optional source span.
|
||||
pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
|
||||
match t.kind() {
|
||||
ty::Tuple(tys) => ArgKind::Tuple(
|
||||
span,
|
||||
tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
|
||||
),
|
||||
_ => ArgKind::Arg("_".to_owned(), t.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HasNumericInferVisitor;
|
||||
|
||||
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum DefIdOrName {
|
||||
DefId(DefId),
|
||||
Name(&'static str),
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::infer::{InferCtxt, TyOrConstInferVar};
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::normalize::normalize_with_depth_to;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::obligation_forest::ProcessResult;
|
||||
|
||||
@@ -6,7 +6,6 @@ pub mod auto_trait;
|
||||
pub(crate) mod coherence;
|
||||
pub mod const_evaluatable;
|
||||
mod engine;
|
||||
pub mod error_reporting;
|
||||
mod fulfill;
|
||||
pub mod misc;
|
||||
pub mod normalize;
|
||||
@@ -24,10 +23,10 @@ mod util;
|
||||
pub mod vtable;
|
||||
pub mod wf;
|
||||
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt as _;
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_middle::query::Providers;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Deeply normalize types using the old trait solver.
|
||||
|
||||
use super::error_reporting::OverflowCause;
|
||||
use super::error_reporting::TypeErrCtxtExt;
|
||||
use super::SelectionContext;
|
||||
use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
|
||||
use crate::error_reporting::traits::OverflowCause;
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::solve::NextSolverError;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_infer::infer::at::At;
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
//! which folds deeply, invoking the underlying
|
||||
//! `normalize_canonicalized_projection_ty` query when it encounters projections.
|
||||
|
||||
use crate::error_reporting::traits::OverflowCause;
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::infer::at::At;
|
||||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::error_reporting::OverflowCause;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::normalize::needs_normalization;
|
||||
use crate::traits::Normalized;
|
||||
use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
|
||||
|
||||
@@ -18,9 +18,9 @@ use super::{
|
||||
TraitQueryMode,
|
||||
};
|
||||
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
|
||||
use crate::solve::InferCtxtSelectExt as _;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::normalize::normalize_with_depth;
|
||||
use crate::traits::normalize::normalize_with_depth_to;
|
||||
use crate::traits::project::ProjectAndUnifyResult;
|
||||
|
||||
@@ -14,6 +14,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use specialization_graph::GraphExt;
|
||||
|
||||
use crate::error_reporting::traits::to_pretty_impl_header;
|
||||
use crate::errors::NegativePositiveConflict;
|
||||
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
@@ -25,8 +26,8 @@ use rustc_errors::{codes::*, Diag, EmissionGuarantee};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::query::LocalCrate;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
|
||||
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
|
||||
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
|
||||
use rustc_span::{sym, ErrorGuaranteed, Span, DUMMY_SP};
|
||||
@@ -485,61 +486,3 @@ fn report_conflicting_impls<'tcx>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
|
||||
/// string.
|
||||
pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
|
||||
use std::fmt::Write;
|
||||
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
|
||||
let mut w = "impl".to_owned();
|
||||
|
||||
let args = GenericArgs::identity_for_item(tcx, impl_def_id);
|
||||
|
||||
// FIXME: Currently only handles ?Sized.
|
||||
// Needs to support ?Move and ?DynSized when they are implemented.
|
||||
let mut types_without_default_bounds = FxIndexSet::default();
|
||||
let sized_trait = tcx.lang_items().sized_trait();
|
||||
|
||||
let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
|
||||
if !arg_names.is_empty() {
|
||||
types_without_default_bounds.extend(args.types());
|
||||
w.push('<');
|
||||
w.push_str(&arg_names.join(", "));
|
||||
w.push('>');
|
||||
}
|
||||
|
||||
write!(
|
||||
w,
|
||||
" {} for {}",
|
||||
trait_ref.print_only_trait_path(),
|
||||
tcx.type_of(impl_def_id).instantiate_identity()
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The predicates will contain default bounds like `T: Sized`. We need to
|
||||
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
|
||||
let predicates = tcx.predicates_of(impl_def_id).predicates;
|
||||
let mut pretty_predicates =
|
||||
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
|
||||
|
||||
for (p, _) in predicates {
|
||||
if let Some(poly_trait_ref) = p.as_trait_clause() {
|
||||
if Some(poly_trait_ref.def_id()) == sized_trait {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pretty_predicates.push(p.to_string());
|
||||
}
|
||||
|
||||
pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
|
||||
|
||||
if !pretty_predicates.is_empty() {
|
||||
write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
|
||||
}
|
||||
|
||||
w.push(';');
|
||||
Some(w)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user