summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/astconv/errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/astconv/errors.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs123
1 files changed, 84 insertions, 39 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index c49e4d9d5..113c3f08a 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -1,10 +1,14 @@
use crate::astconv::AstConv;
-use crate::errors::{ManualImplementation, MissingTypeParams};
+use crate::errors::{
+ AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
+ ParenthesizedFnTraitExpansion,
+};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::FulfillmentError;
+use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
@@ -51,7 +55,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let trait_def = self.tcx().trait_def(trait_def_id);
if !trait_def.paren_sugar {
- if trait_segment.args().parenthesized {
+ if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar {
// For now, require that parenthetical notation be used only with `Fn()` etc.
let mut err = feature_err(
&self.tcx().sess.parse_sess,
@@ -67,7 +71,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let sess = self.tcx().sess;
- if !trait_segment.args().parenthesized {
+ if trait_segment.args().parenthesized != hir::GenericArgsParentheses::ParenSugar {
// For now, require that parenthetical notation be used only with `Fn()` etc.
let mut err = feature_err(
&sess.parse_sess,
@@ -78,43 +82,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Do not suggest the other syntax if we are in trait impl:
// the desugaring would contain an associated type constraint.
if !is_impl {
- let args = trait_segment
- .args
- .as_ref()
- .and_then(|args| args.args.get(0))
- .and_then(|arg| match arg {
- hir::GenericArg::Type(ty) => match ty.kind {
- hir::TyKind::Tup(t) => t
- .iter()
- .map(|e| sess.source_map().span_to_snippet(e.span))
- .collect::<Result<Vec<_>, _>>()
- .map(|a| a.join(", ")),
- _ => sess.source_map().span_to_snippet(ty.span),
- }
- .map(|s| format!("({})", s))
- .ok(),
- _ => None,
- })
- .unwrap_or_else(|| "()".to_string());
- let ret = trait_segment
- .args()
- .bindings
- .iter()
- .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
- (true, hir::TypeBindingKind::Equality { term }) => {
- let span = match term {
- hir::Term::Ty(ty) => ty.span,
- hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
- };
- sess.source_map().span_to_snippet(span).ok()
- }
- _ => None,
- })
- .unwrap_or_else(|| "()".to_string());
err.span_suggestion(
span,
"use parenthetical notation instead",
- format!("{}{} -> {}", trait_segment.ident, args, ret),
+ fn_trait_to_string(self.tcx(), trait_segment, true),
Applicability::MaybeIncorrect,
);
}
@@ -512,8 +483,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
[segment] if segment.args.is_none() => {
trait_bound_spans = vec![segment.ident.span];
associated_types = associated_types
- .into_iter()
- .map(|(_, items)| (segment.ident.span, items))
+ .into_values()
+ .map(|items| (segment.ident.span, items))
.collect();
}
_ => {}
@@ -629,3 +600,77 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.emit();
}
}
+
+/// Emits an error regarding forbidden type binding associations
+pub fn prohibit_assoc_ty_binding(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ segment: Option<(&hir::PathSegment<'_>, Span)>,
+) {
+ tcx.sess.emit_err(AssocTypeBindingNotAllowed {
+ span,
+ fn_trait_expansion: if let Some((segment, span)) = segment
+ && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
+ {
+ Some(ParenthesizedFnTraitExpansion {
+ span,
+ expanded_type: fn_trait_to_string(tcx, segment, false),
+ })
+ } else {
+ None
+ },
+ });
+}
+
+pub(crate) fn fn_trait_to_string(
+ tcx: TyCtxt<'_>,
+ trait_segment: &hir::PathSegment<'_>,
+ parenthesized: bool,
+) -> String {
+ let args = trait_segment
+ .args
+ .as_ref()
+ .and_then(|args| args.args.get(0))
+ .and_then(|arg| match arg {
+ hir::GenericArg::Type(ty) => match ty.kind {
+ hir::TyKind::Tup(t) => t
+ .iter()
+ .map(|e| tcx.sess.source_map().span_to_snippet(e.span))
+ .collect::<Result<Vec<_>, _>>()
+ .map(|a| a.join(", ")),
+ _ => tcx.sess.source_map().span_to_snippet(ty.span),
+ }
+ .map(|s| {
+ // `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma
+ if parenthesized || s.is_empty() { format!("({})", s) } else { format!("({},)", s) }
+ })
+ .ok(),
+ _ => None,
+ })
+ .unwrap_or_else(|| "()".to_string());
+
+ let ret = trait_segment
+ .args()
+ .bindings
+ .iter()
+ .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
+ (true, hir::TypeBindingKind::Equality { term }) => {
+ let span = match term {
+ hir::Term::Ty(ty) => ty.span,
+ hir::Term::Const(c) => tcx.hir().span(c.hir_id),
+ };
+
+ (span != tcx.hir().span(trait_segment.hir_id))
+ .then_some(tcx.sess.source_map().span_to_snippet(span).ok())
+ .flatten()
+ }
+ _ => None,
+ })
+ .unwrap_or_else(|| "()".to_string());
+
+ if parenthesized {
+ format!("{}{} -> {}", trait_segment.ident, args, ret)
+ } else {
+ format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
+ }
+}