diff options
Diffstat (limited to 'compiler')
34 files changed, 348 insertions, 240 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index d05559e9244..e6d26240e24 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -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 diff --git a/compiler/rustc_error_codes/src/error_codes/E0461.md b/compiler/rustc_error_codes/src/error_codes/E0461.md new file mode 100644 index 00000000000..33105c43ccf --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0461.md @@ -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. diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index b53550e5fd5..3401978caf5 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -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 diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index ef50efb8125..406e1569a6f 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -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) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 197f056917f..40aa64d9d40 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -43,7 +43,7 @@ pub(super) fn failed_to_match_macro<'cx>( return result; } - let Some((token, label, remaining_matcher)) = tracker.best_failure else { + let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else { return DummyResult::any(sp); }; @@ -95,11 +95,24 @@ struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> { cx: &'a mut ExtCtxt<'cx>, remaining_matcher: Option<&'matcher MatcherLoc>, /// Which arm's failure should we report? (the one furthest along) - best_failure: Option<(Token, &'static str, MatcherLoc)>, + best_failure: Option<BestFailure>, root_span: Span, result: Option<Box<dyn MacResult + 'cx>>, } +struct BestFailure { + token: Token, + position_in_tokenstream: usize, + msg: &'static str, + remaining_matcher: MatcherLoc, +} + +impl BestFailure { + fn is_better_position(&self, position: usize) -> bool { + position > self.position_in_tokenstream + } +} + impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> { fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) { if self.remaining_matcher.is_none() @@ -119,18 +132,25 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, "should not collect detailed info for successful macro match", ); } - Failure(token, msg) => match self.best_failure { - Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {} - _ => { - self.best_failure = Some(( - token.clone(), + Failure(token, approx_position, msg) => { + debug!(?token, ?msg, "a new failure of an arm"); + + if self + .best_failure + .as_ref() + .map_or(true, |failure| failure.is_better_position(*approx_position)) + { + self.best_failure = Some(BestFailure { + token: token.clone(), + position_in_tokenstream: *approx_position, msg, - self.remaining_matcher + remaining_matcher: self + .remaining_matcher .expect("must have collected matcher already") .clone(), - )) + }) } - }, + } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); self.cx.struct_span_err(span, msg).emit(); diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index d161868edce..df1c1834c1d 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -310,7 +310,8 @@ pub(crate) enum ParseResult<T> { Success(T), /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected /// end of macro invocation. Otherwise, it indicates that no rules expected the given token. - Failure(Token, &'static str), + /// The usize is the approximate position of the token in the input token stream. + Failure(Token, usize, &'static str), /// Fatal error (malformed macro?). Abort compilation. Error(rustc_span::Span, String), ErrorReported(ErrorGuaranteed), @@ -455,6 +456,7 @@ impl TtParser { &mut self, matcher: &'matcher [MatcherLoc], token: &Token, + approx_position: usize, track: &mut T, ) -> Option<NamedParseResult> { // Matcher positions that would be valid if the macro invocation was over now. Only @@ -598,6 +600,7 @@ impl TtParser { token::Eof, if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() }, ), + approx_position, "missing tokens in macro arguments", ), }) @@ -627,7 +630,12 @@ impl TtParser { // Process `cur_mps` until either we have finished the input or we need to get some // parsing from the black-box parser done. - let res = self.parse_tt_inner(matcher, &parser.token, track); + let res = self.parse_tt_inner( + matcher, + &parser.token, + parser.approx_token_stream_pos(), + track, + ); if let Some(res) = res { return res; } @@ -642,6 +650,7 @@ impl TtParser { // parser: syntax error. return Failure( parser.token.clone(), + parser.approx_token_stream_pos(), "no rules expected this token in macro call", ); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 3e6bc81f672..fbb806fe81b 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -326,8 +326,8 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( return Ok((i, named_matches)); } - Failure(_, _) => { - trace!("Failed to match arm, trying the next one"); + Failure(_, reached_position, _) => { + trace!(%reached_position, "Failed to match arm, trying the next one"); // Try the next arm. } Error(_, _) => { @@ -432,7 +432,7 @@ pub fn compile_declarative_macro( let argument_map = match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) { Success(m) => m, - Failure(token, msg) => { + Failure(token, _, msg) => { let s = parse_failure_msg(&token); let sp = token.span.substitute_dummy(def.span); let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 87cc69757b0..28cd18bbb8e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,8 +1,8 @@ use crate::check::intrinsicck::InlineAsmCtxt; use crate::errors::LinkageType; -use super::compare_method::check_type_bounds; -use super::compare_method::{compare_impl_method, compare_ty_impl}; +use super::compare_impl_item::check_type_bounds; +use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; use super::*; use rustc_attr as attr; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; @@ -468,7 +468,7 @@ fn check_opaque_meets_bounds<'tcx>( // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias => { let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors( + let _ = infcx.check_region_obligations_and_report_errors( defining_use_anchor, &outlives_environment, ); @@ -774,7 +774,7 @@ fn check_impl_items_against_trait<'tcx>( let impl_item_full = tcx.hir().impl_item(impl_item.id); match impl_item_full.kind { hir::ImplItemKind::Const(..) => { - let _ = tcx.compare_assoc_const_impl_item_with_trait_item(( + let _ = tcx.compare_impl_const(( impl_item.id.owner_id.def_id, ty_impl_item.trait_item_def_id.unwrap(), )); @@ -791,7 +791,7 @@ fn check_impl_items_against_trait<'tcx>( } hir::ImplItemKind::Type(impl_ty) => { let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - compare_ty_impl( + compare_impl_ty( tcx, &ty_impl_item, impl_ty.span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index c6bda9b4641..a767338ab85 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -34,7 +34,7 @@ use std::iter; /// - `impl_m_span`: span to use for reporting errors /// - `trait_m`: the method in the trait /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation -pub(crate) fn compare_impl_method<'tcx>( +pub(super) fn compare_impl_method<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &ty::AssocItem, trait_m: &ty::AssocItem, @@ -71,7 +71,7 @@ pub(crate) fn compare_impl_method<'tcx>( return; } - if let Err(_) = compare_predicate_entailment( + if let Err(_) = compare_method_predicate_entailment( tcx, impl_m, impl_m_span, @@ -150,7 +150,7 @@ pub(crate) fn compare_impl_method<'tcx>( /// Finally we register each of these predicates as an obligation and check that /// they hold. #[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))] -fn compare_predicate_entailment<'tcx>( +fn compare_method_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &ty::AssocItem, impl_m_span: Span, @@ -337,7 +337,7 @@ fn compare_predicate_entailment<'tcx>( if !errors.is_empty() { match check_implied_wf { CheckImpliedWfMode::Check => { - return compare_predicate_entailment( + return compare_method_predicate_entailment( tcx, impl_m, impl_m_span, @@ -374,7 +374,7 @@ fn compare_predicate_entailment<'tcx>( // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` match check_implied_wf { CheckImpliedWfMode::Check => { - return compare_predicate_entailment( + return compare_method_predicate_entailment( tcx, impl_m, impl_m_span, @@ -407,7 +407,7 @@ enum CheckImpliedWfMode { /// re-check with `Skip`, and emit a lint if it succeeds. Check, /// Skips checking implied well-formedness of the impl method, but will emit - /// a lint if the `compare_predicate_entailment` succeeded. This means that + /// a lint if the `compare_method_predicate_entailment` succeeded. This means that /// the reason that we had failed earlier during `Check` was due to the impl /// having stronger requirements than the trait. Skip, @@ -441,8 +441,41 @@ fn compare_asyncness<'tcx>( Ok(()) } +/// Given a method def-id in an impl, compare the method signature of the impl +/// against the trait that it's implementing. In doing so, infer the hidden types +/// that this method's signature provides to satisfy each return-position `impl Trait` +/// in the trait signature. +/// +/// The method is also responsible for making sure that the hidden types for each +/// RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer +/// `impl Trait = Foo`, that `Foo: Trait` holds. +/// +/// For example, given the sample code: +/// +/// ``` +/// #![feature(return_position_impl_trait_in_trait)] +/// +/// use std::ops::Deref; +/// +/// trait Foo { +/// fn bar() -> impl Deref<Target = impl Sized>; +/// // ^- RPITIT #1 ^- RPITIT #2 +/// } +/// +/// impl Foo for () { +/// fn bar() -> Box<String> { Box::new(String::new()) } +/// } +/// ``` +/// +/// The hidden types for the RPITITs in `bar` would be inferred to: +/// * `impl Deref` (RPITIT #1) = `Box<String>` +/// * `impl Sized` (RPITIT #2) = `String` +/// +/// The relationship between these two types is straightforward in this case, but +/// may be more tenuously connected via other `impl`s and normalization rules for +/// cases of more complicated nested RPITITs. #[instrument(skip(tcx), level = "debug", ret)] -pub fn collect_trait_impl_trait_tys<'tcx>( +pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> { @@ -550,13 +583,13 @@ pub fn collect_trait_impl_trait_tys<'tcx>( // Unify the whole function signature. We need to do this to fully infer // the lifetimes of the return type, but do this after unifying just the // return types, since we want to avoid duplicating errors from - // `compare_predicate_entailment`. + // `compare_method_predicate_entailment`. match ocx.eq(&cause, param_env, trait_fty, impl_fty) { Ok(()) => {} Err(terr) => { - // This function gets called during `compare_predicate_entailment` when normalizing a + // This function gets called during `compare_method_predicate_entailment` when normalizing a // signature that contains RPITIT. When the method signatures don't match, we have to - // emit an error now because `compare_predicate_entailment` will not report the error + // emit an error now because `compare_method_predicate_entailment` will not report the error // when normalization fails. let emitted = report_trait_method_mismatch( infcx, @@ -589,7 +622,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( infcx.check_region_obligations_and_report_errors( impl_m.def_id.expect_local(), &outlives_environment, - ); + )?; let mut collected_tys = FxHashMap::default(); for (def_id, (ty, substs)) in collector.types { @@ -1516,8 +1549,8 @@ fn compare_generic_param_kinds<'tcx>( Ok(()) } -/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead -pub(crate) fn raw_compare_const_impl( +/// Use `tcx.compare_impl_const` instead +pub(super) fn compare_impl_const_raw( tcx: TyCtxt<'_>, (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId), ) -> Result<(), ErrorGuaranteed> { @@ -1617,13 +1650,13 @@ pub(crate) fn raw_compare_const_impl( return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None)); } - // FIXME return `ErrorReported` if region obligations error? let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment); + infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?; + Ok(()) } -pub(crate) fn compare_ty_impl<'tcx>( +pub(super) fn compare_impl_ty<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: &ty::AssocItem, impl_ty_span: Span, @@ -1645,7 +1678,7 @@ pub(crate) fn compare_ty_impl<'tcx>( })(); } -/// The equivalent of [compare_predicate_entailment], but for associated types +/// The equivalent of [compare_method_predicate_entailment], but for associated types /// instead of associated functions. fn compare_type_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, @@ -1730,7 +1763,7 @@ fn compare_type_predicate_entailment<'tcx>( infcx.check_region_obligations_and_report_errors( impl_ty.def_id.expect_local(), &outlives_environment, - ); + )?; Ok(()) } @@ -1749,7 +1782,7 @@ fn compare_type_predicate_entailment<'tcx>( /// from the impl could be overridden). We also can't normalize generic /// associated types (yet) because they contain bound parameters. #[instrument(level = "debug", skip(tcx))] -pub fn check_type_bounds<'tcx>( +pub(super) fn check_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_ty: &ty::AssocItem, impl_ty: &ty::AssocItem, @@ -1944,7 +1977,7 @@ pub fn check_type_bounds<'tcx>( infcx.check_region_obligations_and_report_errors( impl_ty.def_id.expect_local(), &outlives_environment, - ); + )?; let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); for (key, value) in constraints { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index ed2aed293a7..382c3f52945 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -63,7 +63,7 @@ a type parameter). */ mod check; -mod compare_method; +mod compare_impl_item; pub mod dropck; pub mod intrinsic; pub mod intrinsicck; @@ -94,7 +94,7 @@ use std::num::NonZeroU32; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; -use self::compare_method::collect_trait_impl_trait_tys; +use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; pub fn provide(providers: &mut Providers) { @@ -103,8 +103,8 @@ pub fn provide(providers: &mut Providers) { adt_destructor, check_mod_item_types, region_scope_tree, - collect_trait_impl_trait_tys, - compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl, + collect_return_position_impl_trait_in_trait_tys, + compare_impl_const: compare_impl_item::compare_impl_const_raw, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4f27068429c..6cb899f5176 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -115,7 +115,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( let outlives_environment = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); - infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); + let _ = infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 2790d91572b..bfedf63da97 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -325,7 +325,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); + let _ = infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); } } _ => { @@ -565,7 +565,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); + let _ = infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); CoerceUnsizedInfo { custom_kind: kind } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b7d599f57fd..9e46968c408 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -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()); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index b678990f94e..4bd55a54831 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -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"), + )); } } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index ac60f085304..1aae9e0bd20 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -181,7 +181,7 @@ fn get_impl_substs( let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types); let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); - infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); + let _ = infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { let span = tcx.def_span(impl1_def_id); tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index af14ee08a99..829913d278d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -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, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 877680053f0..d342d96a10f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -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); } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index fddb8a458a7..b9b27e8627a 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -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) - }); - - 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) + 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); - 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 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 fn_sig = + self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); - 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())), )); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 9f0d175c4c6..34140f3e1fe 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -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)) } } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 952ea14887f..a0f048fc09b 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -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, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e5823660e3f..7222eb77682 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1836,7 +1836,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // In some (most?) cases cause.body_id points to actual body, but in some cases // it's an actual definition. According to the comments (e.g. in - // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter + // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter // is relied upon by some other code. This might (or might not) need cleanup. let body_owner_def_id = self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a9ef91db059..b17a465eb38 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1693,7 +1693,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Option<ErrorGuaranteed> { + ) -> Result<(), ErrorGuaranteed> { let errors = self.resolve_regions(outlives_env); if let None = self.tainted_by_errors() { @@ -1705,9 +1705,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.report_region_errors(generic_param_scope, &errors); } - (!errors.is_empty()).then(|| { - self.tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted") - }) + if errors.is_empty() { + Ok(()) + } else { + Err(self + .tcx + .sess + .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")) + } } // [Note-Type-error-reporting] diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 47bd1564f08..f71c39dc0d2 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Option<ErrorGuaranteed> { + ) -> Result<(), ErrorGuaranteed> { self.process_registered_region_obligations( outlives_env.region_bound_pairs(), outlives_env.param_env, diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 50d6d5b9bab..4c65fca29b8 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -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; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9d0ccfeb168..e167bbf57e6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -223,7 +223,7 @@ provide! { tcx, def_id, other, cdata, generator_kind => { table } trait_def => { table } deduced_param_attrs => { table } - collect_trait_impl_trait_tys => { + collect_return_position_impl_trait_in_trait_tys => { Ok(cdata .root .tables diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 65beb744cf8..214a5842233 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1197,7 +1197,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.params_in_repr[def_id] <- params_in_repr); } if should_encode_trait_impl_trait_tys(tcx, def_id) - && let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id) + && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ab512804330..37db2274f67 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -169,7 +169,7 @@ rustc_queries! { separate_provide_extern } - query collect_trait_impl_trait_tys(key: DefId) + query collect_return_position_impl_trait_in_trait_tys(key: DefId) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> { desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } @@ -2117,7 +2117,7 @@ rustc_queries! { desc { "checking to see if `{}` permits being left zeroed", key.ty } } - query compare_assoc_const_impl_item_with_trait_item( + query compare_impl_const( key: (LocalDefId, DefId) ) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 6d3b94c1fdb..cc53659f827 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -641,11 +641,11 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.type_of(def_id)) } - pub fn bound_trait_impl_trait_tys( + pub fn bound_return_position_impl_trait_in_trait_tys( self, def_id: DefId, ) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> { - ty::EarlyBinder(self.collect_trait_impl_trait_tys(def_id)) + ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id)) } pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> { diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 18a0bee9c2e..574591529f3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -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, +} diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 40b88788caa..919e71bd115 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1499,6 +1499,10 @@ impl<'a> Parser<'a> { pub fn clear_expected_tokens(&mut self) { self.expected_tokens.clear(); } + + pub fn approx_token_stream_pos(&self) -> usize { + self.token_cursor.num_next_calls + } } pub(crate) fn make_unclosed_delims_error( diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index fc26278909c..8661e9ca16b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -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) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index da37dab6a9c..c450c4da9a8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -213,6 +213,7 @@ symbols! { Is, ItemContext, Iterator, + IteratorItem, Layout, Left, LinkedList, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 5276da2e49c..f7614997585 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2284,7 +2284,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.param_env, cause.clone(), obligation.recursion_depth + 1, - tcx.bound_trait_impl_trait_tys(impl_fn_def_id) + tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id) .map_bound(|tys| { tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id]) }) diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 2da98d33429..8d46ba320fc 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -194,7 +194,7 @@ fn resolve_associated_item<'tcx>( && trait_item_id != leaf_def.item.def_id && let Some(leaf_def_item) = leaf_def.item.def_id.as_local() { - tcx.compare_assoc_const_impl_item_with_trait_item(( + tcx.compare_impl_const(( leaf_def_item, trait_item_id, ))?; |
