diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
6 files changed, 190 insertions, 42 deletions
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 574cf1e88b1..929fa559d75 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -50,6 +50,7 @@ use std::ops::ControlFlow; use std::path::PathBuf; use std::{cmp, fmt, iter}; +use rustc_abi::ExternAbi; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize}; use rustc_hir::def::DefKind; @@ -67,7 +68,6 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym}; -use rustc_target::spec::abi; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -686,10 +686,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // unsafe extern "C" for<'a> fn(&'a T) -> &'a T // ^^^^^^^^^^ - if sig1.abi != abi::Abi::Rust { + if sig1.abi != ExternAbi::Rust { values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi); } - if sig2.abi != abi::Abi::Rust { + if sig2.abi != ExternAbi::Rust { values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi); } @@ -766,6 +766,67 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { values } + pub fn cmp_traits( + &self, + def_id1: DefId, + args1: &[ty::GenericArg<'tcx>], + def_id2: DefId, + args2: &[ty::GenericArg<'tcx>], + ) -> (DiagStyledString, DiagStyledString) { + let mut values = (DiagStyledString::new(), DiagStyledString::new()); + + if def_id1 != def_id2 { + values.0.push_highlighted(self.tcx.def_path_str(def_id1).as_str()); + values.1.push_highlighted(self.tcx.def_path_str(def_id2).as_str()); + } else { + values.0.push_normal(self.tcx.item_name(def_id1).as_str()); + values.1.push_normal(self.tcx.item_name(def_id2).as_str()); + } + + if args1.len() != args2.len() { + let (pre, post) = if args1.len() > 0 { ("<", ">") } else { ("", "") }; + values.0.push_normal(format!( + "{pre}{}{post}", + args1.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ") + )); + let (pre, post) = if args2.len() > 0 { ("<", ">") } else { ("", "") }; + values.1.push_normal(format!( + "{pre}{}{post}", + args2.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ") + )); + return values; + } + + if args1.len() > 0 { + values.0.push_normal("<"); + values.1.push_normal("<"); + } + for (i, (a, b)) in std::iter::zip(args1, args2).enumerate() { + let a_str = a.to_string(); + let b_str = b.to_string(); + if let (Some(a), Some(b)) = (a.as_type(), b.as_type()) { + let (a, b) = self.cmp(a, b); + values.0.0.extend(a.0); + values.1.0.extend(b.0); + } else if a_str != b_str { + values.0.push_highlighted(a_str); + values.1.push_highlighted(b_str); + } else { + values.0.push_normal(a_str); + values.1.push_normal(b_str); + } + if i + 1 < args1.len() { + values.0.push_normal(", "); + values.1.push_normal(", "); + } + } + if args1.len() > 0 { + values.0.push_normal(">"); + values.1.push_normal(">"); + } + values + } + /// Compares two given types, eliding parts that are the same between them and highlighting /// relevant differences, and return two representation of those types for highlighted printing. pub fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagStyledString, DiagStyledString) { 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 7aa558cfd3f..f5cd99222e3 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 @@ -6,8 +6,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, StringPart, Suggestions, pluralize, - struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions, + pluralize, struct_span_code_err, }; use rustc_hir::def::Namespace; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -328,6 +328,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } else if let Some(custom_explanation) = safe_transmute_explanation { err.span_label(span, custom_explanation); + } else if explanation.len() > self.tcx.sess.diagnostic_width() { + // Really long types don't look good as span labels, instead move it + // to a `help`. + err.span_label(span, "unsatisfied trait bound"); + err.help(explanation); } else { err.span_label(span, explanation); } @@ -533,7 +538,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { - // FIXME(effects): We should recompute the predicate with `~const` + // FIXME(const_trait_impl): We should recompute the predicate with `~const` // if it's `const`, and if it holds, explain that this bound only // *conditionally* holds. If that fails, we should also do selection // to drill this down to an impl or built-in source, so we can @@ -1832,21 +1837,81 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if impl_trait_ref.references_error() { return false; } - let self_ty = impl_trait_ref.self_ty().to_string(); - err.highlighted_help(vec![ - StringPart::normal(format!( - "the trait `{}` ", - impl_trait_ref.print_trait_sugared() - )), - StringPart::highlighted("is"), + + if let [child, ..] = &err.children[..] + && child.level == Level::Help + && let Some(line) = child.messages.get(0) + && let Some(line) = line.0.as_str() + && line.starts_with("the trait") + && line.contains("is not implemented for") + { + // HACK(estebank): we remove the pre-existing + // "the trait `X` is not implemented for" note, which only happens if there + // was a custom label. We do this because we want that note to always be the + // first, and making this logic run earlier will get tricky. For now, we + // instead keep the logic the same and modify the already constructed error + // to avoid the wording duplication. + err.children.remove(0); + } + + let traits = self.cmp_traits( + obligation_trait_ref.def_id, + &obligation_trait_ref.args[1..], + impl_trait_ref.def_id, + &impl_trait_ref.args[1..], + ); + let traits_content = (traits.0.content(), traits.1.content()); + let types = self.cmp(obligation_trait_ref.self_ty(), impl_trait_ref.self_ty()); + let types_content = (types.0.content(), types.1.content()); + let mut msg = vec![StringPart::normal("the trait `")]; + if traits_content.0 == traits_content.1 { + msg.push(StringPart::normal( + impl_trait_ref.print_trait_sugared().to_string(), + )); + } else { + msg.extend(traits.0.0); + } + msg.extend([ + StringPart::normal("` "), + StringPart::highlighted("is not"), StringPart::normal(" implemented for `"), - if let [TypeError::Sorts(_)] = &terrs[..] { - StringPart::normal(self_ty) - } else { - StringPart::highlighted(self_ty) - }, - StringPart::normal("`"), ]); + if types_content.0 == types_content.1 { + let ty = + self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None); + msg.push(StringPart::normal(ty)); + } else { + msg.extend(types.0.0); + } + msg.push(StringPart::normal("`")); + if types_content.0 == types_content.1 { + msg.push(StringPart::normal("\nbut trait `")); + msg.extend(traits.1.0); + msg.extend([ + StringPart::normal("` "), + StringPart::highlighted("is"), + StringPart::normal(" implemented for it"), + ]); + } else if traits_content.0 == traits_content.1 { + msg.extend([ + StringPart::normal("\nbut it "), + StringPart::highlighted("is"), + StringPart::normal(" implemented for `"), + ]); + msg.extend(types.1.0); + msg.push(StringPart::normal("`")); + } else { + msg.push(StringPart::normal("\nbut trait `")); + msg.extend(traits.1.0); + msg.extend([ + StringPart::normal("` "), + StringPart::highlighted("is"), + StringPart::normal(" implemented for `"), + ]); + msg.extend(types.1.0); + msg.push(StringPart::normal("`")); + } + err.highlighted_help(msg); if let [TypeError::Sorts(exp_found)] = &terrs[..] { let exp_found = self.resolve_vars_if_possible(*exp_found); @@ -2475,12 +2540,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && self.tcx.trait_impls_of(trait_def_id).is_empty() && !self.tcx.trait_is_auto(trait_def_id) && !self.tcx.trait_is_alias(trait_def_id) + && trait_predicate.polarity() == ty::PredicatePolarity::Positive { err.span_help( self.tcx.def_span(trait_def_id), crate::fluent_generated::trait_selection_trait_has_no_impls, ); - } else if !suggested && !unsatisfied_const { + } else if !suggested + && !unsatisfied_const + && trait_predicate.polarity() == ty::PredicatePolarity::Positive + { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( @@ -2572,7 +2641,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _span: Span, ) -> UnsatisfiedConst { let unsatisfied_const = UnsatisfiedConst(false); - // FIXME(effects) + // FIXME(const_trait_impl) unsatisfied_const } @@ -2983,7 +3052,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // 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) + // FIXME(const_trait_impl) let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); let obligation = Obligation::new( self.tcx, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 553bb61ed04..e155effa1e3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -6,6 +6,7 @@ use std::iter; use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; +use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; @@ -38,7 +39,6 @@ use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, ExpnKind, MacroKind, Span}; -use rustc_target::spec::abi; use tracing::{debug, instrument}; use super::{ @@ -1916,7 +1916,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infcx.next_ty_var(DUMMY_SP), false, hir::Safety::Safe, - abi::Abi::Rust, + ExternAbi::Rust, ) } _ => infcx.tcx.mk_fn_sig( @@ -1924,7 +1924,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infcx.next_ty_var(DUMMY_SP), false, hir::Safety::Safe, - abi::Abi::Rust, + ExternAbi::Rust, ), }; @@ -3563,17 +3563,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )]); } ObligationCauseCode::OpaqueReturnType(expr_info) => { - if let Some((expr_ty, hir_id)) = expr_info { - let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file); - let expr = self.infcx.tcx.hir().expect_expr(hir_id); - err.span_label( - expr.span, - with_forced_trimmed_paths!(format!( - "return type was inferred to be `{expr_ty}` here", - )), - ); - suggest_remove_deref(err, &expr); - } + let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { + let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file); + let expr = tcx.hir().expect_expr(hir_id); + (expr_ty, expr) + } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() + && let body = tcx.hir().body(body_id) + && let hir::ExprKind::Block(block, _) = body.value.kind + && let Some(expr) = block.expr + && let Some(expr_ty) = self + .typeck_results + .as_ref() + .and_then(|typeck| typeck.node_type_opt(expr.hir_id)) + && let Some(pred) = predicate.as_clause() + && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() + && self.can_eq(param_env, pred.self_ty(), expr_ty) + { + let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file); + (expr_ty, expr) + } else { + return; + }; + err.span_label( + expr.span, + with_forced_trimmed_paths!(format!( + "return type was inferred to be `{expr_ty}` here", + )), + ); + suggest_remove_deref(err, &expr); } } } @@ -3680,6 +3697,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { + if trait_pred.polarity() == ty::PredicatePolarity::Negative { + return; + } let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { return; }; @@ -3731,7 +3751,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred.skip_binder().self_ty(), diagnostic_name, ), - // FIXME(effects, const_trait_impl) derive_const as suggestion? + // FIXME(const_trait_impl) derive_const as suggestion? format!("#[derive({diagnostic_name})]\n"), Applicability::MaybeIncorrect, ); @@ -3976,7 +3996,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let [self_ty, found_ty] = trait_ref.args.as_slice() && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn()) && let fn_sig @ ty::FnSig { - abi: abi::Abi::Rust, + abi: ExternAbi::Rust, c_variadic: false, safety: hir::Safety::Safe, .. diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 0eaacbcfbea..c00246cfd7d 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -7,6 +7,7 @@ use std::iter; use std::ops::ControlFlow; +use rustc_abi::BackendRepr; use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -18,7 +19,6 @@ use rustc_middle::ty::{ }; use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_target::abi::BackendRepr; use smallvec::SmallVec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 29e60e3c428..e3d17a910cc 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -374,7 +374,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) - // FIXME(effects): We may need to do this using the higher-ranked + // FIXME(const_trait_impl): We may need to do this using the higher-ranked // pred instead of just instantiating it with placeholders b/c of // higher-ranked implied bound issues in the old solver. | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 03fde1d1598..bf3f83ec827 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1170,8 +1170,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - // FIXME(effects): Destruct is not const yet, and it is implemented - // by all types today in non-const setting. candidates.vec.push(BuiltinCandidate { has_nested: false }); } |
