1
Fork 0

Auto merge of #106215 - matthiaskrgr:rollup-53r89ww, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #106028 (docs/test: add UI test and long-form error docs for `E0461`)
 - #106172 (Suggest `impl Iterator` when possible for `_` return type)
 - #106173 (Deduplicate `op` methods)
 - #106176 (Recover `fn` keyword as `Fn` trait in bounds)
 - #106194 (rustdoc: combine common sidebar background color CSS rules)
 - #106199 (Silence knock-down errors on `[type error]` bindings)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-12-28 17:00:00 +00:00
commit 270c94e484
36 changed files with 502 additions and 397 deletions

View file

@ -244,6 +244,7 @@ E0457: include_str!("./error_codes/E0457.md"),
E0458: include_str!("./error_codes/E0458.md"),
E0459: include_str!("./error_codes/E0459.md"),
E0460: include_str!("./error_codes/E0460.md"),
E0461: include_str!("./error_codes/E0461.md"),
E0462: include_str!("./error_codes/E0462.md"),
E0463: include_str!("./error_codes/E0463.md"),
E0464: include_str!("./error_codes/E0464.md"),
@ -595,7 +596,6 @@ E0791: include_str!("./error_codes/E0791.md"),
// E0421, // merged into 531
// E0427, // merged into 530
// E0456, // plugin `..` is not available for triple `..`
E0461, // couldn't find crate `..` with expected target triple ..
E0465, // multiple .. candidates for `..` found
// E0467, // removed
// E0470, // removed

View file

@ -0,0 +1,30 @@
Couldn't find crate `..` with expected target triple `..`.
Example of erroneous code:
`a.rs`
```ignore (cannot-link-with-other-tests)
#![crate_type = "lib"]
fn foo() {}
```
`main.rs`
```ignore (cannot-link-with-other-tests)
extern crate a;
fn main() {
a::foo();
}
```
`a.rs` is then compiled with `--target powerpc-unknown-linux-gnu` and `b.rs`
with `--target x86_64-unknown-linux-gnu`. `a.rs` is compiled into a binary
format incompatible with `b.rs`; PowerPC and x86 are totally different
architectures. This issue also extends to any difference in target triples, as
`std` is operating-system specific.
This error can be fixed by:
* Using [Cargo](../cargo/index.html), the Rust package manager, automatically
fixing this issue.
* Recompiling either crate so that they target a consistent target triple.

View file

@ -365,3 +365,6 @@ parse_invalid_identifier_with_leading_number = expected identifier, found number
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
.suggestion = replace `fn` with `impl` here
parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
.suggestion = use `Fn` to refer to the trait

View file

@ -626,7 +626,7 @@ impl<'a> ExtCtxt<'a> {
// Builds `#[name = val]`.
//
// Note: `span` is used for both the identifer and the value.
// Note: `span` is used for both the identifier and the value.
pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.parse_sess.attr_id_generator;
attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)

View file

@ -24,6 +24,8 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
@ -31,7 +33,9 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyC
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
mod generics_of;
@ -1224,7 +1228,17 @@ fn infer_return_ty_for_fn_sig<'tcx>(
// to prevent the user from getting a papercut while trying to use the unique closure
// syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
diag.note(
"for more information on `Fn` traits and closure types, see \
https://doc.rust-lang.org/book/ch13-01-closures.html",
);
} else if let Some(i_ty) = suggest_impl_iterator(tcx, ret_ty, ty.span, hir_id, def_id) {
diag.span_suggestion(
ty.span,
"replace with an appropriate return type",
format!("impl Iterator<Item = {}>", i_ty),
Applicability::MachineApplicable,
);
}
diag.emit();
@ -1242,6 +1256,51 @@ fn infer_return_ty_for_fn_sig<'tcx>(
}
}
fn suggest_impl_iterator<'tcx>(
tcx: TyCtxt<'tcx>,
ret_ty: Ty<'tcx>,
span: Span,
hir_id: hir::HirId,
def_id: LocalDefId,
) -> Option<Ty<'tcx>> {
let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) else { return None; };
let Some(iterator_item) = tcx.get_diagnostic_item(sym::IteratorItem) else { return None; };
if !tcx
.infer_ctxt()
.build()
.type_implements_trait(iter_trait, [ret_ty], tcx.param_env(def_id))
.must_apply_modulo_regions()
{
return None;
}
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
// Find the type of `Iterator::Item`.
let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
let ty_var = infcx.next_ty_var(origin);
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
ty::ProjectionPredicate {
projection_ty: tcx.mk_alias_ty(iterator_item, tcx.mk_substs([ret_ty.into()].iter())),
term: ty_var.into(),
},
)));
// Add `<ret_ty as Iterator>::Item = _` obligation.
ocx.register_obligation(crate::traits::Obligation::misc(
tcx,
span,
hir_id,
tcx.param_env(def_id),
projection,
));
if ocx.select_where_possible().is_empty()
&& let item_ty = infcx.resolve_vars_if_possible(ty_var)
&& item_ty.is_suggestable(tcx, false)
{
return Some(item_ty);
}
None
}
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id.expect_local());

