diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
16 files changed, 550 insertions, 483 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 32fec0604c0..485dd1d2204 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,8 +1,9 @@ use std::cell::LazyCell; use std::ops::ControlFlow; -use rustc_abi::FieldIdx; +use rustc_abi::{ExternAbi, FieldIdx}; use rustc_attr_data_structures::ReprAttr::ReprPacked; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{EmissionGuarantee, MultiSpan}; @@ -12,7 +13,6 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS, - UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, }; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; @@ -52,49 +52,22 @@ fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T } pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { - // FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix - // things like #86232. + // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this + // currently only guards function imports, function definitions, and function pointer types. + // Functions in trait declarations can still use "deprecated" ABIs without any warning. match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { AbiMapping::Direct(..) => (), + // already erred in rustc_ast_lowering AbiMapping::Invalid => { - let mut err = struct_span_code_err!( - tcx.dcx(), - span, - E0570, - "`{abi}` is not a supported ABI for the current target", - ); - add_abi_diag_help(abi, &mut err); - err.emit(); + tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering")); } AbiMapping::Deprecated(..) => { tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message("use of calling convention not supported on this target"); - add_abi_diag_help(abi, lint); - }); - } - } -} - -pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { - // This is always an FCW, even for `AbiMapping::Invalid`, since we started linting later than - // in `check_abi` above. - match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { - AbiMapping::Direct(..) => (), - // This is not a redundant match arm: these ABIs started linting after introducing - // UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to - // avoid expanding the scope of that lint so it can move to a hard error sooner. - AbiMapping::Deprecated(..) => { - tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message("use of calling convention not supported on this target"); - add_abi_diag_help(abi, lint); - }); - } - AbiMapping::Invalid => { - tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| { lint.primary_message(format!( - "the calling convention {abi} is not supported on this target" + "{abi} is not a supported ABI for the current target" )); + add_abi_diag_help(abi, lint); }); } } @@ -103,7 +76,7 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { if fn_sig.abi == ExternAbi::Custom { // Function definitions that use `extern "custom"` must be naked functions. - if !tcx.has_attr(def_id, sym::naked) { + if !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(_)) { tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction { span: fn_sig_span, naked_span: tcx.def_span(def_id).shrink_to_lo(), @@ -867,6 +840,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let hir::ItemKind::ForeignMod { abi, items } = it.kind else { return; }; + check_abi(tcx, it.hir_id(), it.span, abi); for item in items { @@ -1384,7 +1358,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), ty::Adt(def, args) => { - if !def.did().is_local() && !tcx.has_attr(def.did(), sym::rustc_pub_transparent) + if !def.did().is_local() + && !attrs::find_attr!( + tcx.get_all_attrs(def.did()), + AttributeKind::PubTransparent(_) + ) { let non_exhaustive = def.is_variant_list_non_exhaustive() || def diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c5c7e6b2aa7..5cec3331bb1 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -72,10 +72,11 @@ pub mod wfcheck; use std::num::NonZero; -pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi}; -use rustc_abi::{ExternAbi, VariantIdx}; +pub use check::{check_abi, check_custom_abi}; +use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_hir::LangItem; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::DenseBitSet; @@ -113,7 +114,15 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> { - tcx.calculate_dtor(def_id, always_applicable::check_drop_impl) + let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl); + if dtor.is_none() && tcx.features().async_drop() { + if let Some(async_dtor) = adt_async_destructor(tcx, def_id) { + // When type has AsyncDrop impl, but doesn't have Drop impl, generate error + let span = tcx.def_span(async_dtor.impl_did); + tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span }); + } + } + dtor } fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> { @@ -302,9 +311,7 @@ fn default_body_is_unstable( reason: reason_str, }); - let inject_span = item_did - .as_local() - .and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id))); + let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span()); rustc_session::parse::add_feature_diagnostics_for_issue( &mut err, &tcx.sess, @@ -331,7 +338,7 @@ fn bounds_from_generic_predicates<'tcx>( ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); - if !tcx.is_default_trait(def_id) { + if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) { // Do not add that restriction to the list if it is a positive requirement. entry.push(trait_predicate.def_id()); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b8dc01cbc03..d05e381f8c8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -382,8 +382,6 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; - check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - // Check that an item definition in a subtrait is shadowing a supertrait item. lint_item_shadowing_supertrait_item(tcx, def_id); @@ -832,70 +830,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> { } } -fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { - match ty.kind { - hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { - [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), - _ => false, - }, - _ => false, - } -} - -/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items. -/// -/// In such cases, suggest using `Self` instead. -fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { - let (trait_ident, trait_def_id) = - match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) { - hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id), - _ => return, - }, - _ => return, - }; - let mut trait_should_be_self = vec![]; - match &item.kind { - hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty)) - if could_be_self(trait_def_id.def_id, ty) => - { - trait_should_be_self.push(ty.span) - } - hir::TraitItemKind::Fn(sig, _) => { - for ty in sig.decl.inputs { - if could_be_self(trait_def_id.def_id, ty) { - trait_should_be_self.push(ty.span); - } - } - match sig.decl.output { - hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => { - trait_should_be_self.push(ty.span); - } - _ => {} - } - } - _ => {} - } - if !trait_should_be_self.is_empty() { - if tcx.is_dyn_compatible(trait_def_id) { - return; - } - let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); - tcx.dcx() - .struct_span_err( - trait_should_be_self, - "associated item referring to unboxed trait object for its own trait", - ) - .with_span_label(trait_ident.span, "in this trait") - .with_multipart_suggestion( - "you might have meant to use `Self` to refer to the implementing type", - sugg, - Applicability::MachineApplicable, - ) - .emit(); - } -} - fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) { let item_name = tcx.item_name(trait_item_def_id.to_def_id()); let trait_def_id = tcx.local_parent(trait_item_def_id); @@ -1064,7 +998,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]), }; if let Some(features) = may_suggest_feature { - tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features); + tcx.disabled_nightly_features(&mut diag, features); } Err(diag.emit()) @@ -1258,6 +1192,11 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant debug!(?item.owner_id); let def_id = item.owner_id.def_id; + if tcx.is_lang_item(def_id.into(), LangItem::PointeeSized) { + // `PointeeSized` is removed during lowering. + return Ok(()); + } + let trait_def = tcx.trait_def(def_id); if trait_def.is_marker || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 6e22ac5a28a..c967e87bfd8 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -21,6 +21,7 @@ use std::ops::Bound; use rustc_abi::ExternAbi; use rustc_ast::Recovered; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ @@ -34,16 +35,22 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions}; +use rustc_middle::ty::{ + self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions, +}; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations}; +use rustc_trait_selection::traits::{ + FulfillmentError, ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations, +}; use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; +use crate::hir_ty_lowering::{ + FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason, +}; pub(crate) mod dump; mod generics_of; @@ -364,6 +371,58 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident)) } + #[instrument(level = "debug", skip(self, _span), ret)] + fn select_inherent_assoc_candidates( + &self, + _span: Span, + self_ty: Ty<'tcx>, + candidates: Vec<InherentAssocCandidate>, + ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) { + assert!(!self_ty.has_infer()); + + // We don't just call the normal normalization routine here as we can't provide the + // correct `ParamEnv` and it would be wrong to invoke arbitrary trait solving under + // the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do + // this just to make resolution a little bit smarter. + let self_ty = self.tcx.expand_free_alias_tys(self_ty); + debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty); + + let candidates = candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); + + // See comment on doing this operation for `self_ty` + let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); + debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); + + // We treat parameters in the self ty as rigid and parameters in the impl ty as infers + // because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing + // `Foo<T>::IAT` from unifying with `impl Foo<u8>`. + // + // We don't really care about a depth limit here because we're only working with user-written + // types and if they wrote a type that would take hours to walk then that's kind of on them. On + // the other hand the default depth limit is relatively low and could realistically be hit by + // users in normal cases. + // + // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases + // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl<T> Foo<T, T>` would + // be considered a valid candidate when resolving `Foo<u8, u16>::IAT`. + // + // Not replacing escaping bound vars in `self_ty` with placeholders also leads to slightly worse + // resolution, but it probably won't come up in practice and it would be backwards compatible + // to switch over to doing that. + ty::DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify_with_depth( + self_ty, + impl_ty, + usize::MAX, + ) + }) + .collect(); + + (candidates, vec![]) + } + fn lower_assoc_item_path( &self, span: Span, @@ -1093,22 +1152,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive); let is_fundamental = tcx.has_attr(def_id, sym::fundamental); - // FIXME: We could probably do way better attribute validation here. - let mut skip_array_during_method_dispatch = false; - let mut skip_boxed_slice_during_method_dispatch = false; - for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) { - if let Some(lst) = attr.meta_item_list() { - for item in lst { - if let Some(ident) = item.ident() { - match ident.as_str() { - "array" => skip_array_during_method_dispatch = true, - "boxed_slice" => skip_boxed_slice_during_method_dispatch = true, - _ => (), - } - } - } - } - } + let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice] + ) + .unwrap_or([false; 2]); let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) { ty::trait_def::TraitSpecializationKind::Marker diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 5f1cdeddc19..53c44cdc411 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -44,6 +44,14 @@ fn associated_type_bounds<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { + icx.lowerer().add_sizedness_bounds( + &mut bounds, + item_ty, + hir_bounds, + None, + None, + span, + ); icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); } // `ConstIfConst` is only interested in `~const` bounds. @@ -333,6 +341,14 @@ fn opaque_type_bounds<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { + icx.lowerer().add_sizedness_bounds( + &mut bounds, + item_ty, + hir_bounds, + None, + None, + span, + ); icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); } //`ConstIfConst` is only interested in `~const` bounds. diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ce0f83d0ec2..c337765c5fe 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -162,7 +162,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .map(|t| ty::Binder::dummy(t.instantiate_identity())); } } - ItemKind::Trait(_, _, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, _, self_bounds) => { is_trait = Some((self_bounds, item.span)); @@ -183,21 +182,29 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // and the explicit where-clauses, but to get the full set of predicates // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. - if let Some(self_bounds) = is_trait { + if let Some((self_bounds, span)) = is_trait { let mut bounds = Vec::new(); icx.lowerer().lower_bounds( tcx.types.self_param, - self_bounds.0, + self_bounds, &mut bounds, ty::List::empty(), PredicateFilter::All, ); + icx.lowerer().add_sizedness_bounds( + &mut bounds, + tcx.types.self_param, + self_bounds, + None, + Some(def_id), + span, + ); icx.lowerer().add_default_super_traits( def_id, &mut bounds, - self_bounds.0, + self_bounds, hir_generics, - self_bounds.1, + span, ); predicates.extend(bounds); } @@ -224,6 +231,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Vec::new(); // Implicit bounds are added to type params unless a `?Trait` bound is found + icx.lowerer().add_sizedness_bounds( + &mut bounds, + param_ty, + &[], + Some((param.def_id, hir_generics.predicates)), + None, + param.span, + ); icx.lowerer().add_default_traits( &mut bounds, param_ty, 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 d45f0475e99..95743f9a63e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2177,84 +2177,80 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { /// Walk the generics of the item for a trait bound whose self type /// corresponds to the expected res, and return the trait def id. fn for_each_trait_bound_on_res(&self, expected_res: Res) -> impl Iterator<Item = DefId> { - std::iter::from_coroutine( - #[coroutine] - move || { - let mut scope = self.scope; - loop { - let hir_id = match *scope { - Scope::Binder { hir_id, .. } => Some(hir_id), - Scope::Root { opt_parent_item: Some(parent_def_id) } => { - Some(self.tcx.local_def_id_to_hir_id(parent_def_id)) - } - Scope::Body { .. } - | Scope::ObjectLifetimeDefault { .. } - | Scope::Supertrait { .. } - | Scope::TraitRefBoundary { .. } - | Scope::LateBoundary { .. } - | Scope::Opaque { .. } - | Scope::Root { opt_parent_item: None } => None, - }; + gen move { + let mut scope = self.scope; + loop { + let hir_id = match *scope { + Scope::Binder { hir_id, .. } => Some(hir_id), + Scope::Root { opt_parent_item: Some(parent_def_id) } => { + Some(self.tcx.local_def_id_to_hir_id(parent_def_id)) + } + Scope::Body { .. } + | Scope::ObjectLifetimeDefault { .. } + | Scope::Supertrait { .. } + | Scope::TraitRefBoundary { .. } + | Scope::LateBoundary { .. } + | Scope::Opaque { .. } + | Scope::Root { opt_parent_item: None } => None, + }; - if let Some(hir_id) = hir_id { - let node = self.tcx.hir_node(hir_id); - // If this is a `Self` bound in a trait, yield the trait itself. - // Specifically, we don't need to look at any supertraits since - // we already do that in `BoundVarContext::supertrait_hrtb_vars`. - if let Res::SelfTyParam { trait_: _ } = expected_res - && let hir::Node::Item(item) = node - && let hir::ItemKind::Trait(..) = item.kind - { - // Yield the trait's def id. Supertraits will be - // elaborated from that. - yield item.owner_id.def_id.to_def_id(); - } else if let Some(generics) = node.generics() { - for pred in generics.predicates { - let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind - else { - continue; - }; - let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = - pred.bounded_ty.kind - else { - continue; - }; - // Match the expected res. - if bounded_path.res != expected_res { - continue; - } - for pred in pred.bounds { - match pred { - hir::GenericBound::Trait(poly_trait_ref) => { - if let Some(def_id) = - poly_trait_ref.trait_ref.trait_def_id() - { - yield def_id; - } + if let Some(hir_id) = hir_id { + let node = self.tcx.hir_node(hir_id); + // If this is a `Self` bound in a trait, yield the trait itself. + // Specifically, we don't need to look at any supertraits since + // we already do that in `BoundVarContext::supertrait_hrtb_vars`. + if let Res::SelfTyParam { trait_: _ } = expected_res + && let hir::Node::Item(item) = node + && let hir::ItemKind::Trait(..) = item.kind + { + // Yield the trait's def id. Supertraits will be + // elaborated from that. + yield item.owner_id.def_id.to_def_id(); + } else if let Some(generics) = node.generics() { + for pred in generics.predicates { + let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind else { + continue; + }; + let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = + pred.bounded_ty.kind + else { + continue; + }; + // Match the expected res. + if bounded_path.res != expected_res { + continue; + } + for pred in pred.bounds { + match pred { + hir::GenericBound::Trait(poly_trait_ref) => { + if let Some(def_id) = + poly_trait_ref.trait_ref.trait_def_id() + { + yield def_id; } - hir::GenericBound::Outlives(_) - | hir::GenericBound::Use(_, _) => {} } + hir::GenericBound::Outlives(_) + | hir::GenericBound::Use(_, _) => {} } } } } + } - match *scope { - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s } - | Scope::LateBoundary { s, .. } - | Scope::Opaque { s, .. } => { - scope = s; - } - Scope::Root { .. } => break, + match *scope { + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s } + | Scope::LateBoundary { s, .. } + | Scope::Opaque { s, .. } => { + scope = s; } + Scope::Root { .. } => break, } - }, - ) + } + } } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 141d96b57e5..902a2e15dff 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -452,13 +452,6 @@ fn infer_placeholder_type<'tcx>( if let Some(ty) = node.ty() { visitor.visit_ty_unambig(ty); } - // If we have just one span, let's try to steal a const `_` feature error. - let try_steal_span = if !tcx.features().generic_arg_infer() && visitor.spans.len() == 1 - { - visitor.spans.first().copied() - } else { - None - }; // If we didn't find any infer tys, then just fallback to `span`. if visitor.spans.is_empty() { visitor.spans.push(span); @@ -489,15 +482,7 @@ fn infer_placeholder_type<'tcx>( } } - if let Some(try_steal_span) = try_steal_span { - cx.dcx().try_steal_replace_and_emit_err( - try_steal_span, - StashKey::UnderscoreForArrayLengths, - diag, - ) - } else { - diag.emit() - } + diag.emit() }); Ty::new_error(tcx, guar) } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 8de2aec95a7..318aaab50f4 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1712,3 +1712,11 @@ pub(crate) struct AbiCustomClothedFunction { )] pub naked_span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_async_drop_without_sync_drop)] +#[help] +pub(crate) struct AsyncDropWithoutSyncDrop { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 106420faa4c..ea1dfdfd806 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -4,15 +4,15 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; -use rustc_hir::AmbigArg; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{AmbigArg, LangItem, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw}; use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -23,23 +23,213 @@ use crate::hir_ty_lowering::{ AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason, }; +#[derive(Debug, Default)] +struct CollectedBound { + /// `Trait` + positive: bool, + /// `?Trait` + maybe: bool, + /// `!Trait` + negative: bool, +} + +impl CollectedBound { + /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered. + fn any(&self) -> bool { + self.positive || self.maybe || self.negative + } +} + +#[derive(Debug)] +struct CollectedSizednessBounds { + // Collected `Sized` bounds + sized: CollectedBound, + // Collected `MetaSized` bounds + meta_sized: CollectedBound, + // Collected `PointeeSized` bounds + pointee_sized: CollectedBound, +} + +impl CollectedSizednessBounds { + /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered for `Sized`, + /// `MetaSized` or `PointeeSized`. + fn any(&self) -> bool { + self.sized.any() || self.meta_sized.any() || self.pointee_sized.any() + } +} + +fn search_bounds_for<'tcx>( + hir_bounds: &'tcx [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>), +) { + let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| { + for hir_bound in hir_bounds { + let hir::GenericBound::Trait(ptr) = hir_bound else { + continue; + }; + + f(ptr) + } + }; + + search_bounds(hir_bounds); + if let Some((self_ty, where_clause)) = self_ty_where_predicates { + for clause in where_clause { + if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind + && pred.is_param_bound(self_ty.to_def_id()) + { + search_bounds(pred.bounds); + } + } + } +} + +fn collect_unbounds<'tcx>( + hir_bounds: &'tcx [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, +) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> { + let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); + search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { + if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) { + unbounds.push(ptr); + } + }); + unbounds +} + +fn collect_bounds<'a, 'tcx>( + hir_bounds: &'a [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + target_did: DefId, +) -> CollectedBound { + let mut collect_into = CollectedBound::default(); + search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { + if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) { + return; + } + + match ptr.modifiers.polarity { + hir::BoundPolarity::Maybe(_) => collect_into.maybe = true, + hir::BoundPolarity::Negative(_) => collect_into.negative = true, + hir::BoundPolarity::Positive => collect_into.positive = true, + } + }); + collect_into +} + +fn collect_sizedness_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + hir_bounds: &'tcx [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + span: Span, +) -> CollectedSizednessBounds { + let sized_did = tcx.require_lang_item(LangItem::Sized, span); + let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did); + + let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); + let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did); + + let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did); + + CollectedSizednessBounds { sized, meta_sized, pointee_sized } +} + +/// Add a trait bound for `did`. +fn add_trait_bound<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, + self_ty: Ty<'tcx>, + did: DefId, + span: Span, +) { + let trait_ref = ty::TraitRef::new(tcx, did, [self_ty]); + // Preferable to put sizedness obligations first, since we report better errors for `Sized` + // ambiguity. + bounds.insert(0, (trait_ref.upcast(tcx), span)); +} + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - pub(crate) fn add_default_traits( + /// Skip `PointeeSized` bounds. + /// + /// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there + /// is actually the absence of any bounds. This avoids limitations around non-global where + /// clauses being preferred over item bounds (where `PointeeSized` bounds would be + /// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is + /// added to some items. + pub(crate) fn should_skip_sizedness_bound<'hir>( + &self, + bound: &'hir hir::GenericBound<'tcx>, + ) -> bool { + bound + .trait_ref() + .and_then(|tr| tr.trait_def_id()) + .map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized)) + .unwrap_or(false) + } + + /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type. + /// + /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit + /// sizedness bounds are present. + /// - On traits and trait aliases, add default `MetaSized` supertrait if no explicit sizedness + /// bounds are present. + /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if + /// a `?Sized` bound is present. + pub(crate) fn add_sizedness_bounds( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, - hir_bounds: &[hir::GenericBound<'tcx>], + hir_bounds: &'tcx [hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + trait_did: Option<LocalDefId>, span: Span, ) { - self.add_default_traits_with_filter( - bounds, - self_ty, - hir_bounds, - self_ty_where_predicates, - span, - |_| true, - ); + let tcx = self.tcx(); + + let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); + let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + + // If adding sizedness bounds to a trait, then there are some relevant early exits + if let Some(trait_did) = trait_did { + let trait_did = trait_did.to_def_id(); + // Never add a default supertrait to `PointeeSized`. + if trait_did == pointee_sized_did { + return; + } + // Don't add default sizedness supertraits to auto traits because it isn't possible to + // relax an automatically added supertrait on the defn itself. + if tcx.trait_is_auto(trait_did) { + return; + } + } else { + // Report invalid unbounds on sizedness-bounded generic parameters. + let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates); + self.check_and_report_invalid_unbounds_on_param(unbounds); + } + + let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span); + if (collected.sized.maybe || collected.sized.negative) + && !collected.sized.positive + && !collected.meta_sized.any() + && !collected.pointee_sized.any() + { + // `?Sized` is equivalent to `MetaSized` (but only add the bound if there aren't any + // other explicit ones) - this can happen for trait aliases as well as bounds. + add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); + } else if !collected.any() { + if trait_did.is_some() { + // If there are no explicit sizedness bounds on a trait then add a default + // `MetaSized` supertrait. + add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); + } else { + // If there are no explicit sizedness bounds on a parameter then add a default + // `Sized` bound. + let sized_did = tcx.require_lang_item(LangItem::Sized, span); + add_trait_bound(tcx, bounds, self_ty, sized_did, span); + } + } } /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds @@ -146,13 +336,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if !self.requires_default_supertraits(trait_bounds, trait_generics) { let self_ty_where_predicates = (parent, trait_item.generics.predicates); - self.add_default_traits_with_filter( + self.add_default_traits( bounds, tcx.types.self_param, &[], Some(self_ty_where_predicates), trait_item.span, - |tr| tr != hir::LangItem::Sized, ); } } @@ -174,41 +363,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); if self.requires_default_supertraits(hir_bounds, hir_generics) { let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); - self.add_default_traits_with_filter( + self.add_default_traits( bounds, self.tcx().types.self_param, hir_bounds, Some(self_ty_where_predicates), span, - |default_trait| default_trait != hir::LangItem::Sized, ); } } - pub(crate) fn add_default_traits_with_filter( + pub(crate) fn add_default_traits( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, - f: impl Fn(hir::LangItem) -> bool, ) { - self.tcx().default_traits().iter().filter(|&&default_trait| f(default_trait)).for_each( - |default_trait| { - self.add_default_trait( - *default_trait, - bounds, - self_ty, - hir_bounds, - self_ty_where_predicates, - span, - ); - }, - ); + self.tcx().default_traits().iter().for_each(|default_trait| { + self.add_default_trait( + *default_trait, + bounds, + self_ty, + hir_bounds, + self_ty_where_predicates, + span, + ); + }); } - /// Add a `Sized` or `experimental_default_bounds` bounds to the `bounds` if appropriate. + /// Add a `experimental_default_bounds` bound to the `bounds` if appropriate. /// /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`. pub(crate) fn add_default_trait( @@ -220,7 +405,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, ) { - let trait_id = self.tcx().lang_items().get(trait_); + let tcx = self.tcx(); + let trait_id = tcx.lang_items().get(trait_); if let Some(trait_id) = trait_id && self.do_not_provide_default_trait_bound( trait_id, @@ -228,11 +414,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty_where_predicates, ) { - // There was no `?Trait` or `!Trait` bound; - // add `Trait` if it's available. - let trait_ref = ty::TraitRef::new(self.tcx(), trait_id, [self_ty]); - // Preferable to put this obligation first, since we report better errors for sized ambiguity. - bounds.insert(0, (trait_ref.upcast(self.tcx()), span)); + add_trait_bound(tcx, bounds, self_ty, trait_id, span); } } @@ -242,90 +424,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_bounds: &'a [hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, ) -> bool { - let tcx = self.tcx(); - let mut seen_negative_bound = false; - let mut seen_positive_bound = false; - - // Try to find an unbound in bounds. - let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); - let mut search_bounds = |hir_bounds: &'a [hir::GenericBound<'tcx>]| { - for hir_bound in hir_bounds { - let hir::GenericBound::Trait(ptr) = hir_bound else { - continue; - }; - match ptr.modifiers.polarity { - hir::BoundPolarity::Maybe(_) => unbounds.push(ptr), - hir::BoundPolarity::Negative(_) => { - if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { - seen_negative_bound = true; - } - } - hir::BoundPolarity::Positive => { - if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { - seen_positive_bound = true; - } - } - } - } - }; - search_bounds(hir_bounds); - if let Some((self_ty, where_clause)) = self_ty_where_predicates { - for clause in where_clause { - if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind - && pred.is_param_bound(self_ty.to_def_id()) - { - search_bounds(pred.bounds); - } - } - } - - let mut unique_bounds = FxIndexSet::default(); - let mut seen_repeat = false; - for unbound in &unbounds { - if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res { - seen_repeat |= !unique_bounds.insert(unbound_def_id); - } - } - if unbounds.len() > 1 { - let err = errors::MultipleRelaxedDefaultBounds { - spans: unbounds.iter().map(|ptr| ptr.span).collect(), - }; - if seen_repeat { - self.dcx().emit_err(err); - } else if !tcx.features().more_maybe_bounds() { - self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit(); - }; - } - - let mut seen_unbound = false; - for unbound in unbounds { - let unbound_def_id = unbound.trait_ref.trait_def_id(); - if unbound_def_id == Some(trait_def_id) { - seen_unbound = true; - } - let emit_relax_err = || { - let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds { - true => "`?Sized` and `experimental_default_bounds`", - false => "`?Sized`", - }; - // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`. - self.dcx().span_err( - unbound.span, - format!( - "relaxing a default bound only does something for {}; \ - all other traits are not bound by default", - unbound_traits - ), - ); - }; - match unbound_def_id { - Some(def_id) if !tcx.is_default_trait(def_id) => emit_relax_err(), - None => emit_relax_err(), - _ => {} - } - } - - !(seen_unbound || seen_negative_bound || seen_positive_bound) + let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id); + !collected.any() } /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any. @@ -361,6 +461,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { 'tcx: 'hir, { for hir_bound in hir_bounds { + if self.should_skip_sizedness_bound(hir_bound) { + continue; + } + // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`, // we skip over any traits that don't define the given associated type. if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index c7cdf1d5bd2..05465b47a26 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -61,14 +61,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ast_bounds: Vec<_> = hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect(); - self.add_default_traits_with_filter( - &mut user_written_bounds, - dummy_self, - &ast_bounds, - None, - span, - |tr| tr != hir::LangItem::Sized, - ); + self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span); let (elaborated_trait_bounds, elaborated_projection_bounds) = traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied()); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 45fee0fa402..0e79a8918b0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -8,7 +8,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, HirId}; +use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -26,6 +26,7 @@ use rustc_trait_selection::traits::{ use smallvec::SmallVec; use tracing::debug; +use super::InherentAssocCandidate; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, @@ -34,6 +35,57 @@ use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits. + pub(crate) fn check_and_report_invalid_unbounds_on_param( + &self, + unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>, + ) { + let tcx = self.tcx(); + + let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP); + + let mut unique_bounds = FxIndexSet::default(); + let mut seen_repeat = false; + for unbound in &unbounds { + if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res { + seen_repeat |= !unique_bounds.insert(unbound_def_id); + } + } + + if unbounds.len() > 1 { + let err = errors::MultipleRelaxedDefaultBounds { + spans: unbounds.iter().map(|ptr| ptr.span).collect(), + }; + + if seen_repeat { + tcx.dcx().emit_err(err); + } else if !tcx.features().more_maybe_bounds() { + tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit(); + }; + } + + for unbound in unbounds { + if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res + && ((did == sized_did) || tcx.is_default_trait(did)) + { + continue; + } + + let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds { + true => "`?Sized` and `experimental_default_bounds`", + false => "`?Sized`", + }; + self.dcx().span_err( + unbound.span, + format!( + "relaxing a default bound only does something for {}; all other traits are \ + not bound by default", + unbound_traits + ), + ); + } + } + /// On missing type parameters, emit an E0393 error and provide a structured suggestion using /// the type parameter's name as a placeholder. pub(crate) fn report_missing_type_params( @@ -742,7 +794,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, name: Ident, self_ty: Ty<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, + candidates: Vec<InherentAssocCandidate>, fulfillment_errors: Vec<FulfillmentError<'tcx>>, span: Span, assoc_tag: ty::AssocTag, @@ -776,8 +828,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let type_candidates = candidates .iter() .take(limit) - .map(|&(impl_, _)| { - format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity()) + .map(|cand| { + format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity()) }) .collect::<Vec<_>>() .join("\n"); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 3a26b8331f8..8c7c3750865 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{ self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; -use rustc_span::{kw, sym}; +use rustc_span::kw; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -258,19 +258,6 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( GenericParamDefKind::Const { .. }, _, ) => { - if let GenericParamDefKind::Const { .. } = param.kind - && let GenericArg::Infer(inf) = arg - && !tcx.features().generic_arg_infer() - { - rustc_session::parse::feature_err( - tcx.sess, - sym::generic_arg_infer, - inf.span, - "const arguments cannot yet be inferred with `_`", - ) - .emit(); - } - // We lower to an infer even when the feature gate is not enabled // as it is useful for diagnostics to be able to see a `ConstKind::Infer` args.push(ctx.provided_kind(&args, param, arg)); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index bf407cbaccb..baf3b9b5bc9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -33,13 +33,14 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; +use rustc_infer::traits::DynCompatibilityViolation; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, + TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -47,10 +48,10 @@ use rustc_session::parse::feature_err; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{self, ObligationCtxt}; +use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; -use crate::check::check_abi_fn_ptr; +use crate::check::check_abi; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; @@ -99,6 +100,13 @@ pub enum RegionInferReason<'a> { OutlivesBound, } +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)] +pub struct InherentAssocCandidate { + pub impl_: DefId, + pub assoc_item: DefId, + pub scope: DefId, +} + /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// @@ -148,6 +156,13 @@ pub trait HirTyLowerer<'tcx> { assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; + fn select_inherent_assoc_candidates( + &self, + span: Span, + self_ty: Ty<'tcx>, + candidates: Vec<InherentAssocCandidate>, + ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>); + /// Lower a path to an associated item (of a trait) to a projection. /// /// This method has to be defined by the concrete lowering context because @@ -1449,48 +1464,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_map(|&impl_| { let (item, scope) = self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?; - Some((impl_, (item.def_id, scope))) + Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope }) }) .collect(); - if candidates.is_empty() { - return Ok(None); - } - - // - // Select applicable inherent associated type candidates modulo regions. - // - - // In contexts that have no inference context, just make a new one. - // We do need a local variable to store it, though. - let infcx = match self.infcx() { - Some(infcx) => infcx, - None => { - assert!(!self_ty.has_infer()); - &tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()) - } - }; + let (applicable_candidates, fulfillment_errors) = + self.select_inherent_assoc_candidates(span, self_ty, candidates.clone()); - // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors - // when inside of an ADT (#108491) or where clause. - let param_env = tcx.param_env(block.owner); + let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } = + match &applicable_candidates[..] { + &[] => Err(self.report_unresolved_inherent_assoc_item( + name, + self_ty, + candidates, + fulfillment_errors, + span, + assoc_tag, + )), - let mut universes = if self_ty.has_escaping_bound_vars() { - vec![None; self_ty.outer_exclusive_binder().as_usize()] - } else { - vec![] - }; + &[applicable_candidate] => Ok(applicable_candidate), - let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars( - infcx, - &mut universes, - self_ty, - |self_ty| { - self.select_inherent_assoc_candidates( - infcx, name, span, self_ty, param_env, candidates, assoc_tag, - ) - }, - )?; + &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( + name, + candidates.into_iter().map(|cand| cand.assoc_item).collect(), + span, + )), + }?; self.check_assoc_item(assoc_item, name, def_scope, block, span); @@ -1507,78 +1506,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(Some((assoc_item, args))) } - fn select_inherent_assoc_candidates( - &self, - infcx: &InferCtxt<'tcx>, - name: Ident, - span: Span, - self_ty: Ty<'tcx>, - param_env: ParamEnv<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, - assoc_tag: ty::AssocTag, - ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { - let tcx = self.tcx(); - let mut fulfillment_errors = Vec::new(); - - let applicable_candidates: Vec<_> = candidates - .iter() - .copied() - .filter(|&(impl_, _)| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_with_diagnostics(infcx); - let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); - - let impl_args = infcx.fresh_args_for_item(span, impl_); - let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); - let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty); - - // Check that the self types can be related. - if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() { - return false; - } - - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = - ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds); - let impl_obligations = traits::predicates_for_generics( - |_, _| ObligationCause::dummy(), - param_env, - impl_bounds, - ); - ocx.register_obligations(impl_obligations); - - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return false; - } - - true - }) - }) - .collect(); - - match &applicable_candidates[..] { - &[] => Err(self.report_unresolved_inherent_assoc_item( - name, - self_ty, - candidates, - fulfillment_errors, - span, - assoc_tag, - )), - - &[applicable_candidate] => Ok(applicable_candidate), - - &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( - name, - applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), - span, - )), - } - } - /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1]. /// /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. @@ -2733,7 +2660,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(bare_fn_ty), span, .. }) = tcx.hir_node(hir_id) { - check_abi_fn_ptr(tcx, hir_id, *span, bare_fn_ty.abi); + check_abi(tcx, hir_id, *span, bare_fn_ty.abi); } // reject function types that violate cmse ABI requirements diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 4633f3951a7..fef0dbf2ece 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -1,7 +1,8 @@ +use rustc_hir::def::DefKind; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{ObligationCause, WellFormedLoc}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions}; @@ -107,6 +108,17 @@ fn diagnostic_hir_wf_check<'tcx>( // over less-specific types (e.g. `Option<MyStruct<u8>>`) if self.depth >= self.cause_depth { self.cause = Some(error.obligation.cause); + if let hir::TyKind::TraitObject(..) = ty.kind { + if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn = + self.tcx.def_kind(self.def_id) + { + self.cause = Some(ObligationCause::new( + ty.span, + self.def_id, + ObligationCauseCode::DynCompatible(ty.span), + )); + } + } self.cause_depth = self.depth } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 7c8c9425a03..76ab2e57a1b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -62,8 +62,8 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(coroutines)] #![feature(debug_closure_helpers)] +#![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(iter_intersperse)] |
