From ef24de24a82fe681581cc130f342363c47c0969a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 7 Jun 2024 07:48:48 +0200 Subject: Merging upstream version 1.75.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_hir_analysis/src/astconv/bounds.rs | 66 ++-- compiler/rustc_hir_analysis/src/astconv/errors.rs | 107 ++++++- .../rustc_hir_analysis/src/astconv/generics.rs | 24 +- compiler/rustc_hir_analysis/src/astconv/lint.rs | 27 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 91 ++++-- .../src/astconv/object_safety.rs | 2 +- compiler/rustc_hir_analysis/src/bounds.rs | 28 ++ compiler/rustc_hir_analysis/src/check/check.rs | 101 +++--- .../src/check/compare_impl_item.rs | 342 ++++++++++++--------- .../src/check/compare_impl_item/refine.rs | 8 +- compiler/rustc_hir_analysis/src/check/entry.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 7 +- compiler/rustc_hir_analysis/src/check/region.rs | 4 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 339 ++++++++++---------- .../rustc_hir_analysis/src/coherence/builtin.rs | 14 +- .../src/coherence/inherent_impls.rs | 4 +- .../rustc_hir_analysis/src/coherence/orphan.rs | 295 ++++++++---------- compiler/rustc_hir_analysis/src/collect.rs | 47 +-- .../rustc_hir_analysis/src/collect/item_bounds.rs | 4 +- .../src/collect/predicates_of.rs | 43 ++- .../src/collect/resolve_bound_vars.rs | 79 ++--- compiler/rustc_hir_analysis/src/collect/type_of.rs | 89 +++--- .../src/collect/type_of/opaque.rs | 33 +- .../src/constrained_generic_params.rs | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 186 ++++++++++- .../src/impl_wf_check/min_specialization.rs | 66 ++-- compiler/rustc_hir_analysis/src/lib.rs | 28 +- .../wrong_number_of_generic_args.rs | 129 +++++--- .../rustc_hir_analysis/src/variance/constraints.rs | 4 +- compiler/rustc_hir_analysis/src/variance/mod.rs | 2 +- 30 files changed, 1344 insertions(+), 829 deletions(-) (limited to 'compiler/rustc_hir_analysis/src') diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 21611e9c5..3e700f2da 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt}; use rustc_span::symbol::Ident; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; +use smallvec::SmallVec; use crate::astconv::{ AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter, @@ -28,15 +29,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { let tcx = self.tcx(); // Try to find an unbound in bounds. - let mut unbound = None; + let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| { for ab in ast_bounds { if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { - if unbound.is_none() { - unbound = Some(&ptr.trait_ref); - } else { - tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span }); - } + unbounds.push(ptr) } } }; @@ -51,33 +48,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } } + if unbounds.len() > 1 { + tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { + spans: unbounds.iter().map(|ptr| ptr.span).collect(), + }); + } + let sized_def_id = tcx.lang_items().sized_trait(); - match (&sized_def_id, unbound) { - (Some(sized_def_id), Some(tpb)) - if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) => - { - // There was in fact a `?Sized` bound, return without doing anything - return; - } - (_, Some(_)) => { - // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.sess.span_warn( - span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default; only `?Sized` is supported", - ); - // Otherwise, add implicitly sized if `Sized` is available. - } - _ => { - // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + + let mut seen_sized_unbound = false; + for unbound in unbounds { + if let Some(sized_def_id) = sized_def_id { + if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { + seen_sized_unbound = true; + continue; + } } + // There was a `?Trait` bound, but it was not `?Sized`; warn. + tcx.sess.span_warn( + unbound.span, + "relaxing a default bound only does something for `?Sized`; \ + all other traits are not bound by default", + ); } + + // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available. if sized_def_id.is_none() { // No lang item for `Sized`, so we can't add it as a bound. return; } - bounds.push_sized(tcx, self_ty, span); + if seen_sized_unbound { + // There was in fact a `?Sized` bound, return without doing anything + } else { + // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + bounds.push_sized(tcx, self_ty, span); + } } /// This helper takes a *converted* parameter type (`param_ty`) @@ -284,6 +289,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), trait_ref.skip_binder().print_only_trait_name(), + None, binding.item_name, path_span, match binding.kind { @@ -447,7 +453,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { debug!(?args_trait_ref_and_assoc_item); - tcx.mk_alias_ty(assoc_item.def_id, args_trait_ref_and_assoc_item) + ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item) }) }; @@ -517,8 +523,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); if let DefKind::AssocConst = def_kind - && let Some(t) = term.ty() && (t.is_enum() || t.references_error()) - && tcx.features().associated_const_equality { + && let Some(t) = term.ty() + && (t.is_enum() || t.references_error()) + && tcx.features().associated_const_equality + { err.span_suggestion( binding.span, "if equating a const, try wrapping with braces", diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index ed4dde419..32be7e083 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -3,17 +3,18 @@ use crate::errors::{ AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams, ParenthesizedFnTraitExpansion, }; +use crate::traits::error_reporting::report_object_safety_error; 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_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; -use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::traits::object_safety_violations_for_assoc_item; use std::collections::BTreeSet; @@ -102,6 +103,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, all_candidates: impl Fn() -> I, ty_param_name: &str, + ty_param_def_id: Option, assoc_name: Ident, span: Span, ) -> ErrorGuaranteed @@ -190,13 +192,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect::>()[..] { + let trait_name = self.tcx().def_path_str(*best_trait); + let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" }; err.span_label( assoc_name.span, format!( - "there is a similarly named associated type `{suggested_name}` in the trait `{}`", - self.tcx().def_path_str(*best_trait) + "there is {an} associated type `{suggested_name}` in the \ + trait `{trait_name}`", ), ); + let hir = self.tcx().hir(); + if let Some(def_id) = ty_param_def_id + && let parent = hir.get_parent_item(hir.local_def_id_to_hir_id(def_id)) + && let Some(generics) = hir.get_generics(parent.def_id) + { + if generics.bounds_for_param(def_id) + .flat_map(|pred| pred.bounds.iter()) + .any(|b| match b { + hir::GenericBound::Trait(t, ..) => { + t.trait_ref.trait_def_id().as_ref() == Some(best_trait) + } + _ => false, + }) + { + // The type param already has a bound for `trait_name`, we just need to + // change the associated type. + err.span_suggestion_verbose( + assoc_name.span, + format!( + "change the associated type name to use `{suggested_name}` from \ + `{trait_name}`", + ), + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else if suggest_constraining_type_param( + self.tcx(), + generics, + &mut err, + &ty_param_name, + &trait_name, + None, + None, + ) + && suggested_name != assoc_name.name + { + // We suggested constraining a type parameter, but the associated type on it + // was also not an exact match, so we also suggest changing it. + err.span_suggestion_verbose( + assoc_name.span, + "and also change the associated type name", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } + } return err.emit(); } } @@ -389,7 +439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let quiet_projection_ty = - tcx.mk_alias_ty(projection_ty.def_id, args_with_infer_self); + ty::AliasTy::new(tcx, projection_ty.def_id, args_with_infer_self); let term = pred.skip_binder().term; @@ -472,24 +522,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) }) .collect(); - let mut names = vec![]; + let mut names: FxHashMap> = Default::default(); + let mut names_len = 0; // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // `issue-22560.rs`. let mut trait_bound_spans: Vec = vec![]; + let mut object_safety_violations = false; for (span, items) in &associated_types { if !items.is_empty() { trait_bound_spans.push(*span); } for assoc_item in items { let trait_def_id = assoc_item.container_id(tcx); - names.push(format!( - "`{}` (from trait `{}`)", - assoc_item.name, - tcx.def_path_str(trait_def_id), - )); + names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name); + names_len += 1; + + let violations = + object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); + if !violations.is_empty() { + report_object_safety_error(tcx, *span, trait_def_id, &violations).emit(); + object_safety_violations = true; + } } } + if object_safety_violations { + return; + } if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { match bound.trait_ref.path.segments { // FIXME: `trait_ref.path.span` can point to a full path with multiple @@ -525,15 +584,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { _ => {} } } + + let mut names = names + .into_iter() + .map(|(trait_, mut assocs)| { + assocs.sort(); + format!( + "{} in `{trait_}`", + match &assocs[..] { + [] => String::new(), + [only] => format!("`{only}`"), + [assocs @ .., last] => format!( + "{} and `{last}`", + assocs.iter().map(|a| format!("`{a}`")).collect::>().join(", ") + ), + } + ) + }) + .collect::>(); names.sort(); + let names = names.join(", "); + trait_bound_spans.sort(); let mut err = struct_span_err!( tcx.sess, trait_bound_spans, E0191, "the value of the associated type{} {} must be specified", - pluralize!(names.len()), - names.join(", "), + pluralize!(names_len), + names, ); let mut suggestions = vec![]; let mut types_count = 0; diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index e3621ef93..d29a27ece 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -429,12 +429,22 @@ pub(crate) fn check_generic_arg_count( .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })) .count(); let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; + let synth_const_param_count = gen_params + .params + .iter() + .filter(|param| { + matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. }) + }) + .count(); + let named_const_param_count = param_counts.consts - synth_const_param_count; let infer_lifetimes = (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); - if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() { - prohibit_assoc_ty_binding(tcx, b.span, None); - } + if gen_pos != GenericArgPosition::Type + && let Some(b) = gen_args.bindings.first() + { + prohibit_assoc_ty_binding(tcx, b.span, None); + } let explicit_late_bound = prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos); @@ -571,11 +581,13 @@ pub(crate) fn check_generic_arg_count( debug!(?expected_min); debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params()); + let provided = gen_args.num_generic_params(); + check_types_and_consts( expected_min, - param_counts.consts + named_type_param_count, - param_counts.consts + named_type_param_count + synth_type_param_count, - gen_args.num_generic_params(), + named_const_param_count + named_type_param_count, + named_const_param_count + named_type_param_count + synth_type_param_count, + provided, param_counts.lifetimes + has_self as usize, gen_args.num_lifetime_params(), ) diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index 1bd1270be..bc57bbcca 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -18,18 +18,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { - self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, .. + self_ty: impl_self_ty, + of_trait: Some(of_trait_ref), + generics, + .. }), .. - }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id + }) = tcx.hir().get_by_def_id(parent_id) + && self_ty.hir_id == impl_self_ty.hir_id { if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { return; } let of_trait_span = of_trait_ref.path.span; // make sure that we are not calling unwrap to abort during the compilation - let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; }; - let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; + let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { + return; + }; + let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { + return; + }; // check if the trait has generics, to make a correct suggestion let param_name = generics.params.next_type_param_name(None); @@ -39,13 +47,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (generics.span, format!("<{param_name}: {impl_trait_name}>")) }; diag.multipart_suggestion( - format!("alternatively use a blanket \ + format!( + "alternatively use a blanket \ implementation to implement `{of_trait_name}` for \ - all types that also implement `{impl_trait_name}`"), - vec![ - (self_ty.span, param_name), - add_generic_sugg, - ], + all types that also implement `{impl_trait_name}`" + ), + vec![(self_ty.span, param_name), add_generic_sugg], Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 56b1fd369..2fcb45ef8 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -36,7 +36,7 @@ use rustc_middle::ty::{ use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{sym, BytePos, Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt}; @@ -567,9 +567,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if let ty::BoundConstness::ConstIfConst = constness - && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) + && generics.has_self + && !tcx.has_attr(def_id, sym::const_trait) { - tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } ); + tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span }); } (args, arg_count) @@ -915,7 +916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Type aliases defined in crates that have the // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will // then actually instantiate the where bounds of. - let alias_ty = tcx.mk_alias_ty(did, args); + let alias_ty = ty::AliasTy::new(tcx, did, args); Ty::new_alias(tcx, ty::Weak, alias_ty) } else { tcx.at(span).type_of(did).instantiate(tcx, args) @@ -1017,7 +1018,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.span_suggestions( span, - "use the fully-qualified path", + "use fully-qualified syntax", suggestions, Applicability::MachineApplicable, ); @@ -1061,6 +1062,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) }, param_name, + Some(ty_param_def_id), assoc_name, span, None, @@ -1074,6 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, all_candidates: impl Fn() -> I, ty_param_name: impl Display, + ty_param_def_id: Option, assoc_name: Ident, span: Span, is_equality: Option>, @@ -1088,13 +1091,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name) }); - let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) { + let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next()) + { (Some(bound), _) => (bound, matching_candidates.next()), (None, Some(bound)) => (bound, const_candidates.next()), (None, None) => { let reported = self.complain_about_assoc_type_not_found( all_candidates, &ty_param_name.to_string(), + ty_param_def_id, assoc_name, span, ); @@ -1103,6 +1108,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!(?bound); + // look for a candidate that is not the same as our first bound, disregarding + // whether the bound is const. + while let Some(mut bound2) = next_cand { + debug!(?bound2); + let tcx = self.tcx(); + if bound2.bound_vars() != bound.bound_vars() { + break; + } + + let generics = tcx.generics_of(bound.def_id()); + let Some(host_index) = generics.host_effect_index else { break }; + + // always return the bound that contains the host param. + if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() { + (bound, bound2) = (bound2, bound); + } + + let unconsted_args = bound + .skip_binder() + .args + .iter() + .enumerate() + .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg }); + + if unconsted_args.eq(bound2.skip_binder().args.iter()) { + next_cand = matching_candidates.next().or_else(|| const_candidates.next()); + } else { + break; + } + } + if let Some(bound2) = next_cand { debug!(?bound2); @@ -1142,30 +1178,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_label( bound_span, format!( - "ambiguous `{}` from `{}`", - assoc_name, + "ambiguous `{assoc_name}` from `{}`", bound.print_only_trait_path(), ), ); if let Some(constraint) = &is_equality { where_bounds.push(format!( - " T: {trait}::{assoc} = {constraint}", + " T: {trait}::{assoc_name} = {constraint}", trait=bound.print_only_trait_path(), - assoc=assoc_name, - constraint=constraint, )); } else { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), - "use fully qualified syntax to disambiguate", - format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()), + "use fully-qualified syntax to disambiguate", + format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } } else { err.note(format!( - "associated type `{}` could derive from `{}`", - ty_param_name, + "associated type `{ty_param_name}` could derive from `{}`", bound.print_only_trait_path(), )); } @@ -1173,8 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if !where_bounds.is_empty() { err.help(format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ - \n where\n T: {},\n{}", - ty_param_name, + \n where\n T: {ty_param_name},\n{}", where_bounds.join(",\n"), )); } @@ -1275,8 +1306,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return; }; // Get the span of the generics args *including* the leading `::`. - let args_span = - assoc_segment.ident.span.shrink_to_hi().to(args.span_ext); + // We do so by stretching args.span_ext to the left by 2. Earlier + // it was done based on the end of assoc segment but that sometimes + // led to impossible spans and caused issues like #116473 + let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2)); if tcx.generics_of(adt_def.did()).count() == 0 { // FIXME(estebank): we could also verify that the arguments being // work for the `enum`, instead of just looking if it takes *any*. @@ -1394,6 +1427,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) }, kw::SelfUpper, + None, assoc_ident, span, None, @@ -1684,7 +1718,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .chain(args.into_iter().skip(parent_args.len())), ); - let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, args)); + let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args)); return Ok(Some((ty, assoc_item))); } @@ -1917,9 +1951,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { Some(( match segment.res { - Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()), + Res::PrimTy(ty) => { + format!("{} `{}`", segment.res.descr(), ty.name()) + } Res::Def(_, def_id) - if let Some(name) = self.tcx().opt_item_name(def_id) => { + if let Some(name) = self.tcx().opt_item_name(def_id) => + { format!("{} `{name}`", segment.res.descr()) } Res::Err => "this type".to_string(), @@ -2249,7 +2286,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.note(msg); } for segment in path.segments { - if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper { + if let Some(args) = segment.args + && segment.ident.name == kw::SelfUpper + { if generics == 0 { // FIXME(estebank): we could also verify that the arguments being // work for the `enum`, instead of just looking if it takes *any*. @@ -2631,7 +2670,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .iter() .enumerate() .map(|(i, a)| { - if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() { + if let hir::TyKind::Infer = a.kind + && !self.allow_ty_infer() + { if let Some(suggested_ty) = self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) { @@ -2660,7 +2701,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_ty_to_ty(output) } } - hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,), + hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx), }; debug!(?output_ty); diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 30c2ab8f5..00ff3f836 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -380,7 +380,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, E0228, "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" + from context; please supply an explicit bound" ); let e = if borrowed { // We will have already emitted an error E0106 complaining about a diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 1d9ae2b9c..b6688e0ce 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -43,6 +43,34 @@ impl<'tcx> Bounds<'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::ImplPolarity, + ) { + self.push_trait_bound_inner(tcx, trait_ref, span, polarity); + + // push a non-const (`host = true`) version of the bound if it is `~const`. + if tcx.features().effects + && let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index + && trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_ + { + let generics = tcx.generics_of(trait_ref.def_id()); + let Some(host_index) = generics.host_effect_index else { return }; + let trait_ref = trait_ref.map_bound(|mut trait_ref| { + trait_ref.args = + tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| { + if host_index == n { tcx.consts.true_.into() } else { arg } + })); + trait_ref + }); + + self.push_trait_bound_inner(tcx, trait_ref, span, polarity); + } + } + + fn push_trait_bound_inner( + &mut self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + span: Span, + polarity: ty::ImplPolarity, ) { self.clauses.push(( trait_ref diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 44e1bdb83..e61ca232d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -128,7 +128,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b let param_env = tcx.param_env(item_def_id); for field in &def.non_enum_variant().fields { - let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args)); + let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args)) + else { + tcx.sess.delay_span_bug(span, "could not normalize field type"); + continue; + }; if !allowed_union_field(field_ty, tcx, param_env) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { @@ -291,7 +295,7 @@ fn check_opaque_meets_bounds<'tcx>( let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - // `ReErased` regions appear in the "parent_args" of closures/generators. + // `ReErased` regions appear in the "parent_args" of closures/coroutines. // We're ignoring them here and replacing them with fresh region variables. // See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs. // @@ -327,7 +331,7 @@ fn check_opaque_meets_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let guar = infcx.err_ctxt().report_fulfillment_errors(&errors); + let guar = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } match origin { @@ -481,8 +485,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi); } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { - let trait_args = - GenericArgs::identity_for_item(tcx, id.owner_id); + let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, @@ -502,7 +505,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(id.owner_id.def_id); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) + | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -589,7 +593,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::GlobalAsm => { let it = tcx.hir().item(id); - let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; + let hir::ItemKind::GlobalAsm(asm) = it.kind else { + span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) + }; InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); } _ => {} @@ -783,21 +789,21 @@ fn check_impl_items_against_trait<'tcx>( let (msg, feature) = if tcx.asyncness(def_id).is_async() { ( format!("async {descr} in trait cannot be specialized"), - sym::async_fn_in_trait, + "async functions in traits", ) } else { ( format!( "{descr} with return-position `impl Trait` in trait cannot be specialized" ), - sym::return_position_impl_trait_in_trait, + "return position `impl Trait` in traits", ) }; tcx.sess .struct_span_err(tcx.def_span(def_id), msg) .note(format!( "specialization behaves in inconsistent and \ - surprising ways with `#![feature({feature})]`, \ + surprising ways with {feature}, \ and for now is disallowed" )) .emit(); @@ -873,10 +879,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct([T; N]) through, let monomorphization catch errors ty::Array(t, _clen) - if matches!( - t.kind(), - ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) - ) => + if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) => { /* struct([f32; 4]) is ok */ } _ => { struct_span_err!( @@ -899,17 +902,17 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { for attr in tcx.get_attrs(def.did(), sym::repr) { for r in attr::parse_repr_attr(&tcx.sess, attr) { if let attr::ReprPacked(pack) = r - && let Some(repr_pack) = repr.pack - && pack as u64 != repr_pack.bytes() - { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } + && let Some(repr_pack) = repr.pack + && pack as u64 != repr_pack.bytes() + { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } } } if repr.align.is_some() { @@ -1174,7 +1177,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let (span, display_discr) = match var.discr { ty::VariantDiscr::Explicit(discr_def_id) => { // In the case the discriminant is both a duplicate and overflowed, let the user know - if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local()) + if let hir::Node::AnonConst(expr) = + tcx.hir().get_by_def_id(discr_def_id.expect_local()) && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node && *lit_value != dis.val @@ -1303,15 +1307,9 @@ pub(super) fn check_type_params_are_used<'tcx>( && let ty::GenericParamDefKind::Type { .. } = param.kind { let span = tcx.def_span(param.def_id); - struct_span_err!( - tcx.sess, - span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .span_label(span, "unused type parameter") - .emit(); + struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,) + .span_label(span, "unused type parameter") + .emit(); } } } @@ -1400,7 +1398,7 @@ fn opaque_type_cycle_error( self.opaques.push(def); ControlFlow::Continue(()) } - ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => { + ty::Closure(def_id, ..) | ty::Coroutine(def_id, ..) => { self.closures.push(def_id); t.super_visit_with(self) } @@ -1430,7 +1428,10 @@ fn opaque_type_cycle_error( let mut label_match = |ty: Ty<'_>, span| { for arg in ty.walk() { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind() + && let ty::Alias( + ty::Opaque, + ty::AliasTy { def_id: captured_def_id, .. }, + ) = *ty.kind() && captured_def_id == opaque_def_id.to_def_id() { err.span_label( @@ -1449,11 +1450,11 @@ fn opaque_type_cycle_error( { label_match(capture.place.ty(), capture.get_path_span(tcx)); } - // Label any generator locals that capture the opaque - if let DefKind::Generator = tcx.def_kind(closure_def_id) - && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id) + // Label any coroutine locals that capture the opaque + if let DefKind::Coroutine = tcx.def_kind(closure_def_id) + && let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id) { - for interior_ty in &generator_layout.field_tys { + for interior_ty in &coroutine_layout.field_tys { label_match(interior_ty.ty, interior_ty.source_info.span); } } @@ -1467,14 +1468,14 @@ fn opaque_type_cycle_error( err.emit() } -pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator)); +pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Coroutine)); let typeck = tcx.typeck(def_id); let param_env = tcx.param_env(def_id); - let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id]; - debug!(?generator_interior_predicates); + let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id]; + debug!(?coroutine_interior_predicates); let infcx = tcx .infer_ctxt() @@ -1486,15 +1487,15 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { .build(); let mut fulfillment_cx = >::new(&infcx); - for (predicate, cause) in generator_interior_predicates { + for (predicate, cause) in coroutine_interior_predicates { let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); fulfillment_cx.register_predicate_obligation(&infcx, obligation); } if (tcx.features().unsized_locals || tcx.features().unsized_fn_params) - && let Some(generator) = tcx.mir_generator_witnesses(def_id) + && let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id) { - for field_ty in generator.field_tys.iter() { + for field_ty in coroutine.field_tys.iter() { fulfillment_cx.register_bound( &infcx, param_env, @@ -1503,7 +1504,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { ObligationCause::new( field_ty.source_info.span, def_id, - ObligationCauseCode::SizedGeneratorInterior(def_id), + ObligationCauseCode::SizedCoroutineInterior(def_id), ), ); } @@ -1512,6 +1513,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { let errors = fulfillment_cx.select_all_or_error(&infcx); debug!(?errors); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d081b0e35..857515f97 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -16,6 +16,7 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -322,7 +323,7 @@ fn compare_method_predicate_entailment<'tcx>( // FIXME(-Ztrait-solver=next): Not needed when the hack below is removed. let errors = ocx.select_where_possible(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -393,7 +394,7 @@ fn compare_method_predicate_entailment<'tcx>( }); } CheckImpliedWfMode::Skip => { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } } @@ -632,8 +633,6 @@ fn compare_asyncness<'tcx>( /// For example, given the sample code: /// /// ``` -/// #![feature(return_position_impl_trait_in_trait)] -/// /// use std::ops::Deref; /// /// trait Foo { @@ -873,7 +872,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // RPITs. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -1010,7 +1009,11 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds - for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).iter_instantiated_copied(self.interner(), proj.args) { + for (pred, pred_span) in self + .interner() + .explicit_item_bounds(proj.def_id) + .iter_instantiated_copied(self.interner(), proj.args) + { let pred = pred.fold_with(self); let pred = self.ocx.normalize( &ObligationCause::misc(self.span, self.body_id), @@ -1181,14 +1184,15 @@ fn report_trait_method_mismatch<'tcx>( if trait_sig.inputs().len() == *i { // Suggestion to change output type. We do not suggest in `async` functions // to avoid complex logic or incorrect output. - if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind + if let ImplItemKind::Fn(sig, _) = + &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind && !sig.header.asyncness.is_async() { let msg = "change the output type to match the trait"; let ap = Applicability::MachineApplicable; match sig.decl.output { hir::FnRetTy::DefaultReturn(sp) => { - let sugg = format!("-> {} ", trait_sig.output()); + let sugg = format!(" -> {}", trait_sig.output()); diag.span_suggestion_verbose(sp, msg, sugg, ap); } hir::FnRetTy::Return(hir_ty) => { @@ -1553,38 +1557,24 @@ fn compare_number_of_generics<'tcx>( DiagnosticId::Error("E0049".into()), ); - let mut suffix = None; - + let msg = + format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); if let Some(spans) = trait_spans { let mut spans = spans.iter(); if let Some(span) = spans.next() { - err.span_label( - *span, - format!( - "expected {} {} parameter{}", - trait_count, - kind, - pluralize!(trait_count), - ), - ); + err.span_label(*span, msg); } for span in spans { err.span_label(*span, ""); } } else { - suffix = Some(format!(", expected {trait_count}")); + err.span_label(tcx.def_span(trait_.def_id), msg); } if let Some(span) = span { err.span_label( span, - format!( - "found {} {} parameter{}{}", - impl_count, - kind, - pluralize!(impl_count), - suffix.unwrap_or_default(), - ), + format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),), ); } @@ -2049,7 +2039,7 @@ fn compare_const_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - return Err(infcx.err_ctxt().report_fulfillment_errors(&errors)); + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } let outlives_env = OutlivesEnvironment::new(param_env); @@ -2142,7 +2132,7 @@ fn compare_type_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -2173,127 +2163,9 @@ pub(super) fn check_type_bounds<'tcx>( impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let param_env = tcx.param_env(impl_ty.def_id); - let container_id = impl_ty.container_id(tcx); - // Given - // - // impl Foo for (A, B) { - // type Bar = Wrapper - // } - // - // - `impl_trait_ref` would be `<(A, B) as Foo>` - // - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) - // - `normalize_impl_ty` would be `Wrapper` - // - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from - // the *trait* with the generic associated type parameters (as bound vars). - // - // A note regarding the use of bound vars here: - // Imagine as an example - // ``` - // trait Family { - // type Member; - // } - // - // impl Family for VecFamily { - // type Member = i32; - // } - // ``` - // Here, we would generate - // ```notrust - // forall { Normalize(::Member => i32) } - // ``` - // when we really would like to generate - // ```notrust - // forall { Normalize(::Member => i32) :- Implemented(C: Eq) } - // ``` - // But, this is probably fine, because although the first clause can be used with types C that - // do not implement Eq, for it to cause some kind of problem, there would have to be a - // VecFamily::Member for some type X where !(X: Eq), that appears in the value of type - // Member = .... That type would fail a well-formedness check that we ought to be doing - // elsewhere, which would check that any ::Member meets the bounds declared in - // the trait (notably, that X: Eq and T: Family). - let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); - // Extend the impl's identity args with late-bound GAT vars - let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id).extend_to( - tcx, - impl_ty.def_id, - |param, _| match param.kind { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - Ty::new_bound( - tcx, - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - ty::Region::new_late_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() - } - }, - ); - // When checking something like - // - // trait X { type Y: PartialEq<::Y> } - // impl X for T { default type Y = S; } - // - // We will have to prove the bound S: PartialEq<::Y>. In this case - // we want ::Y to normalize to S. This is valid because we are - // checking the default value specifically here. Add this equality to the - // ParamEnv for normalization specifically. - let normalize_impl_ty = tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); - let rebased_args = normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); - let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); - let normalize_param_env = { - let mut predicates = param_env.caller_bounds().iter().collect::>(); - match normalize_impl_ty.kind() { - ty::Alias(ty::Projection, proj) - if proj.def_id == trait_ty.def_id && proj.args == rebased_args => - { - // Don't include this predicate if the projected type is - // exactly the same as the projection. This can occur in - // (somewhat dubious) code like this: - // - // impl X for T where T: X { type Y = ::Y; } - } - _ => predicates.push(ty::Clause::from_projection_clause( - tcx, - ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args), - term: normalize_impl_ty.into(), - }, - bound_vars, - ), - )), - }; - ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) - }; - debug!(?normalize_param_env); + debug!(?param_env); + let container_id = impl_ty.container_id(tcx); let impl_ty_def_id = impl_ty.def_id.expect_local(); let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); @@ -2345,6 +2217,11 @@ pub(super) fn check_type_bounds<'tcx>( .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); + // Normalize predicates with the assumption that the GAT may always normalize + // to its definition type. This should be the param-env we use to *prove* the + // predicate too, but we don't do that because of performance issues. + // See . + let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref); for mut obligation in util::elaborate(tcx, obligations) { let normalized_predicate = ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); @@ -2357,7 +2234,7 @@ pub(super) fn check_type_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -2368,6 +2245,171 @@ pub(super) fn check_type_bounds<'tcx>( ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } +/// Install projection predicates that allow GATs to project to their own +/// definition types. This is not allowed in general in cases of default +/// associated types in trait definitions, or when specialization is involved, +/// but is needed when checking these definition types actually satisfy the +/// trait bounds of the GAT. +/// +/// # How it works +/// +/// ```ignore (example) +/// impl Foo for (A, B) { +/// type Bar = Wrapper +/// } +/// ``` +/// +/// - `impl_trait_ref` would be `<(A, B) as Foo>` +/// - `normalize_impl_ty_args` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) +/// - `normalize_impl_ty` would be `Wrapper` +/// - `rebased_args` would be `[(A, B), u32, ^0.0]`, combining the args from +/// the *trait* with the generic associated type parameters (as bound vars). +/// +/// A note regarding the use of bound vars here: +/// Imagine as an example +/// ``` +/// trait Family { +/// type Member; +/// } +/// +/// impl Family for VecFamily { +/// type Member = i32; +/// } +/// ``` +/// Here, we would generate +/// ```ignore (pseudo-rust) +/// forall { Normalize(::Member => i32) } +/// ``` +/// +/// when we really would like to generate +/// ```ignore (pseudo-rust) +/// forall { Normalize(::Member => i32) :- Implemented(C: Eq) } +/// ``` +/// +/// But, this is probably fine, because although the first clause can be used with types `C` that +/// do not implement `Eq`, for it to cause some kind of problem, there would have to be a +/// `VecFamily::Member` for some type `X` where `!(X: Eq)`, that appears in the value of type +/// `Member = ....` That type would fail a well-formedness check that we ought to be doing +/// elsewhere, which would check that any `::Member` meets the bounds declared in +/// the trait (notably, that `X: Eq` and `T: Family`). +fn param_env_with_gat_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + impl_ty: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> ty::ParamEnv<'tcx> { + let param_env = tcx.param_env(impl_ty.def_id); + let container_id = impl_ty.container_id(tcx); + let mut predicates = param_env.caller_bounds().to_vec(); + + // for RPITITs, we should install predicates that allow us to project all + // of the RPITITs associated with the same body. This is because checking + // the item bounds of RPITITs often involves nested RPITITs having to prove + // bounds about themselves. + let impl_tys_to_install = match impl_ty.opt_rpitit_info { + None => vec![impl_ty], + Some( + ty::ImplTraitInTraitData::Impl { fn_def_id } + | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, + ) => tcx + .associated_types_for_impl_traits_in_associated_fn(fn_def_id) + .iter() + .map(|def_id| tcx.associated_item(*def_id)) + .collect(), + }; + + for impl_ty in impl_tys_to_install { + let trait_ty = match impl_ty.container { + ty::AssocItemContainer::TraitContainer => impl_ty, + ty::AssocItemContainer::ImplContainer => { + tcx.associated_item(impl_ty.trait_item_def_id.unwrap()) + } + }; + + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + // Extend the impl's identity args with late-bound GAT vars + let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id) + .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + Ty::new_bound( + tcx, + ty::INNERMOST, + ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }); + // When checking something like + // + // trait X { type Y: PartialEq<::Y> } + // impl X for T { default type Y = S; } + // + // We will have to prove the bound S: PartialEq<::Y>. In this case + // we want ::Y to normalize to S. This is valid because we are + // checking the default value specifically here. Add this equality to the + // ParamEnv for normalization specifically. + let normalize_impl_ty = + tcx.type_of(impl_ty.def_id).instantiate(tcx, normalize_impl_ty_args); + let rebased_args = + normalize_impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); + let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); + + match normalize_impl_ty.kind() { + ty::Alias(ty::Projection, proj) + if proj.def_id == trait_ty.def_id && proj.args == rebased_args => + { + // Don't include this predicate if the projected type is + // exactly the same as the projection. This can occur in + // (somewhat dubious) code like this: + // + // impl X for T where T: X { type Y = ::Y; } + } + _ => predicates.push( + ty::Binder::bind_with_vars( + ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), + term: normalize_impl_ty.into(), + }, + bound_vars, + ) + .to_predicate(tcx), + ), + }; + } + + ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index d9e0e87eb..bc5029a1d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -23,8 +23,12 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { return; } - // crate-private traits don't have any library guarantees, there's no need to do this check. - if !tcx.visibility(trait_m.container_id(tcx)).is_public() { + // unreachable traits don't have any library guarantees, there's no need to do this check. + if trait_m + .container_id(tcx) + .as_local() + .is_some_and(|trait_def_id| !tcx.effective_visibilities(()).is_reachable(trait_def_id)) + { return; } diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 3cd3f5bcf..6681292c9 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); error = true; } // now we can take the return type of the given main function diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 5fa65f33c..15c5558fc 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -90,9 +90,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::parse::feature_err; -use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol}; +use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; @@ -114,7 +113,7 @@ pub fn provide(providers: &mut Providers) { region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, - check_generator_obligations: check::check_generator_obligations, + check_coroutine_obligations: check::check_coroutine_obligations, ..*providers }; } @@ -588,7 +587,7 @@ pub fn check_function_signature<'tcx>( Ok(()) => { let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); return; } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 463fab93e..40b33117f 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -598,7 +598,7 @@ fn resolve_local<'tcx>( } // Make sure we visit the initializer first, so expr_and_pat_count remains correct. - // The correct order, as shared between generator_interior, drop_ranges and intravisitor, + // The correct order, as shared between coroutine_interior, drop_ranges and intravisitor, // is to walk initializer, followed by pattern bindings, finally followed by the `else` block. if let Some(expr) = init { visitor.visit_expr(expr); @@ -825,7 +825,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { resolve_local(self, None, Some(&body.value)); } - if body.generator_kind.is_some() { + if body.coroutine_kind.is_some() { self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 77614a9a4..eb4491b89 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -93,8 +93,9 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( span: Span, body_def_id: LocalDefId, f: F, -) where - F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>), +) -> Result<(), ErrorGuaranteed> +where + F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>, { let param_env = tcx.param_env(body_def_id); let infcx = &tcx.infer_ctxt().build(); @@ -105,42 +106,48 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( if !tcx.features().trivial_bounds { wfcx.check_false_global_bounds() } - f(&mut wfcx); + f(&mut wfcx)?; - let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id) - { - Ok(wf_types) => wf_types, - Err(_guar) => return, - }; + let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); - return; + let err = infcx.err_ctxt().report_fulfillment_errors(errors); + if tcx.sess.err_count() > 0 { + return Err(err); + } else { + // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs causes an + // error (delay_span_bug) during normalization, without reporting an error, so we need to act as if + // no error happened, in order to let our callers continue and report an error later in + // check_impl_items_against_trait. + return Ok(()); + } } let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env); + wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?; + infcx.tainted_by_errors().error_reported() } -fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { +fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { let node = tcx.hir().owner(def_id); - match node { - hir::OwnerNode::Crate(_) => {} + let mut res = match node { + hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), hir::OwnerNode::Item(item) => check_item(tcx, item), hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), - } + }; if let Some(generics) = node.generics() { for param in generics.params { - check_param_wf(tcx, param) + res = res.and(check_param_wf(tcx, param)); } } + res } /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are @@ -157,7 +164,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. #[instrument(skip(tcx), level = "debug")] -fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { +fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( @@ -187,31 +194,32 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { let is_auto = tcx .impl_trait_ref(def_id) .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); + let mut res = Ok(()); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); let mut err = tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default"); err.span_labels(impl_.defaultness_span, "default because of this"); err.span_label(sp, "auto trait"); - err.emit(); + res = Err(err.emit()); } // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match (tcx.impl_polarity(def_id), impl_.polarity) { (ty::ImplPolarity::Positive, _) => { - check_impl(tcx, item, impl_.self_ty, &impl_.of_trait); + res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait)); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? if let hir::Defaultness::Default { .. } = impl_.defaultness { let mut spans = vec![span]; spans.extend(impl_.defaultness_span); - struct_span_err!( + res = Err(struct_span_err!( tcx.sess, spans, E0750, "negative impls cannot be default impls" ) - .emit(); + .emit()); } } (ty::ImplPolarity::Reservation, _) => { @@ -219,49 +227,52 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } _ => unreachable!(), } + res } hir::ItemKind::Fn(ref sig, ..) => { - check_item_fn(tcx, def_id, item.ident, item.span, sig.decl); + check_item_fn(tcx, def_id, item.ident, item.span, sig.decl) } hir::ItemKind::Static(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) } hir::ItemKind::Const(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) } hir::ItemKind::Struct(_, ast_generics) => { - check_type_defn(tcx, item, false); + let res = check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, ast_generics); + res } hir::ItemKind::Union(_, ast_generics) => { - check_type_defn(tcx, item, true); + let res = check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); + res } hir::ItemKind::Enum(_, ast_generics) => { - check_type_defn(tcx, item, true); + let res = check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); + res } - hir::ItemKind::Trait(..) => { - check_trait(tcx, item); - } - hir::ItemKind::TraitAlias(..) => { - check_trait(tcx, item); - } + hir::ItemKind::Trait(..) => check_trait(tcx, item), + hir::ItemKind::TraitAlias(..) => check_trait(tcx, item), // `ForeignItem`s are handled separately. - hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::ForeignMod { .. } => Ok(()), hir::ItemKind::TyAlias(hir_ty, ast_generics) => { if tcx.type_alias_is_lazy(item.owner_id) { // Bounds of lazy type aliases and of eager ones that contain opaque types are respected. // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`. - check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); + let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); check_variances_for_type_defn(tcx, item, ast_generics); + res + } else { + Ok(()) } } - _ => {} + _ => Ok(()), } } -fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { +fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( @@ -276,11 +287,14 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { hir::ForeignItemKind::Static(ty, ..) => { check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) } - hir::ForeignItemKind::Type => (), + hir::ForeignItemKind::Type => Ok(()), } } -fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { +fn check_trait_item( + tcx: TyCtxt<'_>, + trait_item: &hir::TraitItem<'_>, +) -> Result<(), ErrorGuaranteed> { let def_id = trait_item.owner_id.def_id; let (method_sig, span) = match trait_item.kind { @@ -289,18 +303,19 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { _ => (None, trait_item.span), }; check_object_unsafe_self_trait_by_name(tcx, trait_item); - check_associated_item(tcx, def_id, span, method_sig); + let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { - check_associated_item( + res = res.and(check_associated_item( tcx, assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, - ); + )); } } + res } /// Require that the user writes where clauses on GATs for the implicit @@ -315,9 +330,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { /// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; /// } /// ``` -fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) { +fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. let mut required_bounds_by_item = FxHashMap::default(); + let associated_items = tcx.associated_items(trait_def_id); // Loop over all GATs together, because if this lint suggests adding a where-clause bound // to one GAT, it might then require us to an additional bound on another GAT. @@ -326,8 +342,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // those GATs. loop { let mut should_continue = false; - for gat_item in associated_items { - let gat_def_id = gat_item.id.owner_id; + for gat_item in associated_items.in_definition_order() { + let gat_def_id = gat_item.def_id.expect_local(); let gat_item = tcx.associated_item(gat_def_id); // If this item is not an assoc ty, or has no args, then it's not a GAT if gat_item.kind != ty::AssocKind::Type { @@ -343,8 +359,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // This is calculated by taking the intersection of the bounds that each item // constrains the GAT with individually. let mut new_required_bounds: Option>> = None; - for item in associated_items { - let item_def_id = item.id.owner_id; + for item in associated_items.in_definition_order() { + let item_def_id = item.def_id.expect_local(); // Skip our own GAT, since it does not constrain itself at all. if item_def_id == gat_def_id { continue; @@ -352,9 +368,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let param_env = tcx.param_env(item_def_id); - let item_required_bounds = match item.kind { + let item_required_bounds = match tcx.associated_item(item_def_id).kind { // In our example, this corresponds to `into_iter` method - hir::AssocItemKind::Fn { .. } => { + ty::AssocKind::Fn => { // For methods, we check the function signature's return type for any GATs // to constrain. In the `into_iter` case, we see that the return type // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. @@ -370,12 +386,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // We also assume that all of the function signature's parameter types // are well formed. &sig.inputs().iter().copied().collect(), - gat_def_id.def_id, + gat_def_id, gat_generics, ) } // In our example, this corresponds to the `Iter` and `Item` associated types - hir::AssocItemKind::Type => { + ty::AssocKind::Type => { // If our associated item is a GAT with missing bounds, add them to // the param-env here. This allows this GAT to propagate missing bounds // to other GATs. @@ -392,11 +408,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe .instantiate_identity_iter_copied() .collect::>(), &FxIndexSet::default(), - gat_def_id.def_id, + gat_def_id, gat_generics, ) } - hir::AssocItemKind::Const => None, + ty::AssocKind::Const => None, }; if let Some(item_required_bounds) = item_required_bounds { @@ -432,7 +448,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe } for (gat_def_id, required_bounds) in required_bounds_by_item { - let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id); + // Don't suggest adding `Self: 'a` to a GAT that can't be named + if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) { + continue; + } + + let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id); debug!(?required_bounds); let param_env = tcx.param_env(gat_def_id); @@ -442,21 +463,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { !region_known_to_outlive( tcx, - gat_def_id.def_id, + gat_def_id, param_env, &FxIndexSet::default(), a, b, ) } - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive( - tcx, - gat_def_id.def_id, - param_env, - &FxIndexSet::default(), - a, - b, - ), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + !ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b) + } _ => bug!("Unexpected ClauseKind"), }) .map(|clause| clause.to_string()) @@ -535,7 +551,7 @@ fn augment_param_env<'tcx>( fn gather_gat_bounds<'tcx, T: TypeFoldable>>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - item_def_id: hir::OwnerId, + item_def_id: LocalDefId, to_check: T, wf_tys: &FxIndexSet>, gat_def_id: LocalDefId, @@ -568,7 +584,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // reflected in a where clause on the GAT itself. for (ty, ty_idx) in &types { // In our example, requires that `Self: 'a` - if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) { + if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) { debug!(?ty_idx, ?region_a_idx); debug!("required clause: {ty} must outlive {region_a}"); // Translate into the generic parameters of the GAT. In @@ -607,14 +623,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b { continue; } - if region_known_to_outlive( - tcx, - item_def_id.def_id, - param_env, - &wf_tys, - *region_a, - *region_b, - ) { + if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) { debug!(?region_a_idx, ?region_b_idx); debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. @@ -833,7 +842,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem } } -fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { +fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> Result<(), ErrorGuaranteed> { let (method_sig, span) = match impl_item.kind { hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span), // Constrain binding and overflow error spans to `` in `type foo = `. @@ -841,13 +850,13 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig); + check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } -fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { +fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { match param.kind { // We currently only check wf of const params here. - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (), + hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. hir::GenericParamKind::Const { ty: hir_ty, default: _ } => { @@ -867,68 +876,67 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ty, trait_def_id, ); - }); + Ok(()) + }) } else { - let diag = match ty.kind() { - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None, - ty::FnPtr(_) => Some(tcx.sess.struct_span_err( + let mut diag = match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()), + ty::FnPtr(_) => tcx.sess.struct_span_err( hir_ty.span, "using function pointers as const generic parameters is forbidden", - )), - ty::RawPtr(_) => Some(tcx.sess.struct_span_err( + ), + ty::RawPtr(_) => tcx.sess.struct_span_err( hir_ty.span, "using raw pointers as const generic parameters is forbidden", - )), - _ => Some(tcx.sess.struct_span_err( + ), + _ => tcx.sess.struct_span_err( hir_ty.span, format!("`{}` is forbidden as the type of a const generic parameter", ty), - )), + ), }; - if let Some(mut diag) = diag { - diag.note("the only supported types are integers, `bool` and `char`"); + diag.note("the only supported types are integers, `bool` and `char`"); - let cause = ObligationCause::misc(hir_ty.span, param.def_id); - let may_suggest_feature = match type_allowed_to_implement_const_param_ty( - tcx, - tcx.param_env(param.def_id), - ty, - cause, - ) { - // Can never implement `ConstParamTy`, don't suggest anything. - Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, - // May be able to implement `ConstParamTy`. Only emit the feature help - // if the type is local, since the user may be able to fix the local type. - Err(ConstParamTyImplementationError::InfrigingFields(..)) => { - fn ty_is_local(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Adt(adt_def, ..) => adt_def.did().is_local(), - // Arrays and slices use the inner type's `ConstParamTy`. - ty::Array(ty, ..) => ty_is_local(*ty), - ty::Slice(ty) => ty_is_local(*ty), - // `&` references use the inner type's `ConstParamTy`. - // `&mut` are not supported. - ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), - // Say that a tuple is local if any of its components are local. - // This is not strictly correct, but it's likely that the user can fix the local component. - ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), - _ => false, - } + let cause = ObligationCause::misc(hir_ty.span, param.def_id); + let may_suggest_feature = match type_allowed_to_implement_const_param_ty( + tcx, + tcx.param_env(param.def_id), + ty, + cause, + ) { + // Can never implement `ConstParamTy`, don't suggest anything. + Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, + // May be able to implement `ConstParamTy`. Only emit the feature help + // if the type is local, since the user may be able to fix the local type. + Err(ConstParamTyImplementationError::InfrigingFields(..)) => { + fn ty_is_local(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Adt(adt_def, ..) => adt_def.did().is_local(), + // Arrays and slices use the inner type's `ConstParamTy`. + ty::Array(ty, ..) => ty_is_local(*ty), + ty::Slice(ty) => ty_is_local(*ty), + // `&` references use the inner type's `ConstParamTy`. + // `&mut` are not supported. + ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), + // Say that a tuple is local if any of its components are local. + // This is not strictly correct, but it's likely that the user can fix the local component. + ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), + _ => false, } - - ty_is_local(ty) } - // Implments `ConstParamTy`, suggest adding the feature to enable. - Ok(..) => true, - }; - if may_suggest_feature && tcx.sess.is_nightly_build() { - diag.help( + + ty_is_local(ty) + } + // Implments `ConstParamTy`, suggest adding the feature to enable. + Ok(..) => true, + }; + if may_suggest_feature && tcx.sess.is_nightly_build() { + diag.help( "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", ); - } - - diag.emit(); } + + Err(diag.emit()) } } } @@ -940,7 +948,7 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, -) { +) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { let item = tcx.associated_item(item_id); @@ -955,6 +963,7 @@ fn check_associated_item( let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); + Ok(()) } ty::AssocKind::Fn => { let sig = tcx.fn_sig(item.def_id).instantiate_identity(); @@ -966,7 +975,7 @@ fn check_associated_item( hir_sig.decl, item.def_id.expect_local(), ); - check_method_receiver(wfcx, hir_sig, item, self_ty); + check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer = item.container { @@ -977,6 +986,7 @@ fn check_associated_item( let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); } + Ok(()) } } }) @@ -992,7 +1002,11 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option { } /// In a type definition, we check that to ensure that the types of the fields are well-formed. -fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) { +fn check_type_defn<'tcx>( + tcx: TyCtxt<'tcx>, + item: &hir::Item<'tcx>, + all_sized: bool, +) -> Result<(), ErrorGuaranteed> { let _ = tcx.representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); @@ -1087,11 +1101,12 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b } check_where_clauses(wfcx, item.span, item.owner_id.def_id); - }); + Ok(()) + }) } #[instrument(skip(tcx, item))] -fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { +fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuaranteed> { debug!(?item.owner_id); let def_id = item.owner_id.def_id; @@ -1110,14 +1125,16 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { } } - enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { - check_where_clauses(wfcx, item.span, def_id) + let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { + check_where_clauses(wfcx, item.span, def_id); + Ok(()) }); // Only check traits, don't check trait aliases - if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind { - check_gat_where_clauses(tcx, items); + if let hir::ItemKind::Trait(..) = item.kind { + check_gat_where_clauses(tcx, item.owner_id.def_id); } + res } /// Checks all associated type defaults of trait `trait_def_id`. @@ -1131,11 +1148,11 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let wf_obligations = bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| { let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( + traits::wf::clause_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound.as_predicate(), + normalized_bound, bound_span, ) }); @@ -1149,10 +1166,11 @@ fn check_item_fn( ident: Ident, span: Span, decl: &hir::FnDecl<'_>, -) { +) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, ident.span, sig, decl, def_id); + Ok(()) }) } @@ -1167,7 +1185,7 @@ fn check_item_type( item_id: LocalDefId, ty_span: Span, unsized_handling: UnsizedHandling, -) { +) -> Result<(), ErrorGuaranteed> { debug!("check_item_type: {:?}", item_id); enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { @@ -1207,7 +1225,8 @@ fn check_item_type( tcx.require_lang_item(LangItem::Sync, Some(ty_span)), ); } - }); + Ok(()) + }) } #[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] @@ -1216,7 +1235,7 @@ fn check_impl<'tcx>( item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option>, -) { +) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { match ast_trait_ref { Some(ast_trait_ref) => { @@ -1235,7 +1254,7 @@ fn check_impl<'tcx>( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - &trait_pred, + trait_pred, ast_trait_ref.path.span, item, ); @@ -1265,7 +1284,8 @@ fn check_impl<'tcx>( } check_where_clauses(wfcx, item.span, item.owner_id.def_id); - }); + Ok(()) + }) } /// Checks where-clauses and inline bounds that are declared on `def_id`. @@ -1444,13 +1464,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { - traits::wf::predicate_obligations( - infcx, - wfcx.param_env, - wfcx.body_def_id, - p.as_predicate(), - sp, - ) + traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); @@ -1543,11 +1557,11 @@ fn check_method_receiver<'tcx>( fn_sig: &hir::FnSig<'_>, method: ty::AssocItem, self_ty: Ty<'tcx>, -) { +) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); if !method.fn_has_self_parameter { - return; + return Ok(()); } let span = fn_sig.decl.inputs[0].span; @@ -1566,11 +1580,11 @@ fn check_method_receiver<'tcx>( if tcx.features().arbitrary_self_types { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. - e0307(tcx, span, receiver_ty); + return Err(e0307(tcx, span, receiver_ty)); } } else { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { - if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { + return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; would have worked with `arbitrary_self_types`. feature_err( &tcx.sess.parse_sess, @@ -1582,16 +1596,17 @@ fn check_method_receiver<'tcx>( ), ) .help(HELP_FOR_SELF_TYPE) - .emit(); + .emit() } else { // Report error; would not have worked with `arbitrary_self_types`. - e0307(tcx, span, receiver_ty); - } + e0307(tcx, span, receiver_ty) + }); } } + Ok(()) } -fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) { +fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed { struct_span_err!( tcx.sess.diagnostic(), span, @@ -1600,7 +1615,7 @@ fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) { ) .note("type of `self` must be `Self` or a type that dereferences to it") .help(HELP_FOR_SELF_TYPE) - .emit(); + .emit() } /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If @@ -1892,12 +1907,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } -fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) { +fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); - items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))) } fn error_392( diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index be70acfc3..e5e192e00 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -162,7 +162,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent) // even if they do not carry that attribute. - use rustc_type_ir::sty::TyKind::*; + use rustc_type_ir::TyKind::*; match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok() @@ -261,7 +261,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); } // Finally, resolve all regions. @@ -470,7 +470,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); + infcx.err_ctxt().report_fulfillment_errors(errors); } // Finally, resolve all regions. @@ -550,9 +550,11 @@ fn infringing_fields_error( .entry((ty.clone(), predicate.clone())) .or_default() .push(origin.span()); - if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() { - bounds.push((b.to_string(), a.to_string(), None)); - } + if let ty::RegionKind::ReEarlyBound(ebr) = *b + && ebr.has_name() + { + bounds.push((b.to_string(), a.to_string(), None)); + } } RegionResolutionError::GenericBoundFailure(origin, a, b) => { let predicate = format!("{a}: {b}"); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 0042d683b..1b4df31b5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -155,8 +155,8 @@ impl<'tcx> InherentCollect<'tcx> { } ty::FnDef(..) | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 69020b1f1..7eeb78374 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -2,8 +2,7 @@ //! crate or pertains to a type defined in this crate. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, DelayDm}; -use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_errors::{DelayDm, ErrorGuaranteed}; use rustc_hir as hir; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::GenericArgs; @@ -17,6 +16,8 @@ use rustc_span::Span; use rustc_trait_selection::traits; use std::ops::ControlFlow; +use crate::errors; + #[instrument(skip(tcx), level = "debug")] pub(crate) fn orphan_check_impl( tcx: TyCtxt<'_>, @@ -243,8 +244,8 @@ fn do_orphan_check_impl<'tcx>( | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther), ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { @@ -259,49 +260,30 @@ fn do_orphan_check_impl<'tcx>( match local_impl { LocalImpl::Allow => {} LocalImpl::Disallow { problematic_kind } => { - let msg = format!( - "traits with a default impl, like `{trait}`, \ - cannot be implemented for {problematic_kind} `{self_ty}`", - trait = tcx.def_path_str(trait_def_id), - ); - let label = format!( - "a trait object implements `{trait}` if and only if `{trait}` \ - is one of the trait object's trait bounds", - trait = tcx.def_path_str(trait_def_id), - ); - let sp = tcx.def_span(def_id); - let reported = - struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit(); - return Err(reported); + return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl { + span: tcx.def_span(def_id), + traits: tcx.def_path_str(trait_def_id), + problematic_kind, + self_ty, + })); } } } else { - if let Some((msg, label)) = match nonlocal_impl { - NonlocalImpl::Allow => None, - NonlocalImpl::DisallowBecauseNonlocal => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type \ - defined in the current crate", - tcx.def_path_str(trait_def_id) - ), - "can't implement cross-crate trait for type in another crate", - )), - NonlocalImpl::DisallowOther => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, can \ - only be implemented for a struct/enum type, not `{}`", - tcx.def_path_str(trait_def_id), - self_ty - ), - "can't implement cross-crate trait with a default impl for \ - non-struct/enum type", - )), - } { - let sp = tcx.def_span(def_id); - let reported = - struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit(); - return Err(reported); + match nonlocal_impl { + NonlocalImpl::Allow => {} + NonlocalImpl::DisallowBecauseNonlocal => { + return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined { + span: tcx.def_span(def_id), + traits: tcx.def_path_str(trait_def_id), + })); + } + NonlocalImpl::DisallowOther => { + return Err(tcx.sess.emit_err(errors::CrossCrateTraits { + span: tcx.def_span(def_id), + traits: tcx.def_path_str(trait_def_id), + self_ty, + })); + } } } } @@ -322,19 +304,18 @@ fn emit_orphan_check_error<'tcx>( let self_ty = trait_ref.self_ty(); Err(match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { - let msg = match self_ty.kind() { - ty::Adt(..) => "can be implemented for types defined outside of the crate", - _ if self_ty.is_primitive() => "can be implemented for primitive types", - _ => "can be implemented for arbitrary types", - }; - let mut err = struct_span_err!( - tcx.sess, - sp, - E0117, - "only traits defined in the current crate {msg}" - ); - err.span_label(sp, "impl doesn't use only types from inside the current crate"); + let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) = + (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()); + let mut sugg = None; for &(mut ty, is_target_ty) in &tys { + let span = if is_target_ty { + // Point at `D` in `impl for C in D` + self_ty_span + } else { + // Point at `C` in `impl for C in D` + trait_span + }; + ty = tcx.erase_regions(ty); ty = match ty.kind() { // Remove the type arguments from the output, as they are not relevant. @@ -345,50 +326,103 @@ fn emit_orphan_check_error<'tcx>( ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()), _ => ty, }; - let msg = |ty: &str, postfix: &str| { - format!("{ty} is not defined in the current crate{postfix}") - }; - let this = |name: &str| { - if !trait_ref.def_id.is_local() && !is_target_ty { - msg("this", " because this is a foreign trait") + fn push_to_foreign_or_name<'tcx>( + is_foreign: bool, + foreign: &mut Vec, + name: &mut Vec>, + span: Span, + sname: &'tcx str, + ) { + if is_foreign { + foreign.push(errors::OnlyCurrentTraitsForeign { span }) } else { - msg("this", &format!(" because {name} are always foreign")) + name.push(errors::OnlyCurrentTraitsName { span, name: sname }); + } + } + + let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty; + + match &ty.kind() { + ty::Slice(_) => { + push_to_foreign_or_name( + is_foreign, + &mut foreign, + &mut name, + span, + "slices", + ); + } + ty::Array(..) => { + push_to_foreign_or_name( + is_foreign, + &mut foreign, + &mut name, + span, + "arrays", + ); + } + ty::Tuple(..) => { + push_to_foreign_or_name( + is_foreign, + &mut foreign, + &mut name, + span, + "tuples", + ); } - }; - let msg = match &ty.kind() { - ty::Slice(_) => this("slices"), - ty::Array(..) => this("arrays"), - ty::Tuple(..) => this("tuples"), ty::Alias(ty::Opaque, ..) => { - "type alias impl trait is treated as if it were foreign, \ - because its hidden type could be from a foreign crate" - .to_string() + opaque.push(errors::OnlyCurrentTraitsOpaque { span }) } ty::RawPtr(ptr_ty) => { - emit_newtype_suggestion_for_raw_ptr( - full_impl_span, - self_ty, - self_ty_span, - ptr_ty, - &mut err, - ); - - msg(&format!("`{ty}`"), " because raw pointers are always foreign") + if !self_ty.has_param() { + let mut_key = ptr_ty.mutbl.prefix_str(); + sugg = Some(errors::OnlyCurrentTraitsPointerSugg { + wrapper_span: self_ty_span, + struct_span: full_impl_span.shrink_to_lo(), + mut_key, + ptr_ty: ptr_ty.ty, + }); + } + pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); } - _ => msg(&format!("`{ty}`"), ""), - }; - - if is_target_ty { - // Point at `D` in `impl for C in D` - err.span_label(self_ty_span, msg); - } else { - // Point at `C` in `impl for C in D` - err.span_label(trait_span, msg); + _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }), } } - err.note("define and implement a trait or new type instead"); - err.emit() + + let err_struct = match self_ty.kind() { + ty::Adt(..) => errors::OnlyCurrentTraits::Outside { + span: sp, + note: (), + opaque, + foreign, + name, + pointer, + ty: ty_diag, + sugg, + }, + _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive { + span: sp, + note: (), + opaque, + foreign, + name, + pointer, + ty: ty_diag, + sugg, + }, + _ => errors::OnlyCurrentTraits::Arbitrary { + span: sp, + note: (), + opaque, + foreign, + name, + pointer, + ty: ty_diag, + sugg, + }, + }; + tcx.sess.emit_err(err_struct) } traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { let mut sp = sp; @@ -399,85 +433,18 @@ fn emit_orphan_check_error<'tcx>( } match local_type { - Some(local_type) => struct_span_err!( - tcx.sess, - sp, - E0210, - "type parameter `{}` must be covered by another type \ - when it appears before the first local type (`{}`)", - param_ty, - local_type - ) - .span_label( - sp, - format!( - "type parameter `{param_ty}` must be covered by another type \ - when it appears before the first local type (`{local_type}`)" - ), - ) - .note( - "implementing a foreign trait is only possible if at \ - least one of the types for which it is implemented is local, \ - and no uncovered type parameters appear before that first \ - local type", - ) - .note( - "in this case, 'before' refers to the following order: \ - `impl<..> ForeignTrait for T0`, \ - where `T0` is the first and `Tn` is the last", - ) - .emit(), - None => struct_span_err!( - tcx.sess, - sp, - E0210, - "type parameter `{}` must be used as the type parameter for some \ - local type (e.g., `MyStruct<{}>`)", + Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal { + span: sp, + note: (), param_ty, - param_ty - ) - .span_label( - sp, - format!( - "type parameter `{param_ty}` must be used as the type parameter for some \ - local type", - ), - ) - .note( - "implementing a foreign trait is only possible if at \ - least one of the types for which it is implemented is local", - ) - .note( - "only traits defined in the current crate can be \ - implemented for a type parameter", - ) - .emit(), + local_type, + }), + None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }), } } }) } -fn emit_newtype_suggestion_for_raw_ptr( - full_impl_span: Span, - self_ty: Ty<'_>, - self_ty_span: Span, - ptr_ty: &ty::TypeAndMut<'_>, - diag: &mut Diagnostic, -) { - if !self_ty.has_param() { - let mut_key = ptr_ty.mutbl.prefix_str(); - let msg_sugg = "consider introducing a new wrapper type".to_owned(); - let sugg = vec![ - ( - full_impl_span.shrink_to_lo(), - format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty), - ), - (self_ty_span, "WrapperType".to_owned()), - ]; - diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect); - } -} - /// Lint impls of auto traits if they are likely to have /// unsound or surprising effects on auto impls. fn lint_auto_trait_impl<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 221df4e36..9636c6144 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -14,14 +14,11 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use crate::astconv::AstConv; -use crate::check::intrinsic::intrinsic_operation_unsafety; -use crate::errors; -use hir::def::DefKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; @@ -40,6 +37,11 @@ use rustc_trait_selection::traits::ObligationCtxt; use std::iter; use std::ops::Bound; +use crate::astconv::AstConv; +use crate::check::intrinsic::intrinsic_operation_unsafety; +use crate::errors; +pub use type_of::test_opaque_hidden_types; + mod generics_of; mod item_bounds; mod predicates_of; @@ -76,7 +78,7 @@ pub fn provide(providers: &mut Providers) { fn_sig, impl_trait_ref, impl_polarity, - generator_kind, + coroutine_kind, collect_mod_item_types, is_type_alias_impl_trait, ..*providers @@ -212,7 +214,9 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( let mut is_fn = false; let mut is_const_or_static = false; - if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind { + if let Some(hir_ty) = hir_ty + && let hir::TyKind::BareFn(_) = hir_ty.kind + { is_fn = true; // Check if parent is const or static @@ -224,10 +228,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( Node::Item(&hir::Item { kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), .. - }) | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Const(..), - .. - }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + }) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) ); } @@ -1004,10 +1006,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { && let Some(lit) = meta.name_value_literal() { if seen_attr { - tcx.sess.span_err( - meta.span, - "duplicated `implement_via_object` meta item", - ); + tcx.sess.span_err(meta.span, "duplicated `implement_via_object` meta item"); } seen_attr = true; @@ -1021,7 +1020,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { _ => { tcx.sess.span_err( meta.span, - format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol), + format!( + "unknown literal passed to `implement_via_object` attribute: {}", + lit.symbol + ), ); } } @@ -1115,8 +1117,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { // Do not try to infer the return type for a impl method coming from a trait - if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = - tcx.hir().get_parent(hir_id) + if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id) && i.of_trait.is_some() { icx.astconv().ty_of_fn( @@ -1343,7 +1344,13 @@ fn suggest_impl_trait<'tcx>( if ocx.select_where_possible().is_empty() && let item_ty = infcx.resolve_vars_if_possible(item_ty) && let Some(item_ty) = item_ty.make_suggestable(tcx, false) - && let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(args), trait_def_id, assoc_item_def_id, item_ty) + && let Some(sugg) = formatter( + tcx, + infcx.resolve_vars_if_possible(args), + trait_def_id, + assoc_item_def_id, + item_ty, + ) { return Some(sugg); } @@ -1543,12 +1550,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( fty } -fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { +fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { match tcx.hir().get_by_def_id(def_id) { Node::Expr(&rustc_hir::Expr { kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }), .. - }) => tcx.hir().body(body).generator_kind(), + }) => tcx.hir().body(body).coroutine_kind(), _ => None, } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 4b7743fae..d746e6dea 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -169,8 +169,8 @@ impl<'tcx> TypeFolder> for AssocTyToOpaque<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Alias(ty::Projection, projection_ty) = ty.kind() - && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) - = self.tcx.opt_rpitit_info(projection_ty.def_id) + && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = + self.tcx.opt_rpitit_info(projection_ty.def_id) && fn_def_id == self.fn_def_id { self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 1298c0860..104da581e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{sym, Span, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -38,11 +38,38 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` let span = rustc_span::DUMMY_SP; - result.predicates = - tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), + let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { + // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, + // because only implementing `Self: Trait<.., false>` is currently not possible. + Some(( + ty::TraitRef::new( + tcx, + def_id, + ty::GenericArgs::for_item(tcx, def_id, |param, _| { + if param.is_host_effect() { + tcx.consts.true_.into() + } else { + tcx.mk_param_from_def(param) + } + }), + ) + .to_predicate(tcx), span, - )))); + )) + } else { + None + }; + result.predicates = tcx.arena.alloc_from_iter( + result + .predicates + .iter() + .copied() + .chain(std::iter::once(( + ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), + span, + ))) + .chain(non_const_bound), + ); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result @@ -180,7 +207,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // // default impl Foo for Bar { .. } // - // we add a default where clause `Foo: Bar`. We do a similar thing for traits + // we add a default where clause `Bar: Foo`. We do a similar thing for traits // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { @@ -389,7 +416,9 @@ fn const_evaluatable_predicates_of( let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; - if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind { + if let hir::Node::Item(item) = node + && let hir::ItemKind::Impl(impl_) = item.kind + { if let Some(of_trait) = &impl_.of_trait { debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); collector.visit_trait_ref(of_trait); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index eb4466449..6424d1c79 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -880,7 +880,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { (pair, r) }) .unzip(); - self.record_late_bound_vars(hir_id, binders.clone()); + self.record_late_bound_vars(hir_id, binders); // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1190,7 +1190,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { opt_parent_item } => { if let Some(parent_item) = opt_parent_item && let parent_generics = self.tcx.generics_of(parent_item) - && parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some() + && parent_generics + .param_def_id_to_index(self.tcx, region_def_id.to_def_id()) + .is_some() { break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id())); } @@ -1209,13 +1211,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // regular fns. if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin && let hir::LifetimeName::Param(param_id) = lifetime_ref.res - && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) + && let Some(generics) = + self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && param.is_elided_lifetime() && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.features().anonymous_lifetime_in_impl_trait { - let mut diag = rustc_session::parse::feature_err( + let mut diag = rustc_session::parse::feature_err( &self.tcx.sess.parse_sess, sym::anonymous_lifetime_in_impl_trait, lifetime_ref.ident.span, @@ -1225,25 +1228,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(generics) = self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) { - let new_param_sugg = if let Some(span) = - generics.span_for_lifetime_suggestion() - { - (span, "'a, ".to_owned()) - } else { - (generics.span, "<'a>".to_owned()) - }; + let new_param_sugg = + if let Some(span) = generics.span_for_lifetime_suggestion() { + (span, "'a, ".to_owned()) + } else { + (generics.span, "<'a>".to_owned()) + }; let lifetime_sugg = match lifetime_ref.suggestion_position() { - (hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()), - (hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()), - (hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()), - (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()), - (hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()), + (hir::LifetimeSuggestionPosition::Normal, span) => { + (span, "'a".to_owned()) + } + (hir::LifetimeSuggestionPosition::Ampersand, span) => { + (span, "'a ".to_owned()) + } + (hir::LifetimeSuggestionPosition::ElidedPath, span) => { + (span, "<'a>".to_owned()) + } + (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => { + (span, "'a, ".to_owned()) + } + (hir::LifetimeSuggestionPosition::ObjectDefault, span) => { + (span, "+ 'a".to_owned()) + } }; - let suggestions = vec![ - lifetime_sugg, - new_param_sugg, - ]; + let suggestions = vec![lifetime_sugg, new_param_sugg]; diag.span_label( lifetime_ref.ident.span, @@ -1378,7 +1387,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { opt_parent_item } => { if let Some(parent_item) = opt_parent_item && let parent_generics = self.tcx.generics_of(parent_item) - && parent_generics.param_def_id_to_index(self.tcx, param_def_id.to_def_id()).is_some() + && parent_generics + .param_def_id_to_index(self.tcx, param_def_id.to_def_id()) + .is_some() { break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id())); } @@ -1689,14 +1700,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id && self.tcx.def_kind(type_def_id) == DefKind::Trait - && let Some((mut bound_vars, assoc_fn)) = - BoundVarContext::supertrait_hrtb_vars( - self.tcx, - type_def_id, - binding.ident, - ty::AssocKind::Fn, - ) - { + && let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars( + self.tcx, + type_def_id, + binding.ident, + ty::AssocKind::Fn, + ) { bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map( |param| match param.kind { ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( @@ -1708,14 +1717,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, }, )); - bound_vars - .extend(self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars()); + bound_vars.extend( + self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(), + ); bound_vars } else { - self.tcx.sess.delay_span_bug( - binding.ident.span, - "bad return type notation here", - ); + self.tcx + .sess + .delay_span_bug(binding.ident.span, "bad return type notation here"); vec![] }; self.with(scope, |this| { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index ae62119b1..d7bd2a7b1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -11,6 +11,7 @@ use rustc_span::{Span, DUMMY_SP}; use super::ItemCtxt; use super::{bad_placeholder, is_suggestable_infer_ty}; +pub use opaque::test_opaque_hidden_types; mod opaque; @@ -30,10 +31,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id() == hir_id => { - return tcx.types.usize + return tcx.types.usize; } Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { - return tcx.typeck(def_id).node_type(e.hir_id) + return tcx.typeck(def_id).node_type(e.hir_id); } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) @@ -43,36 +44,38 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { _ => false, }) => { - return tcx.typeck(def_id).node_type(hir_id) + return tcx.typeck(def_id).node_type(hir_id); } Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { - return tcx - .adt_def(tcx.hir().get_parent_item(hir_id)) - .repr() - .discr_type() - .to_ty(tcx) + return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx); } Node::GenericParam(&GenericParam { def_id: param_def_id, kind: GenericParamKind::Const { default: Some(ct), .. }, .. }) if ct.hir_id == hir_id => { - return tcx.type_of(param_def_id) + return tcx + .type_of(param_def_id) .no_bound_vars() - .expect("const parameter types cannot be generic") + .expect("const parameter types cannot be generic"); } - Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) - if let Node::TraitRef(trait_ref) = tcx.hir().get( - tcx.hir().parent_id(binding_id) - ) => + Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) + if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) => { let Some(trait_def_id) = trait_ref.trait_def_id() else { - return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait"); + return Ty::new_error_with_message( + tcx, + tcx.def_span(def_id), + "Could not find trait", + ); }; let assoc_items = tcx.associated_items(trait_def_id); let assoc_item = assoc_items.find_by_name_and_kind( - tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), + tcx, + binding.ident, + ty::AssocKind::Const, + def_id.to_def_id(), ); return if let Some(assoc_item) = assoc_item { tcx.type_of(assoc_item.def_id) @@ -80,8 +83,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .expect("const parameter types cannot be generic") } else { // FIXME(associated_const_equality): add a useful error message here. - Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait") - } + Ty::new_error_with_message( + tcx, + tcx.def_span(def_id), + "Could not find associated const on trait", + ) + }; } // This match arm is for when the def_id appears in a GAT whose @@ -138,7 +145,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } else { // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", ); @@ -155,7 +163,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // As there is no relevant param for `def_id`, we simply return // `None` here. let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unable to find type-dependent def for {parent_node_id:?}"), ); @@ -196,14 +205,16 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { path } else { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unable to find const parent for {hir_id} in pat {pat:?}"), ); } } _ => { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unexpected const parent path {parent_node:?}"), ); @@ -216,16 +227,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| { let args = seg.args?; args.args - .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) - .map(|index| (index, seg)).or_else(|| args.bindings .iter() - .filter_map(TypeBinding::opt_const) - .position(|ct| ct.hir_id == hir_id) - .map(|idx| (idx, seg))) + .filter(|arg| arg.is_ty_or_const()) + .position(|arg| arg.hir_id() == hir_id) + .map(|index| (index, seg)) + .or_else(|| { + args.bindings + .iter() + .filter_map(TypeBinding::opt_const) + .position(|ct| ct.hir_id == hir_id) + .map(|idx| (idx, seg)) + }) }) else { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), "no arg matching AnonConst in path", ); @@ -234,7 +249,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); @@ -244,10 +260,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } - _ => return Ty::new_error_with_message(tcx, - tcx.def_span(def_id), - format!("unexpected const parent in type_of(): {parent_node:?}"), - ), + _ => { + return Ty::new_error_with_message( + tcx, + tcx.def_span(def_id), + format!("unexpected const parent in type_of(): {parent_node:?}"), + ); + } }; debug!(?parent_node); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 0544c5ca8..e8ab2651d 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,12 +1,25 @@ use rustc_errors::StashKey; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::DUMMY_SP; +use rustc_span::{sym, DUMMY_SP}; -use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType}; +use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType}; + +pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { + let type_of = tcx.type_of(id.owner_id).instantiate_identity(); + + tcx.sess.emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }); + } + } + } +} /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". @@ -170,9 +183,17 @@ impl TaitConstraintLocator<'_> { }; // Use borrowck to get the type with unerased regions. - let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types; - debug!(?concrete_opaque_types); - if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) { + let borrowck_results = &self.tcx.mir_borrowck(item_def_id); + + // If the body was tainted, then assume the opaque may have been constrained and just set it to error. + if let Some(guar) = borrowck_results.tainted_by_errors { + self.found = + Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); + return; + } + + debug!(?borrowck_results.concrete_opaque_types); + if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) { debug!(?concrete_type, "found constraint"); if let Some(prev) = &mut self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 5591fa6f2..ed5e9dd2b 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::source_map::Span; +use rustc_span::Span; use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 0efe82b20..dd83b5b6f 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -96,7 +96,7 @@ pub struct CopyImplOnTypeWithDtor { #[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")] pub struct MultipleRelaxedDefaultBounds { #[primary_span] - pub span: Span, + pub spans: Vec, } #[derive(Diagnostic)] @@ -226,7 +226,9 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { let mut suggested = false; // Don't suggest setting the type params if there are some already: the order is // tricky to get right and the user will already know what the syntax is. - if let Some(snippet) = self.span_snippet && self.empty_generic_args { + if let Some(snippet) = self.span_snippet + && self.empty_generic_args + { if snippet.ends_with('>') { // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion // we would have to preserve the right order. For now, as clearly the user is @@ -465,6 +467,14 @@ pub(crate) struct VariancesOf { pub variances_of: String, } +#[derive(Diagnostic)] +#[diag(hir_analysis_type_of)] +pub(crate) struct TypeOf<'tcx> { + #[primary_span] + pub span: Span, + pub type_of: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_pass_to_variadic_function, code = "E0617")] pub(crate) struct PassToVariadicFunction<'tcx, 'a> { @@ -673,7 +683,6 @@ pub(crate) struct SIMDFFIHighlyExperimental { } #[derive(Diagnostic)] - pub enum ImplNotMarkedDefault { #[diag(hir_analysis_impl_not_marked_default, code = "E0520")] #[note] @@ -1149,3 +1158,174 @@ pub struct ImplForTyRequires { pub trait_name: String, pub ty: String, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")] +#[note] +pub struct TraitsWithDefaultImpl<'a> { + #[primary_span] + pub span: Span, + pub traits: String, + pub problematic_kind: &'a str, + pub self_ty: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cross_crate_traits, code = "E0321")] +pub struct CrossCrateTraits<'a> { + #[primary_span] + #[label] + pub span: Span, + pub traits: String, + pub self_ty: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")] +pub struct CrossCrateTraitsDefined { + #[primary_span] + #[label] + pub span: Span, + pub traits: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_ty_param_first_local, code = "E0210")] +#[note] +pub struct TyParamFirstLocal<'a> { + #[primary_span] + #[label] + pub span: Span, + #[note(hir_analysis_case_note)] + pub note: (), + pub param_ty: Ty<'a>, + pub local_type: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_ty_param_some, code = "E0210")] +#[note] +pub struct TyParamSome<'a> { + #[primary_span] + #[label] + pub span: Span, + #[note(hir_analysis_only_note)] + pub note: (), + pub param_ty: Ty<'a>, +} + +#[derive(Diagnostic)] +pub enum OnlyCurrentTraits<'a> { + #[diag(hir_analysis_only_current_traits_outside, code = "E0117")] + Outside { + #[primary_span] + #[label(hir_analysis_only_current_traits_label)] + span: Span, + #[note(hir_analysis_only_current_traits_note)] + note: (), + #[subdiagnostic] + opaque: Vec, + #[subdiagnostic] + foreign: Vec, + #[subdiagnostic] + name: Vec>, + #[subdiagnostic] + pointer: Vec>, + #[subdiagnostic] + ty: Vec>, + #[subdiagnostic] + sugg: Option>, + }, + #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")] + Primitive { + #[primary_span] + #[label(hir_analysis_only_current_traits_label)] + span: Span, + #[note(hir_analysis_only_current_traits_note)] + note: (), + #[subdiagnostic] + opaque: Vec, + #[subdiagnostic] + foreign: Vec, + #[subdiagnostic] + name: Vec>, + #[subdiagnostic] + pointer: Vec>, + #[subdiagnostic] + ty: Vec>, + #[subdiagnostic] + sugg: Option>, + }, + #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")] + Arbitrary { + #[primary_span] + #[label(hir_analysis_only_current_traits_label)] + span: Span, + #[note(hir_analysis_only_current_traits_note)] + note: (), + #[subdiagnostic] + opaque: Vec, + #[subdiagnostic] + foreign: Vec, + #[subdiagnostic] + name: Vec>, + #[subdiagnostic] + pointer: Vec>, + #[subdiagnostic] + ty: Vec>, + #[subdiagnostic] + sugg: Option>, + }, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_opaque)] +pub struct OnlyCurrentTraitsOpaque { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_foreign)] +pub struct OnlyCurrentTraitsForeign { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_name)] +pub struct OnlyCurrentTraitsName<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_pointer)] +pub struct OnlyCurrentTraitsPointer<'a> { + #[primary_span] + pub span: Span, + pub pointer: Ty<'a>, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_ty)] +pub struct OnlyCurrentTraitsTy<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_analysis_only_current_traits_pointer_sugg, + applicability = "maybe-incorrect" +)] +pub struct OnlyCurrentTraitsPointerSugg<'a> { + #[suggestion_part(code = "WrapperType")] + pub wrapper_span: Span, + #[suggestion_part(code = "struct WrapperType(*{mut_key}{ptr_ty});\n\n")] + pub struct_span: Span, + pub mut_key: &'a str, + pub ptr_ty: Ty<'a>, +} 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 3760195a5..7941861fd 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 @@ -131,7 +131,9 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node } fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { - if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { + if let Node::Impl(impl2_id) = impl2_node + && tcx.associated_item_def_ids(impl1_def_id).is_empty() + { let base_impl_span = tcx.def_span(impl2_id); tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span }); } @@ -196,7 +198,7 @@ fn get_impl_args( let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors); + let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } @@ -376,9 +378,9 @@ fn check_predicates<'tcx>( let always_applicable_traits = impl1_predicates .iter() .copied() - .filter(|(clause, _span)| { + .filter(|&(clause, _span)| { matches!( - trait_predicate_kind(tcx, clause.as_predicate()), + trait_specialization_kind(tcx, clause), Some(TraitSpecializationKind::AlwaysApplicable) ) }) @@ -402,7 +404,7 @@ fn check_predicates<'tcx>( .iter() .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) { - check_specialization_on(tcx, clause.as_predicate(), span) + check_specialization_on(tcx, clause, span) } } } @@ -441,19 +443,16 @@ fn trait_predicates_eq<'tcx>( } #[instrument(level = "debug", skip(tcx))] -fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) { - match predicate.kind().skip_binder() { +fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) { + match clause.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. - _ if predicate.is_global() => (), + _ if clause.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: _, - })) => { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { if !matches!( - trait_predicate_kind(tcx, predicate), + trait_specialization_kind(tcx, clause), Some(TraitSpecializationKind::Marker) ) { tcx.sess @@ -467,10 +466,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc .emit(); } } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_ty, - term, - })) => { + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { tcx.sess .struct_span_err( span, @@ -478,7 +474,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc ) .emit(); } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => { + ty::ClauseKind::ConstArgHasType(..) => { // FIXME(min_specialization), FIXME(const_generics): // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure // about the actual rules that would be sound. Can't just always error here because otherwise @@ -490,33 +486,25 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc } _ => { tcx.sess - .struct_span_err(span, format!("cannot specialize on predicate `{predicate}`")) + .struct_span_err(span, format!("cannot specialize on predicate `{clause}`")) .emit(); } } } -fn trait_predicate_kind<'tcx>( +fn trait_specialization_kind<'tcx>( tcx: TyCtxt<'tcx>, - predicate: ty::Predicate<'tcx>, + clause: ty::Clause<'tcx>, ) -> Option { - match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: _, - })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind), - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous => None, + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { + Some(tcx.trait_def(trait_ref.def_id).specialization_kind) + } + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::TypeOutlives(_) + | ty::ClauseKind::Projection(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 03963925d..2b8219c01 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -57,6 +57,9 @@ This API is completely unstable and subject to change. #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] @@ -178,14 +181,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; } - tcx.sess.track_errors(|| { - tcx.sess.time("impl_wf_inference", || { - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)) - }); - })?; - tcx.sess.track_errors(|| { tcx.sess.time("coherence_checking", || { + // Check impls constrain their parameters + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); + for &trait_def_id in tcx.all_local_trait_impls(()).keys() { tcx.ensure().coherent_trait(trait_def_id); } @@ -202,17 +202,23 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; } - tcx.sess.track_errors(|| { - tcx.sess.time("wf_checking", || { - tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) - }); - })?; + let errs = tcx.sess.time("wf_checking", || { + tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) + }); // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync. tcx.sess.time("item_types_checking", || { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); + // HACK: `check_mod_type_wf` may spuriously emit errors due to `delay_span_bug`, even if those errors + // only actually get emitted in `check_mod_item_types`. + errs?; + + if tcx.features().rustc_attrs { + tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?; + } + // Freeze definitions as we don't add new ones at this point. This improves performance by // allowing lock-free access to them. tcx.untracked().definitions.freeze(); diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 61b182b1b..76bd370a6 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if self.missing_lifetimes() { "lifetime" } else { "generic" } } + /// Returns true if the generic type is a trait + /// and is being referred to from one of its trait impls + fn is_in_trait_impl(&self) -> bool { + if self.tcx.is_trait(self.def_id) { + // Here we check if the reference to the generic type + // is from the 'of_trait' field of the enclosing impl + + let parent = self.tcx.hir().get_parent(self.path_segment.hir_id); + let parent_item = self + .tcx + .hir() + .get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id); + + // Get the HIR id of the trait ref + let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else { + return false; + }; + + // Get the HIR id of the 'of_trait' field of the impl + let hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl(hir::Impl { + of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }), + .. + }), + .. + }) = parent_item + else { + return false; + }; + + // Check that trait is referred to from the of_trait field of impl + trait_ref_id == id_in_of_trait + } else { + false + } + } + fn num_provided_args(&self) -> usize { if self.missing_lifetimes() { self.num_provided_lifetime_args() @@ -316,12 +354,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } // Suggest `'_` when in function parameter or elided function return. - if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id { + if let Some(fn_decl) = node.fn_decl() + && let Some(ty_id) = ty_id + { let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id); - let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id); + let in_ret = + matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id); if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) { - return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::>().join(", "); + return std::iter::repeat("'_".to_owned()) + .take(num_params_to_take) + .collect::>() + .join(", "); } } @@ -730,28 +774,27 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id) - && let Some(parent_node) = self.tcx.hir().find(parent_node) - && let hir::Node::Expr(expr) = parent_node { + && let Some(parent_node) = self.tcx.hir().find(parent_node) + && let hir::Node::Expr(expr) = parent_node + { match &expr.kind { - hir::ExprKind::Path(qpath) => { - self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( + hir::ExprKind::Path(qpath) => self + .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( err, qpath, msg, num_assoc_fn_excess_args, - num_trait_generics_except_self - ) - }, - hir::ExprKind::MethodCall(..) => { - self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + num_trait_generics_except_self, + ), + hir::ExprKind::MethodCall(..) => self + .suggest_moving_args_from_assoc_fn_to_trait_for_method_call( err, trait_, expr, msg, num_assoc_fn_excess_args, - num_trait_generics_except_self - ) - }, + num_trait_generics_except_self, + ), _ => return, } } @@ -766,23 +809,25 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { num_trait_generics_except_self: usize, ) { if let hir::QPath::Resolved(_, path) = qpath - && let Some(trait_path_segment) = path.segments.get(0) { + && let Some(trait_path_segment) = path.segments.get(0) + { let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params(); - if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self + if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args + == num_trait_generics_except_self { if let Some(span) = self.gen_args.span_ext() - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + { let sugg = vec![ - (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)), - (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()) + ( + self.path_segment.ident.span, + format!("{}::{}", snippet, self.path_segment.ident), + ), + (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()), ]; - err.multipart_suggestion( - msg, - sugg, - Applicability::MaybeIncorrect - ); + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); } } } @@ -948,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // If there is a single unbound associated type and a single excess generic param // suggest replacing the generic param with the associated type bound if provided_args_matches_unbound_traits && !unbound_types.is_empty() { - let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; - let suggestions = iter::zip(unused_generics, &unbound_types) - .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = "))) - .collect::>(); - - if !suggestions.is_empty() { - err.multipart_suggestion_verbose( - format!( - "replace the generic bound{s} with the associated type{s}", - s = pluralize!(unbound_types.len()) - ), - suggestions, - Applicability::MaybeIncorrect, - ); + // Don't suggest if we're in a trait impl as + // that would result in invalid syntax (fixes #116464) + if !self.is_in_trait_impl() { + let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; + let suggestions = iter::zip(unused_generics, &unbound_types) + .map(|(potential, name)| { + (potential.span().shrink_to_lo(), format!("{name} = ")) + }) + .collect::>(); + + if !suggestions.is_empty() { + err.multipart_suggestion_verbose( + format!( + "replace the generic bound{s} with the associated type{s}", + s = pluralize!(unbound_types.len()) + ), + suggestions, + Applicability::MaybeIncorrect, + ); + } } } else if remove_entire_generics { let span = self diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 61d9c989e..5f8b1ace6 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -235,7 +235,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // leaf type -- noop } - ty::FnDef(..) | ty::Generator(..) | ty::Closure(..) => { + ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) => { bug!("Unexpected closure type in variance computation"); } @@ -312,7 +312,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => { + ty::Placeholder(..) | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Infer(..) => { bug!("unexpected type encountered in variance inference: {}", ty); } } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 85e0000ab..9fb39a0e9 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -192,5 +192,5 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } } } - tcx.arena.alloc_from_iter(collector.variances.into_iter()) + tcx.arena.alloc_from_iter(collector.variances) } -- cgit v1.2.3