View file

@ -5,6 +5,7 @@ use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
@ -907,10 +908,10 @@ fn infer_placeholder_type<'a>(
Applicability::MachineApplicable,
);
} else {
err.span_note(
with_forced_trimmed_paths!(err.span_note(
tcx.hir().body(body_id).value.span,
&format!("however, the inferred type `{}` cannot be named", ty),
);
&format!("however, the inferred type `{ty}` cannot be named"),
));
}
}
@ -931,10 +932,10 @@ fn infer_placeholder_type<'a>(
Applicability::MaybeIncorrect,
);
} else {
diag.span_note(
with_forced_trimmed_paths!(diag.span_note(
tcx.hir().body(body_id).value.span,
&format!("however, the inferred type `{}` cannot be named", ty),
);
&format!("however, the inferred type `{ty}` cannot be named"),
));
}
}

View file

@ -241,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
if let Some(ok) = self.lookup_method_in_trait(
call_expr.span,
self.misc(call_expr.span),
method_name,
trait_def_id,
adjusted_ty,

View file

@ -1307,7 +1307,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type check the initializer.
if let Some(ref init) = decl.init {
let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty);
}
// Does the expected pattern type originate from an expression and what is the span?
@ -1322,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type check the pattern. Override if necessary to avoid knock-on errors.
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
let pat_ty = self.node_ty(decl.pat.hir_id);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
if let Some(blk) = decl.els {
let previous_diverges = self.diverges.get();
@ -1627,14 +1627,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
hir_id: hir::HirId,
pat: &'tcx hir::Pat<'tcx>,
decl_ty: Ty<'tcx>,
ty: Ty<'tcx>,
) {
if ty.references_error() {
// Override the types everywhere with `err()` to avoid knock on errors.
self.write_ty(hir_id, ty);
self.write_ty(pat.hir_id, ty);
let local_ty = LocalTy { decl_ty, revealed_ty: ty };
let err = self.tcx.ty_error();
self.write_ty(hir_id, err);
self.write_ty(pat.hir_id, err);
let local_ty = LocalTy { decl_ty: err, revealed_ty: err };
self.locals.borrow_mut().insert(hir_id, local_ty);
self.locals.borrow_mut().insert(pat.hir_id, local_ty);
}

View file

@ -11,7 +11,7 @@ pub use self::suggest::SelfSource;
pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams;
use crate::{Expectation, FnCtxt};
use crate::FnCtxt;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn obligation_for_method(
&self,
span: Span,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
@ -282,71 +282,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
self.var_for_def(span, param)
self.var_for_def(cause.span, param)
});
let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
(
traits::Obligation::misc(
self.tcx,
span,
self.body_id,
self.param_env,
poly_trait_ref.without_const(),
),
substs,
)
}
pub(super) fn obligation_for_op_method(
&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_type: Option<Ty<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
expected: Expectation<'tcx>,
) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
{
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
GenericParamDefKind::Type { .. } => {
if param.index == 0 {
return self_ty.into();
} else if let Some(input_type) = opt_input_type {
return input_type.into();
}
}
}
self.var_for_def(span, param)
});
let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
(
traits::Obligation::new(
self.tcx,
traits::ObligationCause::new(
span,
self.body_id,
traits::BinOp {
rhs_span: opt_input_expr.map(|expr| expr.span),
is_lit: opt_input_expr
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty,
},
),
cause,
self.param_env,
poly_trait_ref,
poly_trait_ref.without_const(),
),
substs,
)
@ -357,55 +305,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// In particular, it doesn't really do any probing: it simply constructs
/// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented.
#[instrument(level = "debug", skip(self, span))]
#[instrument(level = "debug", skip(self))]
pub(super) fn lookup_method_in_trait(
&self,
span: Span,
cause: ObligationCause<'tcx>,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) =
self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(
span,
m_name,
trait_def_id,
obligation,
substs,
None,
false,
)
}
pub(super) fn lookup_op_method_in_trait(
&self,
span: Span,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_type: Option<Ty<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
expected: Expectation<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) = self.obligation_for_op_method(
span,
trait_def_id,
self_ty,
opt_input_type,
opt_input_expr,
expected,
);
self.construct_obligation_for_trait(
span,
m_name,
trait_def_id,
obligation,
substs,
opt_input_expr,
true,
)
self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
}
// FIXME(#18741): it seems likely that we can consolidate some of this
@ -413,13 +324,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// of this method is basically the same as confirmation.
fn construct_obligation_for_trait(
&self,
span: Span,
m_name: Ident,
trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>,
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
is_op: bool,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation);
@ -435,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
tcx.sess.delay_span_bug(
span,
obligation.cause.span,
"operator trait does not have corresponding operator method",
);
return None;
@ -461,24 +369,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// with bound regions.
let fn_sig = tcx.bound_fn_sig(def_id);
let fn_sig = fn_sig.subst(self.tcx, substs);
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
let fn_sig =
self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
let cause = if is_op {
ObligationCause::new(
span,
self.body_id,
traits::BinOp {
rhs_span: opt_input_expr.map(|expr| expr.span),
is_lit: opt_input_expr
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: None,
},
)
} else {
traits::ObligationCause::misc(span, self.body_id)
};
let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
@ -494,7 +389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(bounds);
let bounds = {
obligations.extend(o);
value
@ -502,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
assert!(!bounds.has_escaping_bound_vars());
let predicates_cause = cause.clone();
let predicates_cause = obligation.cause.clone();
obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(),
self.param_env,
@ -517,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
obligations.push(traits::Obligation::new(
tcx,
cause,
obligation.cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
));

View file

@ -12,14 +12,16 @@ use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
use rustc_middle::ty::{
self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::FulfillmentError;
use rustc_trait_selection::traits::{self, FulfillmentError};
use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -48,8 +50,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self
.lookup_op_method(
lhs_deref_ty,
Some(rhs_ty),
Some(rhs),
Some((rhs, rhs_ty)),
Op::Binary(op, IsAssign::Yes),
expected,
)
@ -60,8 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self
.lookup_op_method(
lhs_ty,
Some(rhs_ty),
Some(rhs),
Some((rhs, rhs_ty)),
Op::Binary(op, IsAssign::Yes),
expected,
)
@ -248,8 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let result = self.lookup_op_method(
lhs_ty,
Some(rhs_ty_var),
Some(rhs_expr),
Some((rhs_expr, rhs_ty_var)),
Op::Binary(op, is_assign),
expected,
);
@ -382,8 +381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self
.lookup_op_method(
lhs_deref_ty,
Some(rhs_ty),
Some(rhs_expr),
Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
@ -410,8 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let is_compatible = |lhs_ty, rhs_ty| {
self.lookup_op_method(
lhs_ty,
Some(rhs_ty),
Some(rhs_expr),
Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
@ -471,8 +468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let errors = self
.lookup_op_method(
lhs_ty,
Some(rhs_ty),
Some(rhs_expr),
Some((rhs_expr, rhs_ty)),
Op::Binary(op, is_assign),
expected,
)
@ -492,6 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(output_def_id) = output_def_id
&& let Some(trait_def_id) = trait_def_id
&& self.tcx.parent(output_def_id) == trait_def_id
&& output_ty.is_suggestable(self.tcx, false)
{
Some(("Output", *output_ty))
} else {
@ -625,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
assert!(op.is_by_value());
match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) {
match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) {
Ok(method) => {
self.write_method_call(ex.hir_id, method);
method.sig.output()
@ -712,8 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn lookup_op_method(
&self,
lhs_ty: Ty<'tcx>,
other_ty: Option<Ty<'tcx>>,
other_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>,
op: Op,
expected: Expectation<'tcx>,
) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
@ -742,20 +738,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Op::Unary(..) => 0,
},
) {
self.tcx
.sess
.delay_span_bug(span, "operator didn't have the right number of generic args");
return Err(vec![]);
}
let opname = Ident::with_dummy_span(opname);
let input_types =
opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default();
let cause = self.cause(
span,
traits::BinOp {
rhs_span: opt_rhs.map(|(expr, _)| expr.span),
is_lit: opt_rhs
.map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: expected.only_has_type(self),
},
);
let method = trait_did.and_then(|trait_did| {
self.lookup_op_method_in_trait(
span,
opname,
trait_did,
lhs_ty,
other_ty,
other_ty_expr,
expected,
)
self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
});
match (method, trait_did) {
@ -766,14 +769,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
(None, None) => Err(vec![]),
(None, Some(trait_did)) => {
let (obligation, _) = self.obligation_for_op_method(
span,
trait_did,
lhs_ty,
other_ty,
other_ty_expr,
expected,
);
let (obligation, _) =
self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
}
}

View file

@ -225,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
imm_tr.and_then(|trait_did| {
self.lookup_method_in_trait(
span,
self.misc(span),
Ident::with_dummy_span(imm_op),
trait_did,
base_ty,
@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mut_tr.and_then(|trait_did| {
self.lookup_method_in_trait(
span,
self.misc(span),
Ident::with_dummy_span(mut_op),
trait_did,
base_ty,

View file

@ -851,7 +851,7 @@ impl Cursor<'_> {
}
// Eats the identifier. Note: succeeds on `_`, which isn't a valid
// identifer.
// identifier.
fn eat_identifier(&mut self) {
if !is_id_start(self.first()) {
return;

View file

@ -1229,3 +1229,11 @@ pub(crate) struct FnTypoWithImpl {
#[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")]
pub fn_span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_expected_fn_path_found_fn_keyword)]
pub(crate) struct ExpectedFnPathFoundFnKeyword {
#[primary_span]
#[suggestion(applicability = "machine-applicable", code = "Fn", style = "verbose")]
pub fn_token_span: Span,
}

View file

@ -1,8 +1,9 @@
use super::{Parser, PathStyle, TokenType};
use crate::errors::{FnPtrWithGenerics, FnPtrWithGenericsSugg};
use crate::errors::{ExpectedFnPathFoundFnKeyword, FnPtrWithGenerics, FnPtrWithGenericsSugg};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use ast::DUMMY_NODE_ID;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case;
@ -12,7 +13,9 @@ use rustc_ast::{
};
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use thin_vec::thin_vec;
/// Any `?` or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers {
@ -931,7 +934,14 @@ impl<'a> Parser<'a> {
modifiers: BoundModifiers,
) -> PResult<'a, GenericBound> {
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
let path = self.parse_path(PathStyle::Type)?;
let path = if self.token.is_keyword(kw::Fn)
&& self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
&& let Some(path) = self.recover_path_from_fn()
{
path
} else {
self.parse_path(PathStyle::Type)?
};
if has_parens {
if self.token.is_like_plus() {
// Someone has written something like `&dyn (Trait + Other)`. The correct code
@ -960,6 +970,38 @@ impl<'a> Parser<'a> {
Ok(GenericBound::Trait(poly_trait, modifier))
}
// recovers a `Fn(..)` parenthesized-style path from `fn(..)`
fn recover_path_from_fn(&mut self) -> Option<ast::Path> {
let fn_token_span = self.token.span;
self.bump();
let args_lo = self.token.span;
let snapshot = self.create_snapshot_for_diagnostic();
match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) {
Ok(decl) => {
self.sess.emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });
Some(ast::Path {
span: fn_token_span.to(self.prev_token.span),
segments: thin_vec![ast::PathSegment {
ident: Ident::new(Symbol::intern("Fn"), fn_token_span),
id: DUMMY_NODE_ID,
args: Some(P(ast::GenericArgs::Parenthesized(ast::ParenthesizedArgs {
span: args_lo.to(self.prev_token.span),
inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(),
inputs_span: args_lo.until(decl.output.span()),
output: decl.output.clone(),
}))),
}],
tokens: None,
})
}
Err(diag) => {
diag.cancel();
self.restore_snapshot(snapshot);
None
}
}
}
/// Optionally parses `for<$generic_params>`.
pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> {
if self.eat_keyword(kw::For) {

View file

@ -213,6 +213,7 @@ symbols! {
Is,
ItemContext,
Iterator,
IteratorItem,
Layout,
Left,
LinkedList,